Javascript Prototype原型

首先我們要知道艇搀,在Javascript中,所有的函數(shù)function和對(duì)象object都有一個(gè)屬性叫做原型求晶,不同的是函數(shù)的原型屬性寫成prototype焰雕,而對(duì)象的原型屬性在不同的瀏覽器里實(shí)現(xiàn)可能稍微有一點(diǎn)不一樣,不過一般都寫成__proto__芳杏。

我們來看下面的例子:

function Cat(name, color) {

? this.name = name;

? this.color = color;

}

Cat.prototype.age = 0;

var catC = new Cat("Fluffy", "White");

catC.__proto__.age = 4;

這里的Cat.prototype和catC.__proto__實(shí)際上指向了同一個(gè)對(duì)象矩屁,所以當(dāng)catC.__proto__.age的值被改為4時(shí)辟宗,Cat.prototype.age的值也變?yōu)榱?.

為了理解原型prototype的作用,我們先要了解Javascript中對(duì)象Object的構(gòu)造吝秕。簡單來說泊脐,Javascript的對(duì)象就是一堆屬性的集合,一個(gè)屬性由一個(gè)key(關(guān)鍵字或者屬性名)和value(值)組成烁峭。比如

{ name:"Fluffy", color: "White"}

這個(gè)對(duì)象由兩個(gè)屬性組成:name和color容客。

Javascript對(duì)象的屬性又分兩種,一種是內(nèi)部屬性约郁,就像上面這個(gè)對(duì)象中的name和color缩挑。這種屬性是只屬于這個(gè)對(duì)象的,對(duì)這樣的屬性值的訪問和修改只能通過對(duì)象的名字加屬性名來實(shí)現(xiàn)鬓梅,就像catC.name,catC.color供置。另外一種屬性叫外部屬性,就是通過原型prototype來實(shí)現(xiàn)的绽快。一個(gè)對(duì)象是否有對(duì)應(yīng)的內(nèi)部屬性可以通過hasOwnProperty方法來判斷芥丧,例如catC.hasOwnProperty('age')返回false,表示age不是catC的內(nèi)部屬性谎僻,雖然catC.age是可以可以訪問的值。

我們以訪問catC.age為例來說明外部屬性寓辱。當(dāng)Javascript引擎解析catC.age時(shí)艘绍,它首先會(huì)在catC的內(nèi)部屬性中尋找屬性age,這時(shí)發(fā)現(xiàn)catC這個(gè)對(duì)象沒有age的屬性秫筏,它會(huì)繼續(xù)在catC的__proto__這個(gè)屬性中找(從上面的討論中我們知道诱鞠,每一個(gè)對(duì)象都有一個(gè)原型屬性__proto__)。如何從__proto__中找呢这敬?我們知道__proto__是一個(gè)對(duì)象航夺,所以__proto__也有自己對(duì)象的內(nèi)部屬性,所以Javascript引擎會(huì)找__proto__是否有age這樣的內(nèi)部屬性崔涂,在上面的例子中我們發(fā)現(xiàn)有一個(gè)調(diào)用catC.__proto__.age = 4阳掐,這實(shí)際上是給catC.__proto__設(shè)置了內(nèi)部屬性age的值,這就是catC的外部屬性age冷蚂。如果在catC.__proto__中沒有找到相應(yīng)的屬性缭保,會(huì)怎么辦呢?我們知道catC.__proto__也是一個(gè)對(duì)象蝙茶,所以它也有__proto__屬性艺骂,所以Javascript引擎會(huì)繼續(xù)在catC.__proto__.__proto__中找,最終會(huì)找到系統(tǒng)的Object對(duì)象的prototype屬性隆夯。這個(gè)尋找的過程钳恕,像是循著一個(gè)鏈條找别伏,這個(gè)鏈條就叫原型鏈(Prototype Chain)。

我們?cè)賮矸治鲆幌聦?duì)象和函數(shù)中的原型(Prototype)的值是怎么設(shè)置的忧额。首先我們來看對(duì)象的原型是如何設(shè)置的厘肮。我們創(chuàng)建對(duì)象有幾種方式:

1.直接創(chuàng)建對(duì)象 { name:"Fluffy", color: "White"}:這時(shí)它的原型屬性__proto__的值是一個(gè)空的Object對(duì)象。

2.通過new方法使用函數(shù)創(chuàng)建 new Cat("Fluffy", "White"): 這時(shí)創(chuàng)建的對(duì)象的__proto__的值是函數(shù)的prototype屬性即Cat.prototype.

3.通過Object.create創(chuàng)建 Object.create(catC): 這時(shí)創(chuàng)建的對(duì)象的__proto__的值是catC.

我們?cè)賮砜春瘮?shù)的prototype屬性值宙址。對(duì)于一個(gè)函數(shù)而言轴脐,它的prototype屬性值缺省為一個(gè)沒有屬性的空對(duì)象。在Cat函數(shù)的例子中抡砂,Cat函數(shù)的prototype屬性最開始就是一個(gè)空的對(duì)象大咱,這個(gè)對(duì)象的對(duì)象名為函數(shù)名(Cat)。當(dāng)我們調(diào)用Cat.prototype.age = 0之后注益,Cat.prototype增加了一個(gè)age屬性碴巾。因?yàn)?b>Cat.prototype是一個(gè)對(duì)象,所以它也有一個(gè)原型屬性__proto__丑搔,這個(gè)原型屬性Cat.prototype.__proto__的值是一個(gè)空的Object對(duì)象厦瓢,空的Object對(duì)象也有__proto__屬性值,只不過屬性值為null啤月。

有了以上的知識(shí)煮仇,我們就能很容易判斷下面程序中的運(yùn)行結(jié)果(粗體的為運(yùn)行結(jié)果):
function Cat(name, color) {

? this.name = name;

? this.color = color;

}

Cat.prototype.age = 3;

var fluffy = new Cat("Fluffy", "White");

var scratchy = new Cat("Scratchy", "Black");

fluffy.age;

3

scratchy.age;

3

Cat.prototype.age = 4; //fluffy和scratchy的__proto__指向Cat.prototype,改變Cat.prototype.age的值谎仲,就相當(dāng)于改變fluffy和scratchy的age的值

fluffy.age;

4

scratchy.age;

4

Cat.prototype = {age: 5}; // fluffy和scratchy的__proto__指向的是原來Cat.prototype的那個(gè)對(duì)象浙垫,改變Cat.prototype所指向的對(duì)象并不會(huì)改變?cè)瓉韺?duì)象里的值

fluffy.age;

4

scratchy.age;

4

var muffin = new Cat("Muffin", "Brown"); //這個(gè)對(duì)象的__proto__指向的是當(dāng)前的Cat.prototype即{age:5}

muffin.age;

5

fluffy.age = 6; //這個(gè)相當(dāng)于添加了一個(gè)fluffy的內(nèi)部屬性,只會(huì)影響fluffy郑诺,不會(huì)影響其他對(duì)象

fluffy.age;

6

scratchy.age;

4

fluffy.__proto__.age = 7; //fluffy.__proto__和scratchy.__proto__指向的是同一個(gè)對(duì)象夹姥,改變一個(gè)會(huì)導(dǎo)致另外一個(gè)改變

fluffy.age;

7

scratchy.age;

7

從上面的討論中,我們可以看出原型prototype主要是用于為Javascript對(duì)象提供外部屬性辙诞。有了這一特性辙售,它可以在Javascript實(shí)現(xiàn)一些其他強(qiáng)大的功能,例如繼承飞涂。

簡單的旦部,我們通過函數(shù)創(chuàng)建出來的所有對(duì)象實(shí)例的原型__proto__都指向的是函數(shù)的原型,所以我們通過改變函數(shù)的原型就能改變所有對(duì)象實(shí)例的外部屬性较店,例如添加新的方法志鹃。在下面的例子中,可以給所有Cat的實(shí)例添加一個(gè)changeName的方法泽西。

function Cat(name, color) {

? this.name = name;

? this.color = color;

}

Cat.prototype.changeName = function(newName) {

? this.name = newName;

};

或者我們可以基于原有的函數(shù)曹铃,創(chuàng)建一個(gè)新的函數(shù),新函數(shù)可以繼承原來函數(shù)的所有方法和屬性捧杉。

function PersianCat(name, color, type) {

? Cat.call(this, name, color); // 調(diào)用Cat的構(gòu)造函數(shù)以設(shè)置內(nèi)部屬性

? this.type = type;

}

PersianCat.prototype = Object.create(Cat.prototype); // 這可以將Cat的原型做為上層原型陕见,繼承Cat的外部屬性秘血。

Object.defineProperty(PersianCat.prototype, 'constructor', {

? ? value: PersianCat,

? ? enumerable: false, // 這樣這個(gè)構(gòu)造函數(shù)就不會(huì)出現(xiàn)在'for in' 循環(huán)里

? ? writable: true }); // 通過這個(gè)來修改PersianCat的構(gòu)造函數(shù)的名字

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市评甜,隨后出現(xiàn)的幾起案子灰粮,更是在濱河造成了極大的恐慌,老刑警劉巖忍坷,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件粘舟,死亡現(xiàn)場離奇詭異,居然都是意外死亡佩研,警方通過查閱死者的電腦和手機(jī)柑肴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來旬薯,“玉大人晰骑,你說我怎么就攤上這事“硇颍” “怎么了硕舆?”我有些...
    開封第一講書人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵,是天一觀的道長骤公。 經(jīng)常有香客問我抚官,道長,這世上最難降的妖魔是什么阶捆? 我笑而不...
    開封第一講書人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任凌节,我火速辦了婚禮,結(jié)果婚禮上趁猴,老公的妹妹穿的比我還像新娘刊咳。我一直安慰自己彪见,他們只是感情好儡司,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著余指,像睡著了一般捕犬。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上酵镜,一...
    開封第一講書人閱讀 49,764評(píng)論 1 290
  • 那天碉碉,我揣著相機(jī)與錄音,去河邊找鬼淮韭。 笑死垢粮,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的靠粪。 我是一名探鬼主播蜡吧,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼毫蚓,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了昔善?” 一聲冷哼從身側(cè)響起元潘,我...
    開封第一講書人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎君仆,沒想到半個(gè)月后翩概,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡返咱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年钥庇,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片洛姑。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡上沐,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出楞艾,到底是詐尸還是另有隱情参咙,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布硫眯,位于F島的核電站蕴侧,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏两入。R本人自食惡果不足惜净宵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望裹纳。 院中可真熱鬧择葡,春花似錦、人聲如沸剃氧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽朋鞍。三九已至已添,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間滥酥,已是汗流浹背更舞。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留坎吻,地道東北人缆蝉。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親刊头。 傳聞我的和親對(duì)象是個(gè)殘疾皇子贝搁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348