JavaScript 面向?qū)ο缶幊?/h1>
上傳人:沈***
文檔編號(hào):161746874
上傳時(shí)間:2022-10-15
格式:DOC
頁數(shù):14
大小:66KB
《JavaScript 面向?qū)ο缶幊獭酚蓵?huì)員分享,可在線閱讀,更多相關(guān)《JavaScript 面向?qū)ο缶幊蹋?4頁珍藏版)》請?jiān)谘b配圖網(wǎng)上搜索。
1、JavaScript 面向?qū)ο缶幊? 第一部分: 繼承
作者:lzlhero
2、建立原型, 如何檢測一個(gè)對(duì)象是否是另外一個(gè)對(duì)象的原型, 及其 JavaScript 的模型與 Java 面向?qū)ο缶幊讨g的區(qū)別. 我們同樣會(huì)向你展示如何檢測對(duì)象所包含的各種屬性的方法. 在另外一篇文章里, 我還會(huì)詳細(xì)地講解有關(guān) "原型鏈 (prototype chain)" 的知識(shí). 本文大量地參考了 W 中 "Object-Oriented Programming with JavaScript, Part I: Inheritance" 的內(nèi)容, 許多內(nèi)容我進(jìn)行了詳細(xì)的測試和再探討, 以保證內(nèi)容不會(huì)有太大的失誤. 原文地址: 面向?qū)ο笳Z言的特點(diǎn) 面向?qū)ο笤O(shè)計(jì)是基于以下 3 個(gè)主要
3、原理的: 封裝, 繼承和多態(tài). 說某種程序語言是支持 OO (面向?qū)ο? 設(shè)計(jì)的, 只有在它的語法中支持以上 3 個(gè)概念才可以這么說. 這種語言應(yīng)該為你提供某些方法, 以使你能很輕松地定義和使用這些范例. 封裝涉及到了將某個(gè)對(duì)象變成一個(gè) "黑盒子"的概念. 當(dāng)你使用某個(gè)對(duì)象時(shí), 你不用知道它內(nèi)部是如何工作的, 你也不必理解對(duì)象是如何工作的. 這個(gè)對(duì)象只需將它絕對(duì)有用的信息以接口方式提供出來. 此對(duì)象應(yīng)該給你提供友好的接口, 來讓你可以使用其有限的屬性集和方法集. 封裝還有一層意思, 那就是說某個(gè)對(duì)象包含了它需要的每一樣?xùn)|西, 這包括數(shù)據(jù)和對(duì)于它的操作. 封裝的概念非常的強(qiáng)大, 因?yàn)樗试S將一個(gè)
4、大的軟件項(xiàng)目有效地分配給每個(gè)開發(fā)人員, 對(duì)于團(tuán)隊(duì)中的每個(gè)人, 他們只需要關(guān)注自己所實(shí)現(xiàn)的對(duì)象, 而不需要太多地關(guān)注于別人的實(shí)現(xiàn). 開發(fā)項(xiàng)目中的開銷使得開發(fā)團(tuán)隊(duì)中成員與接口的數(shù)量按指數(shù)級(jí)別增長. 封裝是自 "軟件危機(jī)" 以來最受歡迎的 OO 設(shè)計(jì)理念. 軟件的復(fù)用是 OO 設(shè)計(jì)思想中另外一個(gè)重要的特點(diǎn). 在軟件體系中實(shí)現(xiàn)此思想的主要方法就是繼承. 類就是定義對(duì)象的功能. 超類是某個(gè)新類, 或者說是子類被建立的來源類. 一個(gè)子類從它的超類中繼承了所的方法和屬性. 實(shí)際上, 所有的子類都是被自動(dòng)地生成的, 因此節(jié)省了大量的工作. 你不需要一個(gè)一個(gè)地定義這些子類. 當(dāng)然, 你可以重載那些繼承下來的方
5、法和屬性. 事實(shí)上, 誰也沒有指出哪個(gè)子類要建立得和其超類一模一樣, 除非你沒有重載任何的屬性和方法. 多態(tài)可能是這個(gè) 3 個(gè)概念中最復(fù)雜的一個(gè)了. 其本質(zhì)上是說, 每個(gè)對(duì)象都可以處理各種不同的數(shù)據(jù)類型. 你不必為處理不同的數(shù)據(jù)類型而建立不同的類. 其典型的例子就是畫圖的類, 你不必為實(shí)現(xiàn)畫圓, 畫矩形, 畫橢圓而編寫不同的類. 你可以建立一個(gè)足夠聰明的類來調(diào)用特定的方法來操作特定的形狀. 通過函數(shù)實(shí)現(xiàn)繼承 雖然 JavaScript 不支持顯示繼承操作符, 但你可以通過其實(shí)方式實(shí)現(xiàn)隱式繼承. 對(duì)于實(shí)現(xiàn)類的繼承, 有 2 種比較常用的方式. 第一種將某個(gè)類定義成子類的方法是, 通過在負(fù)責(zé)
6、定義子類函數(shù)的內(nèi)部調(diào)用超類的構(gòu)造函數(shù). 看下面的示例: // 超類構(gòu)造函數(shù) function superClass() { ? this.bye = superBye; ? this.hello = superHello; } // 子類構(gòu)造函數(shù) function subClass() { ? this.inheritFrom = superClass; ? this.inheritFrom(); ? this.bye = subBye; } function superHello() { ? return "Hello from superClass"; } ?
7、 function superBye() { ? return "Bye from superClass"; } function subBye() { ? return "Bye from subClass"; } // 測試構(gòu)造特性的函數(shù) function printSub() { ? var newClass = new subClass(); ? alert(newClass.bye()); ? alert(newClass.hello()); } 當(dāng)你運(yùn)行上面的 printSub 函數(shù)時(shí), 它會(huì)依次執(zhí)行 subBuy 和 superHello 函數(shù). 我們
8、可以看到, bye 和 hello 方法最先在 superClass 中被定義了. 然而, 在 subClass 中, bye 方法又被重載了, subClass 構(gòu)造函數(shù)頭兩行的功能只是做了一個(gè)簡單的原始的繼承操作, 但它是通過顯示執(zhí)行 inheritFrom 方法來完成的繼承操作. 繼承的過程先是將 superClass 的對(duì)象原型賦給 subClass 下的 inheritFrom 方法, 然后在執(zhí)行完 superClass 的構(gòu)造函數(shù)后, superClass 的屬性就被自動(dòng)地加到了 subClass 的屬性列表中.這主要是由于在 subClass 中通過 this 來調(diào)用的 inhe
9、ritFrom (也就是 superClass) 構(gòu)造函數(shù)造成的, 通過此種方式調(diào)用 superClass 構(gòu)造函數(shù)時(shí), JavaScript 解釋器會(huì)把 superClass 中的 this 與 subClass 中的 this 理解成位于同一個(gè)作用域下的 this 關(guān)鍵字, 所以就產(chǎn)生了繼承的效果. 另外, 需要說明的是, 對(duì)于任何一個(gè)實(shí)例化的對(duì)象, 你任意地為它添加屬性或方法, 如下所示: ? var newClass = new subClass(); ? newClass.addprop = "added property to instance object"; 很明顯,
10、通過此種方式添加的屬性和方法只對(duì)當(dāng)前實(shí)例化對(duì)象有效, 不會(huì)影響所有的同類型對(duì)象實(shí)例. 無疑, 它是你創(chuàng)造的一個(gè)獨(dú)一無二的對(duì)象實(shí)例. 通過原型實(shí)現(xiàn)繼承 第二種, 也是更強(qiáng)大的方法是通過建立一個(gè)超類對(duì)象, 然后將其賦值給子類對(duì)象的 prototype 屬性, 以此方式來建立子類的繼承. 假設(shè)我們的超類是 superClass, 子類是 subClass. 其 prototype 的賦值格式如下: subClass.prototype = new superClass; 對(duì)于原型繼承的實(shí)現(xiàn)方式, 讓我們剛前面的代碼改寫一下, 示例如下: // 超類構(gòu)造函數(shù) function superC
11、lass() { ? this.bye = superBye; ? this.hello = superHello; } // 子類構(gòu)造函數(shù) function subClass() { ? this.bye = subBye; } subClass.prototype = new superClass; function superHello() { ? return "Hello from superClass"; } ? function superBye() { ? return "Bye from superClass"; } function sub
12、Bye() { ? return "Bye from subClass"; } // 測試構(gòu)造特性的函數(shù) function printSub() { ? var newClass = new subClass(); ? alert(newClass.bye()); ? alert(newClass.hello()); } 我們可以看到, 除了將前面第一種繼承方式中 subClass 中的前 2 行內(nèi)容, 換成函數(shù)外的 prototype 賦值語句之外, 沒有其它任何的變化, 但代碼的執(zhí)行效果和前面是一樣的. 為已經(jīng)建立的對(duì)象添加屬性 通過原型實(shí)現(xiàn)的繼承比通過函數(shù)實(shí)現(xiàn)的繼承
13、更好, 因?yàn)樗С謩?dòng)態(tài)繼承. 你可以在構(gòu)造函數(shù)已經(jīng)完成之后, 再通過 prototype 屬性定義超類的其它方法和屬性, 并且其下的子類對(duì)象會(huì)自動(dòng)地獲得新的方法和屬性. 下面是示例, 你可以看到它的效果. function superClass() { ? this.bye = superBye; ? this.hello = superHello; } function subClass() { ? this.bye = subBye; } subClass.prototype = new superClass; function superHello() { ? ret
14、urn "Hello from superClass"; } ? function superBye() { ? return "Bye from superClass"; } function subBye() { ? return "Bye from subClass"; } var newClass = new subClass(); /*****************************/ // 動(dòng)態(tài)添加的 blessyou 屬性 superClass.prototype.blessyou = superBlessyou; function super
15、Blessyou() { ? return "Bless You from SuperClass"; } /*****************************/ function printSub() { ? alert(newClass.bye()); ? alert(newClass.hello()); ? alert(newClass.blessyou()); } 這就是我們經(jīng)??吹降臑閮?nèi)部對(duì)象, 如 String, Math 等再添加其它屬性和方法的技巧. 對(duì)于任何的內(nèi)部對(duì)象和自定義對(duì)象, 你都也可以通過 prototype 來重載其下的屬性和方法. 那么在調(diào)
16、用執(zhí)行時(shí), 它將調(diào)用你所定義的方法和屬性. 下面是示例: // 為內(nèi)部 String 對(duì)象添加方法 String.prototype.myMethod = function(){ ? return "my define method"; } // 為內(nèi)部 String 對(duì)象重載方法 String.prototype.toString = function(){ ? return "my define toString method"; } var myObj = new String("foo"); alert(myObj.myMethod()); alert(myObj
17、); alert("foo".toString()); 另外需要注意的是, 所有 JavaScript 內(nèi)部對(duì)的 prototype 屬性都是只讀的. 你可以像上面那樣為內(nèi)部對(duì)象的原型添加或重載屬性和方法,但不能更改該內(nèi)部對(duì)象的 prototype 原型. 然而, 自定義對(duì)象可以被賦給新的原型. 也就是說, 像下面這樣做是沒有意思的. function Employee() { ? this.dept = "HR"; ? this.manager = "John Johnson"; } String.prototype = new Employee; var myString
18、= new String("foo"); 上面的程序在運(yùn)行之后不會(huì)報(bào)錯(cuò), 但顯然, 如果你調(diào)用 myString.dept 將會(huì)得到一個(gè)非定義的值. 另外, 一個(gè)經(jīng)常使用的是 prototype 下的 isPrototypeOf() 方法, 它主要用來判斷指定對(duì)象是否存在于另一個(gè)對(duì)象的原型鏈中. 語法如下: object1.prototype.isPrototypeOf(0bject2); 上面的格式是用來判斷 Object2 是否出現(xiàn) Object1 的原型鏈中. 示例如下: function Person() { ? this.name = "Rob Roberson"; ?
19、 this.age = 31; } function Employee() { ? this.dept = "HR"; ? this.manager = "John Johnson"; } Employee.prototype = new Person(); var Ken = new Employee(); 當(dāng)執(zhí)行 Employee.prototype.isPrototypeOf(Ken), Person.prototype.isPrototypeOf(Ken) 和 Object.prototype.isPrototypeOf(Ken) 時(shí), 結(jié)果都會(huì)返回 true. 用于
20、 Netscape 下的特定繼承檢測 在 Netscape 瀏覽器 4.x 到 6, 及其 Mozilla 系列瀏覽中, JavaScript 將對(duì)象間的原型關(guān)系存儲(chǔ)在一個(gè)特殊的內(nèi)部屬性對(duì)象中, __proto__ (前后是 2 個(gè)下劃線). 下面是一個(gè)示例: function Shape() { ? this.borderWidth = 5; } function Square() { ? this.edge = 12; } Square.prototype = new Shape; myPicture = new Square; alert(myPicture.__pr
21、oto__); alert(myPicture.borderWidth); 由于腳本執(zhí)行過 Square.prototype = new Shape 語句, 所以 myPicture 具有了一個(gè)指向 Shape 對(duì)象的內(nèi)部屬性 __proto__. 在腳本的執(zhí)行過程中, 當(dāng)要獲取對(duì)象的某個(gè)屬性值, 并且此對(duì)象是通過原型賦值而建立的某個(gè)對(duì)象, 在自身并沒有對(duì)某個(gè)屬性進(jìn)行定義時(shí), JavaScript 解析器會(huì)查看它的 __proto__ 屬性對(duì)象, 也就它的原型對(duì)象, 然后枚舉其原型中的所有屬性, 而得出的結(jié)果要么是有這個(gè)屬性, 要么是沒有這個(gè)屬性. 如果沒有此屬性, 再枚舉原型對(duì)象下面的原
22、型對(duì)象, 直到此過程真正的結(jié)束. 而所有的這些 JavaScript 引擎內(nèi)部的操作, 我們是不會(huì)知道的, 下面的內(nèi)容就是對(duì)這個(gè)問題的解釋. 其實(shí), 對(duì)于所有的自定義對(duì)象, 無論它有沒有使用過 prototype 賦值操作, 它都具有一個(gè) __proto__ 內(nèi)部對(duì)象. 而如果某個(gè)對(duì)象是通過多層 prototype "繼承" 來的, 所有的 "繼承" 而來的屬性卻可以通過簡單的一層循環(huán)遍歷出來, 而不需要使用什么遞歸算法, 因?yàn)?JavaScript 引擎自動(dòng)給我們做了. 示例如下: function Shape() { ? this.borderWidth = 5; } funct
23、ion Square() { ? this.edge = 12; } function RoundSquare() { ? this.radio = 0.5; } Square.prototype = new Shape; RoundSquare.prototype = new Square; var myPicture = new RoundSquare; for (property in myPicture.__proto__) { alert(property); } 我們或者還可以通過更改后面的循環(huán), 來遍歷某個(gè)子類對(duì)象繼承來的所有屬性, 如下: for (
24、property in RoundSquare.prototype) { alert(property); } 如果你不怕麻煩, 我們甚至還可以通過級(jí)連的方式, 取出其構(gòu)造函數(shù)中定義的原始屬性值. alert(myPicture.__proto__.__proto__.borderWidth); 無論你是否修改過此屬性值, 通過上面語句所取出的屬性值都是原始定義值. 讓我們沿著這個(gè)思路再往下看, 下面的代碼涉及到另外一個(gè)問題, 這個(gè)問題和原型鏈 (prototype chain) 有關(guān). 代碼如下: function State() { } function City() {
25、 } City.prototype = new State; function Street() { } Street.prototype = new City; var UniversityAvenue = new Street(); function tryIt() { ? alert(UniversityAvenue.__proto__== Street.prototype); ? alert(UniversityAvenue.__proto__.__proto__== ?? City.prototype); ? alert(UniversityAvenue.__pr
26、oto__.__proto__.__proto__ ?? == State.prototype); ? alert(UniversityAvenue.__proto__.__proto__.__proto__. ?? __proto__== Object.prototype); ? alert(UniversityAvenue.__proto__.__proto__.__proto__. ?? __proto__.__proto__== null); } 當(dāng)執(zhí)行 tryIt 函數(shù)時(shí), 所有的顯示均為 true. 也就是說, 子類對(duì)象的 prototype.__proto__ 總是
27、等于超類對(duì)象的 prototype 屬性; 超類對(duì)象的 prototype.__proto__ 總是等于 Object.prototype; Object.prototype.__proto__ 總是為 null; 而實(shí)例對(duì)象的 __proto__ 總是等于其類對(duì)象的 prototype, 這就是為什么任何自定義對(duì)象都具有 __proto__ 屬性的原因. 對(duì)于上面的敘述, 其對(duì)應(yīng)的代碼如下: Street.prototype.__proto__ == City.prototype???? // true State.prototype.__proto__ == Object.protot
28、ype??? // true Object.prototype.__proto__ == null?????????????? // true UniversityAvenue.__proto__ == Street.prototype??? // true 模擬實(shí)現(xiàn) instanceOf 函數(shù) 根據(jù)上一節(jié)的內(nèi)容, 我們了解了有關(guān) Netscape 所支持的 __proto__ 特性的內(nèi)容. 這一節(jié), 我們將利用此特性來創(chuàng)建自己的實(shí)例對(duì)象檢測函數(shù). 許多時(shí)候, 我們都需要判斷某個(gè)對(duì)象是否是由某個(gè)類來定義的, 在其它的語言里, 你可以通過 instanceOf 函數(shù)來實(shí)現(xiàn)此判斷. 在
29、JavaScript 中同樣提供了一個(gè) instanceof 運(yùn)行符, 而在 __proto__ 的基礎(chǔ)上, 我們完全可以自己定義一個(gè)同樣的函數(shù), 雖然這看上去是在重復(fù)勞動(dòng), 但有助于我們更深刻地了解有關(guān) __proto__ 的知識(shí). 下面的代碼只是用來說明功能, 在實(shí)際的應(yīng)用中, 你不需要重復(fù)定義 instanceOf 函數(shù), 使用 instanceof 運(yùn)算符即可. function instanceOf(object, constructorFunction) { ? while (object != null) { ??? if (object == constructorFun
30、ction.prototype) ???? {return true} ??? object = object.__proto__; ? } ? return false; } function State() { } function City() { } City.prototype = new State; function Street() { } Street.prototype = new City; var UniversityAvenue = new Street(); function demo() { ? alert("instanceOf(
31、UniversityAvenue, Street) is " + ?? instanceOf(UniversityAvenue, Street)); ? alert("instanceOf(UniversityAvenue, City) is " + ?? instanceOf(UniversityAvenue, City)); ? alert("instanceOf(UniversityAvenue, State) is " + ?? instanceOf(UniversityAvenue, State)); } 你會(huì)看到所有的運(yùn)行結(jié)果全部為 true, 其原理和上一節(jié)的級(jí)連判
32、斷相等如出一轍. 實(shí)際證明, 它的運(yùn)行結(jié)果和 instanceof 運(yùn)行符的運(yùn)行結(jié)果是一致的. 你可以通過 constructor 屬性來檢測任意對(duì)象的超類, 此屬性返回通過 new 運(yùn)算符創(chuàng)建新對(duì)象時(shí)所調(diào)用的構(gòu)造函數(shù), 返回值是 Function 對(duì)象類型. 因?yàn)?Object 內(nèi)部對(duì)象是支持 constructor 屬性的, 并且有的對(duì)象 (包括內(nèi)部對(duì)象和自定義對(duì)象) 都是由 Object 繼承而來的, 所以所有的對(duì)象都支持此屬性. 讓我們再看一下下面的例子: function Employee() { ? this.dept = "HR"; ? this.manager = "J
33、ohn Johnson"; } function printProp() { ? var Ken = new Employee(); ? alert(Ken.constructor); } 調(diào)用完 printProp 函數(shù)之后, 你會(huì)看到彈出框中顯示的是 Employee 函數(shù)的定義文本, 其實(shí) Ken.constructor 的返回值本身是 Function 對(duì)象類型, 而在 alert 時(shí)被隱含地調(diào)用了 toString 方法. 對(duì)于類對(duì)象本身, 你同樣可以調(diào)用 prototype.constructor 來取出其構(gòu)造函數(shù). 對(duì)象的分類和打印 JavaScript 支持 3
34、 種主要類型的對(duì)象: 內(nèi)部對(duì)象, 宿主對(duì)象, 自定義對(duì)象, 可能還有特殊的外部對(duì)象, 如: ActiveX 對(duì)象或 XPCOM 對(duì)象. 內(nèi)部對(duì)象被 JavaScript 語言本身所支持, 如: Object, Math, Number 對(duì)象等. 所有的內(nèi)部對(duì)象的共同特點(diǎn)是以大寫字母開頭, 并且它們是大小寫敏感的. 如果你想使用數(shù)學(xué)常量 PI, 必須寫成 Math.PI, 你如果寫成 math.PI, JavaScript 會(huì)顯示錯(cuò)誤. 宿主對(duì)象是被瀏覽器支持的, 目的是為了能和被瀏覽的文檔可以交互, 如: document, window 和 frames. 宿主對(duì)象的特點(diǎn)是所有對(duì)象全部以小寫
35、字母開頭. 因?yàn)?JavaScript 本身就是大小寫敏感的, 所以你同樣不能將大小寫搞混. 剩下要說的就只是自定義對(duì)象了, 你可以隨便將你的對(duì)象定義成小寫或大小寫, 但是一定要符合基本的命名規(guī)范. 如下所示, 這就是一個(gè)自定義對(duì)象: function employee() { ? this.dept = "HR"; ? this.manager = "John Johnson"; } function printProp() { ? var ken = new Employee(); ? for (property in ken) { ??? alert(property);
36、 ? } } 前面我們已經(jīng)提到過, 所有的內(nèi)部對(duì)象和自定義對(duì)象都是從 Object 對(duì)象繼承而來的, 它是所有對(duì)象的超類對(duì)象. 你可建立一個(gè) Object 對(duì)象的實(shí)例. 如下: var myObject = new Object(); Object 類型的對(duì)象有許多的屬性和方法, 你可以查看相關(guān)的手冊. 上面只是定義了一個(gè)最簡單的空對(duì)象, 你還可以為 Object 構(gòu)造函數(shù)傳入?yún)?shù), 它會(huì)返回相應(yīng)類型值的實(shí)例化對(duì)象. 記住, 返回值的類型是某種對(duì)象類型的 (如: String, Number 或 Object). 這種方式和直接通過賦值字符串或數(shù)值常量不同, 主要表示在類型方面. 如
37、下所示: var myObject = new Object("foo"); // 返回值類型為 object var myObject = new String("foo"); // 返回值類型為 object, 效果同上 與 var myObject = "foo";???????????? // 返回值類型為 string 你可以從調(diào)試器的 type 列中看出這個(gè)細(xì)微的差別, 它是簡單類型與對(duì)象類型之間的區(qū)別. 但是, 你通過 alert 調(diào)用是看出不這些內(nèi)部差別的, 因?yàn)樵谡{(diào)用 alert 的過程中, 所有的對(duì)象類型值都會(huì)被自動(dòng)調(diào)用 toString 方法進(jìn)行字符串類型轉(zhuǎn)換,
38、 轉(zhuǎn)換規(guī)則在 JavaScript 手冊中有說明. 如果你 alert 的是某個(gè)自定義對(duì)象, 并且它沒有定義 toString 方法, 那么它的返回值將為 "[object Object]". 對(duì)于 Math 對(duì)象, 當(dāng)你查看其 Math.constructor 屬性時(shí), 你會(huì)得到一個(gè)不同于其它內(nèi)部對(duì)象的內(nèi)容為 "function Object()..." 的對(duì)象構(gòu)造函數(shù), 這與其它對(duì)象返回 "function Function()..." 的構(gòu)造函數(shù)很不相同. 原因很簡單, 因?yàn)?Math 對(duì)象是不能通過 new 運(yùn)算符進(jìn)行創(chuàng)建的. 另外, 如果傳入 Object 構(gòu)造函數(shù)中的值是一個(gè)對(duì)象
39、, 它將原封不動(dòng)地將該對(duì)象返回. 記住, 此操作只是一個(gè)引用, 而不是復(fù)制. 請求對(duì)象的屬性 在前面的示例代碼中, 已經(jīng)出現(xiàn)過以循環(huán)方式枚舉對(duì)象屬性的示例. 其實(shí), 通過 for...in 語句, 無論是任何對(duì)象和數(shù)組, 其下的元素, 屬性和方法都可以遍歷出來. 示例如下: function employee() { ? this.dept = "HR"; ? this.manager = "John Johnson"; } function printProp() { ? var ken = new employee(); ? for (property in ken) {
40、 ??? alert(property + " : " + ken[property]); ? } } 在遍歷測試過程中, 你會(huì)發(fā)現(xiàn), 對(duì)于自定義對(duì)象和宿主對(duì)象一般都可以枚舉出其下的屬性, 而對(duì)于內(nèi)部對(duì)象, 幾乎沒有什么屬性可以遍歷出來, 為什么要說幾乎呢? 因?yàn)閷?duì)于 Mozilla 內(nèi)核的瀏覽和 IE 內(nèi)核的瀏覽器, 其 JavaScript 引擎有不同, Mozilla 下可以枚舉出部分內(nèi)容, 而枚舉的原則不得而知. 對(duì)于每一個(gè)對(duì)象, 你還可以使用 hasOwnProperty 方法來檢測其是否具有某個(gè)屬性或方法. 由于 hasOwnProperty 是 Object 對(duì)象下的方
41、法, 因此所有的對(duì)象都具有此方法. 但是, 需要注意的是, 此方法只能檢測通過 this 關(guān)鍵字定義的成員, 如果某個(gè)成員是通過原型鏈定義的, 那么此方法將返回 false. 也就是說, 通過 prototype 繼承來的屬性和方法, 及其通過 prototype 定義的屬性和方法, 都是不能通過 hasOwnProperty 來進(jìn)行檢測的. 由此, 我們可以看出, 通過 this關(guān)鍵字定義的屬性和方法是同對(duì)象本身處于同一個(gè)地址空間內(nèi)的; 而通過 prototype 定義的屬性和方法, 是通過所謂的 "原型鏈" 進(jìn)行管理的, 其下的的屬性和方法不位于同一個(gè)地址空間之間, 當(dāng)其調(diào)用這種屬性或方法
42、時(shí), 必須通過 "鏈表" 才能索引到其下的某個(gè)屬性或方法. 也就說, 調(diào)用以原型方式定義的屬性和方法會(huì)有一個(gè)類似于鏈表的 "回溯" 操作. 和 hasOwnProperty 差不多, 對(duì)于對(duì)象中的每個(gè)屬性, 我們還可以通過 propertyIsEnumerable 來測試它是否可以被枚舉出來. 如下所示: function Employee1() { ? this.dept = "HR"; ? this.manager = "John Johnson"; ? this.month = new Array("jan", "feb", "mar"); } var Ken = new
43、Employee1(); Ken.month.propertyIsEnumerable(0); 我們可以看到, 其語法是 propertyIsEnumerable 后跟數(shù)組的元素索引或?qū)ο笾械膶傩悦Q. 同樣, 對(duì)于原型鏈中的屬性或方法它是不予考慮的, 結(jié)果當(dāng)然是返回 false. 對(duì)于 JavaScript 和 Java 的比較 與 Java 這種基于類的語言不同, JavaScript 是一種基于原型的語言. 這種特點(diǎn)影響著每一個(gè)方面. 如術(shù)語 instance 在基于類的語言中有著特殊的意義, 它表示某個(gè)實(shí)例是隸屬于某個(gè)特殊類的獨(dú)立個(gè)體, 是對(duì)類定義的真實(shí)實(shí)現(xiàn); 而在 JavaS
44、cript 中, 術(shù)語 instance 沒有這個(gè)意思, 因?yàn)樵谒恼Z法里面, 類和實(shí)例是沒有區(qū)別的. 雖然, 實(shí)例可以用來說明某個(gè)對(duì)象是使用某個(gè)特殊的構(gòu)造函數(shù)生成的. 如下所示: function superClass() { ? this.bye = superBye; ? this.hello = superHello; } function subClass() { ? this.bye = subBye; } subClass.prototype = new superClass; function superHello() { ? return "Hello f
45、rom superClass"; } ? function superBye() { ? return "Bye from superClass"; } function subBye() { ? return "Bye from subClass"; } var newClass = new subClass(); newClass 是 subClass 的實(shí)例, 它是通過 subClass 的構(gòu)造函數(shù)生成的. 而如果使用基于類的語言呢, 如下所示是 Java 的等價(jià)實(shí)現(xiàn). public class superClass { ? public superClass
46、() { ??? this.bye = superBye; ??? this.hello = superHello; ? } } public class subClass extends superClass { ? public subClass () { ??? this.bye = subBye; ? } } 結(jié)束語 我們在上面的幾節(jié)中, 詳細(xì)地說明了有關(guān) JavaScipt 中的面向?qū)ο髮?shí)現(xiàn), 或者只能說是模擬實(shí)現(xiàn). 在此期間向你展示了實(shí)現(xiàn)方法. 并且闡述了有關(guān)如何檢測對(duì)象之間關(guān)系的方法, 如何打印屬性和測試某個(gè)特定的屬性, 還做了一個(gè) JavaScript 和 Java 的簡單比較. 但這顯然是不夠的, 因而, JavaScript 的面向?qū)ο缶幊淌欠浅6鄻踊? 格式也非常繁雜. 我打算在后面的內(nèi)容里, 再總結(jié)一下有問封裝的格式問題, 著重說明與對(duì)象方法有關(guān)的內(nèi)容和實(shí)現(xiàn), 同時(shí)還有上面提到的原型鏈 (prototype chain) 問題.
- 溫馨提示:
1: 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
2: 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
3.本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
5. 裝配圖網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 人教部編版教材三年級(jí)上冊道德與法治第四單元家是最溫暖的地方教學(xué)ppt課件 (全套)
- 蘇教版小學(xué)科學(xué)三年級(jí)下冊《雨下得有多大》課件1
- 花的形態(tài)與結(jié)構(gòu)課件匯總
- 一年級(jí)-數(shù)學(xué)下冊十幾減九人教版課件
- 電影膠片動(dòng)態(tài)課件
- 高電壓技術(shù)課件第六章
- 項(xiàng)目采購管理(6)
- 四川省攀枝花市XX小學(xué)一年級(jí)數(shù)學(xué)下冊六100以內(nèi)的加法和減法二練習(xí)十三2課件蘇教版
- 山東省青島市黃島區(qū)海青鎮(zhèn)中心中學(xué)七年級(jí)歷史下冊 15 明朝君權(quán)的加強(qiáng)課件 新人教版
- 把握人物的性格特征
- 剪小紙人PPT課件
- 八年級(jí)物理探究凸透鏡成像規(guī)律8
- 1[1]22配方法2
- 近代機(jī)械行業(yè)唯物主義管理分析自然觀
- 全國科技創(chuàng)新大賽“科學(xué)幻想畫”獲獎(jiǎng)作品ppt課件