JavaScript 繼承與原型鏈

基本知識

js中可以理解為只有一種結(jié)構(gòu)逻悠,那就是 object叙谨,每個實例對象(object)都會有一個私有屬性(__proto__)指向他的原型對象(prototype)。該原型對象(prototype)自己也有__proto__欧宜,層層向上指,直到一個對象的原型對象為null疾渣。根據(jù)定義篡诽,null沒有原型,為原型鏈的最后一個環(huán)節(jié)榴捡。

幾乎所有 JavaScript 中的對象都是位于原型鏈頂端的Object的實例杈女。

基于原型鏈的繼承

繼承屬性

JavaScript 對象是動態(tài)的屬性“包”(指其自己的屬性)。JavaScript 對象有一個指向一個原型對象的鏈吊圾。當試圖訪問一個對象的屬性時达椰,它不僅僅在該對象上搜尋,還會搜尋該對象的原型项乒,以及該對象的原型的原型啰劲,依次層層向上搜索,直到找到一個名字匹配的屬性或到達原型鏈的末尾

// eg:
let  func = function(){
    this.a = 1;
    this.b = 2;
}
let obj = new func() // { a:1, b:2 }
func.prototype.b = 3;
func.prototype.c = 4;
// 那么我們就可以得到一個原型鏈
obj  // { a:1, b:2 }
obj.__proto__ // { b:3, c:4 }
obj.__proto__.__proto__ // Object.prototype
obj.__proto__.__proto__.__proto__ // null
// 原型鏈的末尾檀何,即 null
// 所以整條原型鏈如下:
{a:1, b:2} ---> {b:3, c:4} ---> Object.prototye---> null
控制臺截圖
// 那么檢查一下:
obj.a // 1
obj.b // 2
obj.c // 4
obj.d // undefined (因為未在原型鏈上被找到)
// 疑問:
// 原型上也有一個'b'屬性,但是它不會被訪問到.這種情況稱為"屬性遮蔽 (property shadowing)"
繼承方法

在js中并沒有基于類繼承的方法蝇裤,任何函數(shù)都可以添加到對象上作為對象的屬性。函數(shù)的繼承與其他的屬性繼承沒有差別频鉴,包括上面的“屬性遮蔽”(這種情況相當于其他語言的方法重寫)栓辜。
當繼承的函數(shù)被調(diào)用的時候,可以簡單理解為在哪里被調(diào)用this就指向哪里垛孔,因為this會指向當前繼承的對象藕甩,而不是繼承函數(shù)所在的原型對象

let obj2  = {
a:1,
b:function(){
return this.a + 1;
}}
console.log(obj2.b()) // 2 this指向了obj2
let obj3 = Object.create(obj2)
obj3.a = 4;
console.log(obj3.b())// 5 this指向了obj3
}

使用不同的方法來創(chuàng)建對象和生成原型鏈

語法結(jié)構(gòu)創(chuàng)建的對象
let obj4 = { a:1 };
// obj4 繼承了Object.proptype上的所有屬性
// 原型鏈:{ a:1 } => Object.proptype => null
let obj5 = [ 1, 2, 3 ];
// obj5 繼承了Array.proptype上的所有屬性 但是js中array也屬于對象,
// 所以Array.proptype 也繼承了Object.proptype上的所有屬性周荐。
// 原型鏈:[ 1, 2, 3 ] => Array.proptype => Object.proptype =>  null
function obj6(){
  return 2;
}
// 同樣obj6繼承了Function.proptype上的所有屬性狭莱,但是js中function也屬于對象
// 原型鏈:obj6 => Function.prototype => Object.proptype => null
構(gòu)造器創(chuàng)建的對象

在 JavaScript 中,構(gòu)造器其實就是一個普通的函數(shù)概作。當使用 new 操作符 來作用這個函數(shù)時贩毕,它就可以被稱為構(gòu)造方法(構(gòu)造函數(shù))。

function func1() {
this.list = [];
};
func1.proptype.addlist = function(item){
this.list.push(item)
};
let func2 = new func1;
//  func2 => func1.proptype => Object.Proptype => null 
Object.create 創(chuàng)建的對象

ECMAScript 5 中引入了一個新方法:Object.create()仆嗦』越祝可以調(diào)用這個方法來創(chuàng)建一個新對象。新對象的原型就是調(diào)用 create 方法時傳入的第一個參數(shù):

let obj7 = { a : 3 }
//  obj7 => Object.proptype => null 
let obj8 = Object.create(obj7);
// obj8 => obj7 =>  Object.proptype => null
let obj9 = Object.create(obj8)
//obj9  => obj8 => obj7 =>  Object.proptype => null
var obj10 = Object.create(null);
// d ---> null
console.log(obj10.hasOwnProperty); 
// undefined, 因為d沒有繼承Object.prototype
class關(guān)鍵字創(chuàng)建的對象

ECMAScript6 引入了一套新的關(guān)鍵字用來實現(xiàn) class瘩扼。使用基于類語言的開發(fā)人員會對這些結(jié)構(gòu)感到熟悉谆甜,但它們是不同的。JavaScript 仍然基于原型集绰。這些新的關(guān)鍵字包括 class, constructor规辱,staticextendssuper栽燕。

class  Check{
    constructor(a){
      this.a = a;
    }
}
class AddNum  extends Check{
    constructor(num) {
      super(num);
  }
  get addnum() {
    return this.num + this.num
  }
  set  setNum(num) {
    this.num = num 
  }
}
let test = new AddNum(3)
// test => {a:3 ,addnum:NaN} => AddNum的原型對象 => Check的原型對象 => Object.proptype => null
性能

在原型鏈上查找屬性比較耗時罕袋,對性能有副作用改淑,這在性能要求苛刻的情況下很重要。另外浴讯,試圖訪問不存在的屬性時會遍歷整個原型鏈
遍歷對象的屬性時朵夏,原型鏈上的每個可枚舉屬性都會被枚舉出來。要檢查對象是否具有自己定義的屬性榆纽,而不是其原型鏈上的某個屬性仰猖,則必須使用所有對象從Object.prototype繼承的 hasOwnProperty 方法。下面給出一個具體的例子來說明它:

let obj11 = {
  a:1
  }
let obj12 = Object.create(obj11)
console.log(obj11.hasOwnProperty('a'));
//  true
console.log(obj11.hasOwnProperty('b'));
//  false
console.log(obj12.hasOwnProperty('a'));
//  false
console.log(obj12.__proto__.hasOwnProperty('a'));
//  true

hasOwnProperty 是 JavaScript 中處理屬性并且不會遍歷原型鏈的方法之一奈籽。(另一種方法: Object.keys())

Object.keys(obj12)
// []
Object.keys(obj11)
// ["a"]

注意:檢查屬性是否undefined還不夠饥侵。該屬性可能存在,但其值恰好設置為undefined衣屏。

總結(jié)

var o = new Foo();
// JavaScript 實際上執(zhí)行的是:
var o = new Object();
o.__proto__ = Foo.prototype;
Foo.call(o);
// 然后當你執(zhí)行
o.a
// 它檢查o是否具有a屬性躏升。如果沒有,它會查找 Object.getPrototypeOf(o).a狼忱,如果仍 
// 舊沒有膨疏,它會繼續(xù)查找 Object.getPrototypeOf(Object.getPrototypeOf(o)).a。

遵循ECMAScript標準藕赞,someObject.[[Prototype]] 符號是用于指向 someObject的原型。從 ECMAScript 6 開始卖局,[[Prototype]] 可以通過Object.getPrototypeOf()Object.setPrototypeOf()訪問器來訪問斧蜕。這個等同于 JavaScript 的非標準但許多瀏覽器實現(xiàn)的屬性 __proto__

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末砚偶,一起剝皮案震驚了整個濱河市批销,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌染坯,老刑警劉巖均芽,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異单鹿,居然都是意外死亡掀宋,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進店門仲锄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來劲妙,“玉大人,你說我怎么就攤上這事儒喊×头埽” “怎么了?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵怀愧,是天一觀的道長侨颈。 經(jīng)常有香客問我余赢,道長,這世上最難降的妖魔是什么哈垢? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任妻柒,我火速辦了婚禮,結(jié)果婚禮上温赔,老公的妹妹穿的比我還像新娘蛤奢。我一直安慰自己,他們只是感情好陶贼,可當我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布啤贩。 她就那樣靜靜地躺著,像睡著了一般拜秧。 火紅的嫁衣襯著肌膚如雪痹屹。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天枉氮,我揣著相機與錄音志衍,去河邊找鬼。 笑死聊替,一個胖子當著我的面吹牛楼肪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播惹悄,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼春叫,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了泣港?” 一聲冷哼從身側(cè)響起暂殖,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎当纱,沒想到半個月后呛每,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡坡氯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年晨横,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片箫柳。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡颓遏,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出滞时,到底是詐尸還是另有隱情叁幢,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布坪稽,位于F島的核電站曼玩,受9級特大地震影響鳞骤,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜黍判,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一豫尽、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧顷帖,春花似錦美旧、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至陶舞,卻和暖如春嗽测,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背肿孵。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工唠粥, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人停做。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓晤愧,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蛉腌。 傳聞我的和親對象是個殘疾皇子官份,可洞房花燭夜當晚...
    茶點故事閱讀 45,512評論 2 359

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