JavaScript面向?qū)ο笾甈rototypes和繼承
更新時(shí)間:2012年07月12日 17:04:47 作者:
本文翻譯自微軟的牛人Scott Allen Prototypes and Inheritance in JavaScript ,本文對(duì)到底什么是Prototype和為什么通過(guò)Prototype能實(shí)現(xiàn)繼承做了詳細(xì)的分析和闡述,是理解JS OO 的佳作之一
一、前言
本文翻譯自微軟的牛人Scott Allen Prototypes and Inheritance in JavaScript ,本文對(duì)到底什么是Prototype和為什么通過(guò)Prototype能實(shí)現(xiàn)繼承做了詳細(xì)的分析和闡述,是理解JS OO 的佳作之一。翻譯不好的地方望大家修改補(bǔ)充。
二、正文
JavaScript中的面向?qū)ο蟛煌谄渌Z(yǔ)言,在學(xué)習(xí)前最好忘掉你所熟知的面向?qū)ο蟮母拍?。JS中的OO更強(qiáng)大、更值得討論(arguably)、更靈活。
1.類(lèi)和對(duì)象
JS從傳統(tǒng)觀點(diǎn)來(lái)說(shuō)是面向?qū)ο蟮恼Z(yǔ)言。屬性、行為組合成一個(gè)對(duì)象。比如說(shuō),JS中的array就是由屬性和方法(如push、reverse、pop 等)組合成的對(duì)象。
var myArray = [1, 2];
myArray.push(3);
myArray.reverse();
myArray.pop();
var length = myArray.length;
問(wèn)題是:這些方法(如push)從哪里來(lái)的?一些靜態(tài)語(yǔ)言(比如JAVA)用class來(lái)定義一個(gè)對(duì)象的結(jié)構(gòu)。但是JS是沒(méi)有”class"(classless)的語(yǔ)言,沒(méi)有一個(gè)叫做“Array"的類(lèi)定義了這些方法給每個(gè)array去繼承。因?yàn)镴S是動(dòng)態(tài)的,我們可以在需要的時(shí)候隨意的往對(duì)象中添加方法。例如,下面的代碼定義了一個(gè)對(duì)象,該對(duì)象表示二維空間中的坐標(biāo),里面有一個(gè)add方法。
var point = {
x : 10,
y : 5,
add: function(otherPoint)
{
this.x = otherPoint.x;
this.y = otherPoint.y;
}
};
我們想讓每一個(gè)point對(duì)象都有一個(gè)add方法。我們也希望所有的poin對(duì)象共享一個(gè)add方法,而不必把a(bǔ)dd方法加到所有的point對(duì)象當(dāng)中。這就需要讓prototype登場(chǎng)了。
2.關(guān)于Prototypes
JS中每一個(gè)對(duì)象都有一個(gè)隱含的屬性(state)——對(duì)另一個(gè)對(duì)象的引用,稱(chēng)為對(duì)象的prototype.我們上面創(chuàng)建的array和point當(dāng)然也都含有各自prototype的引用。prototype引用是隱含的,但是它是ECMAScript已實(shí)現(xiàn)的,允許我們使用對(duì)象的_proto_(在Chrome中)屬性來(lái)獲取它。從概念上理解我們可以認(rèn)為對(duì)象和prototype的關(guān)系就像下圖所表示的:
作為開(kāi)發(fā)者,我們將用Object.getPrototypeOf 函數(shù)來(lái)替代_proto_屬性來(lái)查看對(duì)象的prototype引用。在寫(xiě)這篇文章的時(shí)候,Object.getPrototypeOf這個(gè)函數(shù)已經(jīng)在Chrome,firefox,還有IE9中提供了支持。在未來(lái)還會(huì)有更多的瀏覽器來(lái)支持這一特性,這已經(jīng)是ECMAScript的標(biāo)準(zhǔn)之一。我們可以用以下代碼來(lái)證明myArray和我們之前創(chuàng)建的point對(duì)象確實(shí)引用了兩個(gè)不同的prototype對(duì)象。
Object.getPrototypeOf(point) != Object.getPrototypeOf(myArray);
在文章接下來(lái)的部分,我還將使用到_proto_,主要是因?yàn)開(kāi)proto_在圖示和句子里里比較直觀。但要記住這不是規(guī)范的,Object.getPrototypeOf才是用來(lái)獲取對(duì)象prototype的推薦方法。
2.1是什么使Prototypes如此特別?
我們已經(jīng)知道了array的push方法來(lái)自myArray的prototype對(duì)象。圖2是Chrome中的一個(gè)截圖,我們調(diào)用Object.getPrototypeOf方法來(lái)取得myArray的prototype對(duì)象。
圖 2
注意到myArray的prototype對(duì)象里包含了很多方法,比如push、pop還有reverse這些我們?cè)陂_(kāi)頭代碼里使用過(guò)的。prototype對(duì)象才是push方法的唯一擁有者,但這個(gè)方法是如何通過(guò)myArray調(diào)用到的呢?
myArray.push(3);
要想明白它是怎樣實(shí)現(xiàn)的,第一步是認(rèn)清Protytype一點(diǎn)兒不特殊。Prototype就是一些對(duì)象。我們可以給這些對(duì)象添加方法、屬性,像其他任何的JS對(duì)象一樣。但同時(shí)Prototype也是一個(gè)特殊的對(duì)象。
Prototype的特殊是因?yàn)橄铝幸?guī)則:當(dāng)我們通知JS我們想要在一個(gè)對(duì)象上調(diào)用push方法或是讀取某個(gè)屬性的時(shí)候,解釋器(runtime)首先去尋找這個(gè)對(duì)象本身的方法或?qū)傩?。如果解釋器沒(méi)有找到該方法(或?qū)傩裕┚蜁?huì)沿著_proto_引用去尋找對(duì)象的prototype中的各個(gè)成員。當(dāng)我們?cè)趍yArray中調(diào)用push方法,JS沒(méi)有在myArray對(duì)象中找到push,但是在myArray的prototype對(duì)象中找到了push,即調(diào)用了該push方法(圖3)。
圖 3
我所描述的這種行為本質(zhì)上就是對(duì)象本身繼承了 它的prototype中的所有方法和屬性。我們?cè)贘S中不需要用class來(lái)實(shí)現(xiàn)這種繼承關(guān)系。即,一個(gè)JS對(duì)象從它的prototype中繼承特性。
圖3還告訴我們每個(gè)array對(duì)象都能維護(hù)自己的狀態(tài)(state)和成員。如果我們需要myArray的length屬性,JS將從myArray中找到length的值而不會(huì)去prototype中去尋找。我們能運(yùn)用這個(gè)特性來(lái)“override"一個(gè)方法,即,將需覆蓋的方法(像push)放到myArray自己的對(duì)象中。這樣做就可以有效的將prototype中的push方法隱藏掉。
3.共享Prototype
Prototype在JS中真正神奇的地方是多個(gè)對(duì)象能引用同一個(gè)prototype對(duì)象。比如,我們創(chuàng)建兩個(gè)數(shù)組:
var myArray = [1, 2];var yourArray = [4, 5, 6];
這兩個(gè)數(shù)組將共享一個(gè)相同的prototype對(duì)象,下面的代碼將返回true
Object.getPrototypeOf(myArray) === Object.getPrototypeOf(yourArray);
如果我們?cè)趦蓚€(gè)數(shù)組中調(diào)用push方法,JS將調(diào)用他們共同的prototype中的push。
Prototype對(duì)象在JS中給我們這種繼承的特性,它們也允許我們共享方法的實(shí)現(xiàn)。Prototype也是鏈?zhǔn)降?。換句話(huà)說(shuō),prototype是一個(gè)對(duì)象,那么prototype對(duì)象也可以擁有一個(gè)指向別的prototype對(duì)象的引用。從圖2中可以看到prototype的_proto_屬性是一個(gè)不為null的值也指向另外一個(gè)prototype.當(dāng)JS開(kāi)始尋找成員變量的時(shí)候,比如push方法,它將沿著這些prototype的引用檢查每一個(gè)對(duì)象直到找到這個(gè)對(duì)象或達(dá)到鏈的尾部為止。這種鏈的方式更增加了JS中繼承和共享的靈活性。
接下來(lái)你也許會(huì)問(wèn):我怎樣設(shè)置自定義對(duì)象的prototype引用?比如,我們之前創(chuàng)建過(guò)的對(duì)象point,我們?cè)鯓蛹尤胍粋€(gè)add方法到prototype對(duì)象中,讓所有的point對(duì)象都能繼承它?在我們回答這個(gè)問(wèn)題之前,我們先了解一下JS中的函數(shù).
4.關(guān)于Funciton
函數(shù)在JS中同樣也是對(duì)象。函數(shù)在JS中有很多重要的特性,在此文章中我們不能一一列舉。但像把一個(gè)函數(shù)賦值給一個(gè)變量或是將一個(gè)函數(shù)當(dāng)做另外一個(gè)函數(shù)的參數(shù)在當(dāng)今的JS編程中是很基礎(chǔ)的方式。
我們需要關(guān)注的是:因?yàn)楹瘮?shù)是對(duì)象,所以它擁有方法、屬性和一個(gè)prototype對(duì)象的引用。我們一起討論一下下面代碼的含義:
// this will return true:
typeof (Array) === "function"
// and so will this:
Object.getPrototypeOf(Array) === Object.getPrototypeOf(function () { })
// and this, too:
Array.prototype != null
第一行代碼證明Array在JS中是一個(gè)函數(shù)。待會(huì)兒我們將看到怎樣調(diào)用Array函數(shù)來(lái)創(chuàng)建一個(gè)新的array對(duì)象。
第二行代碼證明Array對(duì)象和function對(duì)象引用相同的prototype,就像我們之前看到的所有的array對(duì)象共享一個(gè)prototype。
最后一行證明Array函數(shù)有一個(gè)prototype屬性。千萬(wàn)不要將這個(gè)prototype屬性和_proto_屬性混淆了。它們的使用目的和指向的對(duì)象都不相同。
// true
Array.prototype == Object.getPrototypeOf(myArray)
// also true
Array.prototype == Object.getPrototypeOf(yourArray);
我們用新學(xué)的知識(shí)重畫(huà)之前的圖片:
// create a new, empty object
var o = {};
// inherit from the same prototype as an array object
o.__proto__ = Array.prototype;
// now we can invoke any of the array methods ...
o.push(3);
盡管上面的代碼看起來(lái)不錯(cuò),但問(wèn)題是不是每一個(gè)JS的環(huán)境都支持對(duì)象的_proto_屬性。幸運(yùn)的是,JS內(nèi)置一個(gè)標(biāo)準(zhǔn)的機(jī)制用來(lái)創(chuàng)建新對(duì)象同時(shí)設(shè)置對(duì)象的_proto_屬性,這就是“new”操作符。
var o = new Array();
o.push(3);
“new”操作符在JS中有三個(gè)重要的任務(wù):首先,它創(chuàng)建一個(gè)新的空對(duì)象。接著,它設(shè)置這個(gè)新對(duì)象的_proto_屬性指向調(diào)用函數(shù)的prototype屬性。最后,執(zhí)行調(diào)用函數(shù)同時(shí)把“this”指針指向新的對(duì)象。如果我們把上面的兩行代碼展開(kāi),將得到以下的代碼:
var o = {};
o.__proto__ = Array.prototype;
Array.call(o);
o.push(3);
函數(shù)的“call”方法允許你調(diào)用一個(gè)函數(shù)同時(shí)指定這個(gè)函數(shù)里面的"this"指向傳入的新對(duì)象。當(dāng)然,我們也想通過(guò)上面的方法來(lái)創(chuàng)建我們自己的對(duì)象來(lái)實(shí)現(xiàn)對(duì)象的繼承,這種函數(shù)就是我們所熟知的——構(gòu)造函數(shù)。
5.構(gòu)造函數(shù)
構(gòu)造函數(shù)是一個(gè)有兩個(gè)獨(dú)特標(biāo)識(shí)的普通JS函數(shù)對(duì)象:
1.首字母大寫(xiě)(容易識(shí)別)。
2.用new操作符連接來(lái)構(gòu)造新對(duì)象。
Array就是一個(gè)構(gòu)造函數(shù)——Array函數(shù)用new連接、首字母大寫(xiě)。JS中的Array函數(shù)是內(nèi)置的,但任何人都可以創(chuàng)建自己的構(gòu)造函數(shù)。事實(shí)上,我們終于到了該為point對(duì)象來(lái)創(chuàng)建一個(gè)構(gòu)造函數(shù)的時(shí)候了。
var Point = function (x, y) {
this.x = x;
this.y = y;
this.add = function (otherPoint) {
this.x = otherPoint.x;
this.y = otherPoint.y;
}
}
var p1 = new Point(3, 4);
var p2 = new Point(8, 6);
p1.add(p2);
上面的代碼中我們使用new操作符和Point函數(shù)來(lái)來(lái)構(gòu)造一個(gè)point對(duì)象。在內(nèi)存中你可以把最終的結(jié)果想成圖6所表示的樣子。
圖 6
現(xiàn)在的問(wèn)題是,add方法存在于每一個(gè)point對(duì)象中。鑒于我們對(duì)prototype的了解,把a(bǔ)dd方法加到Point.prototype中是一個(gè)更好的選擇(不必把a(bǔ)dd方法的代碼拷貝到每個(gè)對(duì)象中)。為了實(shí)現(xiàn)這個(gè)目的,我們需要在Point.prototype對(duì)象上做些修改。
var Point = function (x, y) {
this.x = x;
this.y = y;
}
Point.prototype.add = function (otherPoint) {
this.x = otherPoint.x;
this.y = otherPoint.y;
}
var p1 = new Point(3, 4);
var p2 = new Point(8, 6);
p1.add(p2);
好了!我們已經(jīng)用prototype實(shí)現(xiàn)了JS中的繼承!
6.總結(jié)
希望能通過(guò)這篇文章讓你能撥開(kāi)prototype的迷霧。當(dāng)然這只是功能強(qiáng)大又靈活的prototype的入門(mén)。更多的關(guān)于prototype的知識(shí)還是希望讀者能夠自己去探索和發(fā)現(xiàn)。
本文翻譯自微軟的牛人Scott Allen Prototypes and Inheritance in JavaScript ,本文對(duì)到底什么是Prototype和為什么通過(guò)Prototype能實(shí)現(xiàn)繼承做了詳細(xì)的分析和闡述,是理解JS OO 的佳作之一。翻譯不好的地方望大家修改補(bǔ)充。
二、正文
JavaScript中的面向?qū)ο蟛煌谄渌Z(yǔ)言,在學(xué)習(xí)前最好忘掉你所熟知的面向?qū)ο蟮母拍?。JS中的OO更強(qiáng)大、更值得討論(arguably)、更靈活。
1.類(lèi)和對(duì)象
JS從傳統(tǒng)觀點(diǎn)來(lái)說(shuō)是面向?qū)ο蟮恼Z(yǔ)言。屬性、行為組合成一個(gè)對(duì)象。比如說(shuō),JS中的array就是由屬性和方法(如push、reverse、pop 等)組合成的對(duì)象。
復(fù)制代碼 代碼如下:
var myArray = [1, 2];
myArray.push(3);
myArray.reverse();
myArray.pop();
var length = myArray.length;
問(wèn)題是:這些方法(如push)從哪里來(lái)的?一些靜態(tài)語(yǔ)言(比如JAVA)用class來(lái)定義一個(gè)對(duì)象的結(jié)構(gòu)。但是JS是沒(méi)有”class"(classless)的語(yǔ)言,沒(méi)有一個(gè)叫做“Array"的類(lèi)定義了這些方法給每個(gè)array去繼承。因?yàn)镴S是動(dòng)態(tài)的,我們可以在需要的時(shí)候隨意的往對(duì)象中添加方法。例如,下面的代碼定義了一個(gè)對(duì)象,該對(duì)象表示二維空間中的坐標(biāo),里面有一個(gè)add方法。
復(fù)制代碼 代碼如下:
var point = {
x : 10,
y : 5,
add: function(otherPoint)
{
this.x = otherPoint.x;
this.y = otherPoint.y;
}
};
我們想讓每一個(gè)point對(duì)象都有一個(gè)add方法。我們也希望所有的poin對(duì)象共享一個(gè)add方法,而不必把a(bǔ)dd方法加到所有的point對(duì)象當(dāng)中。這就需要讓prototype登場(chǎng)了。
2.關(guān)于Prototypes
JS中每一個(gè)對(duì)象都有一個(gè)隱含的屬性(state)——對(duì)另一個(gè)對(duì)象的引用,稱(chēng)為對(duì)象的prototype.我們上面創(chuàng)建的array和point當(dāng)然也都含有各自prototype的引用。prototype引用是隱含的,但是它是ECMAScript已實(shí)現(xiàn)的,允許我們使用對(duì)象的_proto_(在Chrome中)屬性來(lái)獲取它。從概念上理解我們可以認(rèn)為對(duì)象和prototype的關(guān)系就像下圖所表示的:
作為開(kāi)發(fā)者,我們將用Object.getPrototypeOf 函數(shù)來(lái)替代_proto_屬性來(lái)查看對(duì)象的prototype引用。在寫(xiě)這篇文章的時(shí)候,Object.getPrototypeOf這個(gè)函數(shù)已經(jīng)在Chrome,firefox,還有IE9中提供了支持。在未來(lái)還會(huì)有更多的瀏覽器來(lái)支持這一特性,這已經(jīng)是ECMAScript的標(biāo)準(zhǔn)之一。我們可以用以下代碼來(lái)證明myArray和我們之前創(chuàng)建的point對(duì)象確實(shí)引用了兩個(gè)不同的prototype對(duì)象。
復(fù)制代碼 代碼如下:
Object.getPrototypeOf(point) != Object.getPrototypeOf(myArray);
在文章接下來(lái)的部分,我還將使用到_proto_,主要是因?yàn)開(kāi)proto_在圖示和句子里里比較直觀。但要記住這不是規(guī)范的,Object.getPrototypeOf才是用來(lái)獲取對(duì)象prototype的推薦方法。
2.1是什么使Prototypes如此特別?
我們已經(jīng)知道了array的push方法來(lái)自myArray的prototype對(duì)象。圖2是Chrome中的一個(gè)截圖,我們調(diào)用Object.getPrototypeOf方法來(lái)取得myArray的prototype對(duì)象。
圖 2
注意到myArray的prototype對(duì)象里包含了很多方法,比如push、pop還有reverse這些我們?cè)陂_(kāi)頭代碼里使用過(guò)的。prototype對(duì)象才是push方法的唯一擁有者,但這個(gè)方法是如何通過(guò)myArray調(diào)用到的呢?
復(fù)制代碼 代碼如下:
myArray.push(3);
要想明白它是怎樣實(shí)現(xiàn)的,第一步是認(rèn)清Protytype一點(diǎn)兒不特殊。Prototype就是一些對(duì)象。我們可以給這些對(duì)象添加方法、屬性,像其他任何的JS對(duì)象一樣。但同時(shí)Prototype也是一個(gè)特殊的對(duì)象。
Prototype的特殊是因?yàn)橄铝幸?guī)則:當(dāng)我們通知JS我們想要在一個(gè)對(duì)象上調(diào)用push方法或是讀取某個(gè)屬性的時(shí)候,解釋器(runtime)首先去尋找這個(gè)對(duì)象本身的方法或?qū)傩?。如果解釋器沒(méi)有找到該方法(或?qū)傩裕┚蜁?huì)沿著_proto_引用去尋找對(duì)象的prototype中的各個(gè)成員。當(dāng)我們?cè)趍yArray中調(diào)用push方法,JS沒(méi)有在myArray對(duì)象中找到push,但是在myArray的prototype對(duì)象中找到了push,即調(diào)用了該push方法(圖3)。
圖 3
我所描述的這種行為本質(zhì)上就是對(duì)象本身繼承了 它的prototype中的所有方法和屬性。我們?cè)贘S中不需要用class來(lái)實(shí)現(xiàn)這種繼承關(guān)系。即,一個(gè)JS對(duì)象從它的prototype中繼承特性。
圖3還告訴我們每個(gè)array對(duì)象都能維護(hù)自己的狀態(tài)(state)和成員。如果我們需要myArray的length屬性,JS將從myArray中找到length的值而不會(huì)去prototype中去尋找。我們能運(yùn)用這個(gè)特性來(lái)“override"一個(gè)方法,即,將需覆蓋的方法(像push)放到myArray自己的對(duì)象中。這樣做就可以有效的將prototype中的push方法隱藏掉。
3.共享Prototype
Prototype在JS中真正神奇的地方是多個(gè)對(duì)象能引用同一個(gè)prototype對(duì)象。比如,我們創(chuàng)建兩個(gè)數(shù)組:
復(fù)制代碼 代碼如下:
var myArray = [1, 2];var yourArray = [4, 5, 6];
這兩個(gè)數(shù)組將共享一個(gè)相同的prototype對(duì)象,下面的代碼將返回true
復(fù)制代碼 代碼如下:
Object.getPrototypeOf(myArray) === Object.getPrototypeOf(yourArray);
如果我們?cè)趦蓚€(gè)數(shù)組中調(diào)用push方法,JS將調(diào)用他們共同的prototype中的push。
Prototype對(duì)象在JS中給我們這種繼承的特性,它們也允許我們共享方法的實(shí)現(xiàn)。Prototype也是鏈?zhǔn)降?。換句話(huà)說(shuō),prototype是一個(gè)對(duì)象,那么prototype對(duì)象也可以擁有一個(gè)指向別的prototype對(duì)象的引用。從圖2中可以看到prototype的_proto_屬性是一個(gè)不為null的值也指向另外一個(gè)prototype.當(dāng)JS開(kāi)始尋找成員變量的時(shí)候,比如push方法,它將沿著這些prototype的引用檢查每一個(gè)對(duì)象直到找到這個(gè)對(duì)象或達(dá)到鏈的尾部為止。這種鏈的方式更增加了JS中繼承和共享的靈活性。
接下來(lái)你也許會(huì)問(wèn):我怎樣設(shè)置自定義對(duì)象的prototype引用?比如,我們之前創(chuàng)建過(guò)的對(duì)象point,我們?cè)鯓蛹尤胍粋€(gè)add方法到prototype對(duì)象中,讓所有的point對(duì)象都能繼承它?在我們回答這個(gè)問(wèn)題之前,我們先了解一下JS中的函數(shù).
4.關(guān)于Funciton
函數(shù)在JS中同樣也是對(duì)象。函數(shù)在JS中有很多重要的特性,在此文章中我們不能一一列舉。但像把一個(gè)函數(shù)賦值給一個(gè)變量或是將一個(gè)函數(shù)當(dāng)做另外一個(gè)函數(shù)的參數(shù)在當(dāng)今的JS編程中是很基礎(chǔ)的方式。
我們需要關(guān)注的是:因?yàn)楹瘮?shù)是對(duì)象,所以它擁有方法、屬性和一個(gè)prototype對(duì)象的引用。我們一起討論一下下面代碼的含義:
復(fù)制代碼 代碼如下:
// this will return true:
typeof (Array) === "function"
// and so will this:
Object.getPrototypeOf(Array) === Object.getPrototypeOf(function () { })
// and this, too:
Array.prototype != null
第一行代碼證明Array在JS中是一個(gè)函數(shù)。待會(huì)兒我們將看到怎樣調(diào)用Array函數(shù)來(lái)創(chuàng)建一個(gè)新的array對(duì)象。
第二行代碼證明Array對(duì)象和function對(duì)象引用相同的prototype,就像我們之前看到的所有的array對(duì)象共享一個(gè)prototype。
最后一行證明Array函數(shù)有一個(gè)prototype屬性。千萬(wàn)不要將這個(gè)prototype屬性和_proto_屬性混淆了。它們的使用目的和指向的對(duì)象都不相同。
復(fù)制代碼 代碼如下:
// true
Array.prototype == Object.getPrototypeOf(myArray)
// also true
Array.prototype == Object.getPrototypeOf(yourArray);
我們用新學(xué)的知識(shí)重畫(huà)之前的圖片:
圖 5
現(xiàn)在我們要?jiǎng)?chuàng)建一個(gè)array對(duì)象。其中一種方法就是:復(fù)制代碼 代碼如下:
// create a new, empty object
var o = {};
// inherit from the same prototype as an array object
o.__proto__ = Array.prototype;
// now we can invoke any of the array methods ...
o.push(3);
盡管上面的代碼看起來(lái)不錯(cuò),但問(wèn)題是不是每一個(gè)JS的環(huán)境都支持對(duì)象的_proto_屬性。幸運(yùn)的是,JS內(nèi)置一個(gè)標(biāo)準(zhǔn)的機(jī)制用來(lái)創(chuàng)建新對(duì)象同時(shí)設(shè)置對(duì)象的_proto_屬性,這就是“new”操作符。
復(fù)制代碼 代碼如下:
var o = new Array();
o.push(3);
“new”操作符在JS中有三個(gè)重要的任務(wù):首先,它創(chuàng)建一個(gè)新的空對(duì)象。接著,它設(shè)置這個(gè)新對(duì)象的_proto_屬性指向調(diào)用函數(shù)的prototype屬性。最后,執(zhí)行調(diào)用函數(shù)同時(shí)把“this”指針指向新的對(duì)象。如果我們把上面的兩行代碼展開(kāi),將得到以下的代碼:
復(fù)制代碼 代碼如下:
var o = {};
o.__proto__ = Array.prototype;
Array.call(o);
o.push(3);
函數(shù)的“call”方法允許你調(diào)用一個(gè)函數(shù)同時(shí)指定這個(gè)函數(shù)里面的"this"指向傳入的新對(duì)象。當(dāng)然,我們也想通過(guò)上面的方法來(lái)創(chuàng)建我們自己的對(duì)象來(lái)實(shí)現(xiàn)對(duì)象的繼承,這種函數(shù)就是我們所熟知的——構(gòu)造函數(shù)。
5.構(gòu)造函數(shù)
構(gòu)造函數(shù)是一個(gè)有兩個(gè)獨(dú)特標(biāo)識(shí)的普通JS函數(shù)對(duì)象:
1.首字母大寫(xiě)(容易識(shí)別)。
2.用new操作符連接來(lái)構(gòu)造新對(duì)象。
Array就是一個(gè)構(gòu)造函數(shù)——Array函數(shù)用new連接、首字母大寫(xiě)。JS中的Array函數(shù)是內(nèi)置的,但任何人都可以創(chuàng)建自己的構(gòu)造函數(shù)。事實(shí)上,我們終于到了該為point對(duì)象來(lái)創(chuàng)建一個(gè)構(gòu)造函數(shù)的時(shí)候了。
復(fù)制代碼 代碼如下:
var Point = function (x, y) {
this.x = x;
this.y = y;
this.add = function (otherPoint) {
this.x = otherPoint.x;
this.y = otherPoint.y;
}
}
var p1 = new Point(3, 4);
var p2 = new Point(8, 6);
p1.add(p2);
上面的代碼中我們使用new操作符和Point函數(shù)來(lái)來(lái)構(gòu)造一個(gè)point對(duì)象。在內(nèi)存中你可以把最終的結(jié)果想成圖6所表示的樣子。
圖 6
現(xiàn)在的問(wèn)題是,add方法存在于每一個(gè)point對(duì)象中。鑒于我們對(duì)prototype的了解,把a(bǔ)dd方法加到Point.prototype中是一個(gè)更好的選擇(不必把a(bǔ)dd方法的代碼拷貝到每個(gè)對(duì)象中)。為了實(shí)現(xiàn)這個(gè)目的,我們需要在Point.prototype對(duì)象上做些修改。
復(fù)制代碼 代碼如下:
var Point = function (x, y) {
this.x = x;
this.y = y;
}
Point.prototype.add = function (otherPoint) {
this.x = otherPoint.x;
this.y = otherPoint.y;
}
var p1 = new Point(3, 4);
var p2 = new Point(8, 6);
p1.add(p2);
好了!我們已經(jīng)用prototype實(shí)現(xiàn)了JS中的繼承!
6.總結(jié)
希望能通過(guò)這篇文章讓你能撥開(kāi)prototype的迷霧。當(dāng)然這只是功能強(qiáng)大又靈活的prototype的入門(mén)。更多的關(guān)于prototype的知識(shí)還是希望讀者能夠自己去探索和發(fā)現(xiàn)。
您可能感興趣的文章:
- Javascript中 關(guān)于prototype屬性實(shí)現(xiàn)繼承的原理圖
- JavaScript類(lèi)和繼承 prototype屬性
- js中繼承的幾種用法總結(jié)(apply,call,prototype)
- 深入了解javascript中的prototype與繼承
- javascript prototype的深度探索不是原型繼承那么簡(jiǎn)單
- Javascript 原型和繼承(Prototypes and Inheritance)
- JavaScript不使用prototype和new實(shí)現(xiàn)繼承機(jī)制
- JavaScript使用prototype原型實(shí)現(xiàn)的封裝繼承多態(tài)示例
- javascript基于prototype實(shí)現(xiàn)類(lèi)似OOP繼承的方法
- Javascript中的prototype與繼承
- JS偽繼承prototype實(shí)現(xiàn)方法示例
- JavaScript使用prototype屬性實(shí)現(xiàn)繼承操作示例
相關(guān)文章
javascript最常用與實(shí)用的創(chuàng)建類(lèi)的代碼
組合構(gòu)造函數(shù)模式和原型模式2010-08-08javascript 面向?qū)ο缶幊?聊聊對(duì)象的事
javascript是基于對(duì)象的編程語(yǔ)言。從window到document,從方法到類(lèi),從object到Array都是對(duì)象。2009-09-09javascript面向?qū)ο笾甁avascript 繼承
所有面向?qū)ο蟮恼Z(yǔ)言都應(yīng)該有繼承的特性,JavaScript 也不例外。2010-05-05從面試題學(xué)習(xí)Javascript 面向?qū)ο螅▌?chuàng)建對(duì)象)
從面試題學(xué)習(xí)Javascript 面向?qū)ο螅▌?chuàng)建對(duì)象),學(xué)習(xí)js的朋友可以參考下2012-03-03javascript面向?qū)ο蟮姆绞綄?shí)現(xiàn)的彈出層效果代碼
由于本人以前是.net程序員,所以即使現(xiàn)在在做前端,也習(xí)慣于用面向?qū)ο蟮姆绞骄帉?xiě)js腳本,我想如果你以前也是或者現(xiàn)在還是名第三代程序員的話(huà),應(yīng)該對(duì)此并不陌生。2010-01-01mapper--圖片熱點(diǎn)區(qū)域高亮組件官方站點(diǎn)
2007-12-12