理解 JavaScript 中的原型

前言

JavaScript 中的原型一直是我很懼怕的一個(gè)主題忿项,理由很簡單,因?yàn)檎娴牟缓美斫猓_實(shí)是 JavaScript 中很重要的一部分榨为,而且是面試的必考題,就算現(xiàn)在不懂,以后遲早有一天要把它弄懂绰精,不然的話永遠(yuǎn)都沒辦法把自己的技術(shù)能力往上提高一個(gè)層次,所以今天就來講講 JavaScript 中的原型硫椰。

本文是這系列的第四篇蹄胰,往期文章:

  1. 理解 JavaScript 中的作用域
  2. 理解 JavaScript 中的閉包
  3. 理解 JavaScript 中的 this

什么是原型

首先要說一下為什么會(huì)有原型這個(gè)東西派继,那是因?yàn)樵?JavaScript 中并沒有 “類” 的概念庆猫,它是靠原型和原型鏈實(shí)現(xiàn)對象屬性的繼承,即便在 ES6 中新出了class的語法,但那也只是一個(gè)語法糖,它的底層依然是原型。

要理解原型(原型鏈)牙丽,最重要的是理解兩個(gè)屬性以及它們之間的關(guān)系:

  • __proto__
  • prototype

__proto__

JavaScript中构罗,萬物皆對象,所有的對象都有__proto__屬性(nullundefined除外)盖彭,而且指向創(chuàng)造這個(gè)對象的函數(shù)對象的prototype屬性。

var obj = {};
console.log( obj.__proto__ === Object.prototype ); // true
var arr = [];
console.log( arr.__proto__ === Array.prototype ); // true
var fn = function(){};
console.log( fn.__proto__ === Function.prototype ); // true
var str = "";
console.log( str.__proto__ === String.prototype ); // true
var num = 1;
console.log( num.__proto__ === Number.prototype ); // true

前面說了片挂,在 JavaScript 中邻悬,一切皆對象(可以理解為它們都是從對象那里繼承過來的),所以:

console.log( Function.prototype.__proto__ === Object.prototype ); // true
console.log( Array.prototype.__proto__ === Object.prototype ); // true
console.log( String.prototype.__proto__ === Object.prototype ); // true

而因?yàn)?code>Object.prototype的__proto__已經(jīng)是終點(diǎn)了攘烛,所以它的指向是:

console.log( Object.prototype.__proto__ === null ); // true

注意更哄,雖然大多數(shù)瀏覽器都支持通過__proto__來訪問,但它并不是ECMAScript的標(biāo)準(zhǔn),在 ES5 中可以通過Object.getPrototypeOf()來獲取這個(gè)屬性。

var obj = {};
console.log( Object.getPrototypeOf(obj) === Object.prototype ); // true

prototype

prototype是每個(gè)函數(shù)對象都具有的屬性(它也有__proto__鱼喉,因?yàn)楹瘮?shù)也是對象)皱坛,實(shí)例化創(chuàng)建出來的對象會(huì)共享此prototype里的屬性和方法(通過__proto__)贩猎。

在上面的例子中已經(jīng)看到過prototype的身影,下面通過一個(gè)例子來講述它的作用。

現(xiàn)在我們有一個(gè)構(gòu)造函數(shù)Person桩匪,并且對它進(jìn)行實(shí)例化:

function Person(name){
    this.name = name;
    this.sayName = function(){
        console.log("我的名字是:" + this.name);
    }
}

var a = new Person("小明");
var b = new Person("小紅");

a.sayName(); // 我的名字是:小明
b.sayName(); // 我的名字是:小紅

new運(yùn)算符的缺點(diǎn)

但是葛碧,用構(gòu)造函數(shù)生成實(shí)例對象,有一個(gè)缺點(diǎn),那就是無法共享屬性和方法菠发。

例如上面例子中的ab糜俗,它們都有sayName方法楔敌,雖然做的事相同氛谜,但它們卻是獨(dú)立的杨何,這就會(huì)造成極大的資源浪費(fèi),因?yàn)槊恳粋€(gè)實(shí)例對象埃跷,都有自己的屬性和方法的副本。

prototype屬性的引入

考慮到這一點(diǎn)酱固,Brendan Eich 決定為構(gòu)造函數(shù)設(shè)置一個(gè)prototype屬性。

這個(gè)屬性包含一個(gè)對象,所有實(shí)例對象需要共享的屬性和方法恃鞋,都放在這個(gè)對象里面荠呐,而不需要共享屬性和方法媚创,就放在構(gòu)造函數(shù)里面,這個(gè)對象就是prototype對象宝磨。

實(shí)例對象一旦創(chuàng)建,將自動(dòng)引用prototype對象的屬性和方法。也就是說贝奇,實(shí)例對象的屬性和方法,分成兩種,一種是本地的塌忽,另一種是引用的棉圈。

現(xiàn)在對上面的例子進(jìn)行改寫:

function Person(name){
    this.name = name;
}
Person.prototype = {
    sayName : function(){
        console.log("我的名字是:" + this.name);
    }
}

var a = new Person("小明");
var b = new Person("小紅");
a.sayName() // 我的名字是:小明
b.sayName() // 我的名字是:小紅

現(xiàn)在無論Person被實(shí)例化多少次上岗,它的實(shí)例對象都共享同一個(gè)sayName方法,這就是prototype最大的用處。

原型鏈

講原型一個(gè)不可避免的概念就是原型鏈始绍,原型鏈?zhǔn)峭ㄟ^__proto__來實(shí)現(xiàn)的。

現(xiàn)在我們以Person的例子來講整個(gè)原型鏈芽狗。

var a = new Person("小明");

// 實(shí)例化對象的 __proto__ 指針指向構(gòu)造函數(shù)的原型
console.log( a.__proto__ === Person.prototype )
// 構(gòu)造函數(shù)的原型是一個(gè)對象鲁捏,它的 __proto__ 指向?qū)ο蟮脑?console.log( Person.prototype.__proto__ === Object.prototype )
// 函數(shù)也是一個(gè)對象,它的 __proto__ 指向 函數(shù)的原型
console.log( Person.__proto__ === Function.prototype )
// 函數(shù)的原型是一個(gè)對象虎谢,它的 __proto__ 指向?qū)ο蟮脑?console.log( Function.prototype.__proto__ === Object.prototype )
// 對象的原型的__proto__ 指向 null
console.log( Object.prototype.__proto__ === null )

以上就是a對象的整個(gè)原型鏈婴噩。

屬性查找機(jī)制

當(dāng)訪問一個(gè)對象的屬性時(shí),Javascript 會(huì)從對象本身開始往上遍歷整個(gè)原型鏈,直到找到對應(yīng)屬性為止峭沦。如果此時(shí)到達(dá)了原型鏈的頂部,也就是上例中的 Object.prototype矛辕,仍然未發(fā)現(xiàn)需要查找的屬性刽宪,那么 Javascript 就會(huì)返回 undefined值。

注:此文為原創(chuàng)文章界酒,如需轉(zhuǎn)載圣拄,請注明出處。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末毁欣,一起剝皮案震驚了整個(gè)濱河市庇谆,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌凭疮,老刑警劉巖饭耳,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異执解,居然都是意外死亡寞肖,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進(jìn)店門衰腌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來新蟆,“玉大人,你說我怎么就攤上這事桶唐≌て希” “怎么了?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵尤泽,是天一觀的道長欣簇。 經(jīng)常有香客問我,道長坯约,這世上最難降的妖魔是什么熊咽? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮闹丐,結(jié)果婚禮上横殴,老公的妹妹穿的比我還像新娘。我一直安慰自己卿拴,他們只是感情好衫仑,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著堕花,像睡著了一般文狱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上缘挽,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天瞄崇,我揣著相機(jī)與錄音呻粹,去河邊找鬼。 笑死苏研,一個(gè)胖子當(dāng)著我的面吹牛等浊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播摹蘑,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼筹燕,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了衅鹿?” 一聲冷哼從身側(cè)響起庄萎,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎塘安,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體援奢,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡兼犯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了集漾。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片切黔。...
    茶點(diǎn)故事閱讀 38,064評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖具篇,靈堂內(nèi)的尸體忽然破棺而出纬霞,到底是詐尸還是另有隱情,我是刑警寧澤驱显,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布诗芜,位于F島的核電站,受9級特大地震影響埃疫,放射性物質(zhì)發(fā)生泄漏伏恐。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一栓霜、第九天 我趴在偏房一處隱蔽的房頂上張望翠桦。 院中可真熱鬧,春花似錦胳蛮、人聲如沸销凑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽斗幼。三九已至,卻和暖如春茂洒,著一層夾襖步出監(jiān)牢的瞬間孟岛,已是汗流浹背瓶竭。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留渠羞,地道東北人斤贰。 一個(gè)月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像次询,于是被迫代替她去往敵國和親荧恍。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 在Brendan Eich大神為JavaScript設(shè)計(jì)面向?qū)ο笙到y(tǒng)時(shí)屯吊,之所以選擇基于原型的面向?qū)ο笙到y(tǒng)送巡,并不是因...
    指尖的宇宙閱讀 650評論 0 2
  • 原型prototype是javascript中極其重要的概念之一,但也是比較容易引起混淆的地方盒卸。我們需要花費(fèi)一些時(shí)...
    六尺帳篷閱讀 2,141評論 1 15
  • JavaScript 作為一門面對對象語言骗爆,但是卻不支持接口繼承,只支持實(shí)現(xiàn)繼承蔽介。JavaScript 中實(shí)現(xiàn)繼承...
    demonly閱讀 168評論 0 0
  • 麥芽屬于大麥品種摘投,主要種植和產(chǎn)地都在北方,也是他們?nèi)粘6紩?huì)食用的一種食物虹蓄。當(dāng)然犀呼,隨著如今交通的便利,南方比較大型的...
    執(zhí)筆青衫閱讀 1,394評論 0 0
  • 我寧可獨(dú)自坐在南瓜上薇组,也不愿意跟人擠著坐在天鵝絨墊子上外臂。我寧可乘坐一輛沒有路線的牛車,也不愿搭乘花里胡哨的火車律胀、沿...
    xiaoqinghua閱讀 606評論 0 0