繼承和原型鏈

繼承方面,JavaScript 中的每一個對象都有一個內部私有的連接指向另外一個對象,這個對象就是原對象的原型。這個原型對象也有本身的原型,直到對象的原型爲 null 爲止(也就是沒有原型)。這種一級一級的鏈結構就稱爲原型鏈數組

雖然這一般會被稱做 JavaScript 的弱點之一,實際上這種原型繼承的模型要比經典的繼承模型還要強大。雖然在原型模型上構建一個經典模型是至關瑣碎的,但若是採起其餘方式實現則會更加困難。函數

基於原型鏈的繼承

繼承屬性

JavaScript 對象有兩種不一樣的屬性,一種是對象自身的屬性,另一種是繼承於原型鏈上的屬性。下面的代碼則演示了當訪問一個對象的屬性時發生的行爲:this

// 假定咱們有個對象o,而且o所在的原型鏈以下:
// {a:1, b:2} ---> {b:3, c:4} ---> null
// 'a'和'b'是o自身的屬性.

// 該例中,用"對象.[[Prototype]]"來表示這個對象的原型.
// 這只是一個純粹的符號表示(ECMAScript標準中也這樣使用),不能在實際代碼中使用.

console.log(o.a); // 1
// a是o的自身屬性嗎?是的,該屬性的值爲1

console.log(o.b); // 2
// b是o的自身屬性嗎?是的,該屬性的值爲2
// o.[[Prototype]]上還有一個'b'屬性,可是它不會被訪問到.這種狀況稱爲"屬性遮蔽".

console.log(o.c); // 4
// c是o的自身屬性嗎?不是,那看看o.[[Prototype]]上有沒有.
// c是o.[[Prototype]]的自身屬性嗎?是的,該屬性的值爲4
console.log(o.d); // undefined
// d是o的自身屬性嗎?不是,那看看o.[[Prototype]]上有沒有.
// d是o.[[Prototype]]的自身屬性嗎?不是,那看看o.[[Prototype]].[[Prototype]]上有沒有.
// o.[[Prototype]].[[Prototype]]爲null,原型鏈已到頂端,沒有d屬性,返回undefined

 

繼承方法

JavaScript 並無真正的「方法」,JavaScript 只有函數,並且任何函數均可以添加到對象上做爲對象的屬性。繼承的函數與其餘的屬性是基本沒有差異的,包括「屬性遮蔽」(這種狀況至關於其餘語言的方法重寫)。prototype

當繼承的函數被調用時,this 指向的是當前繼承原型的對象,而不是繼承的函數所在的原型對象。code

var o = {
  a: 2,
  m: function(){
    return this.a + 1;
  }
};

console.log(o.m()); // 3
// 當調用 o.m 時,'this'指向了o.

var p = Object.create(o);
// p是一個對象, p.[[Prototype]]是o.

p.a = 12; // 建立p的自身屬性a.
console.log(p.m()); // 13
// 調用p.m時, 'this'指向 p. 'this.a'則是12.1

 

使用不一樣的方法來建立對象和生成原型鏈

使用普通語法建立對象

var o = {a: 1};

// o這個對象繼承了Object.prototype上面的全部屬性
// 因此能夠這樣使用 o.hasOwnProperty('a').
// hasOwnProperty 是Object.prototype的自身屬性。
// Object.prototype的原型爲null。
// 原型鏈以下:
// o ---> Object.prototype ---> null

var a = ["yo", "whadup", "?"];

// 數組都繼承於Array.prototype (indexOf, forEach等方法都是從它繼承而來).
// 原型鏈以下:
// a ---> Array.prototype ---> Object.prototype ---> null

function f(){
  return 2;
}

// 函數都繼承於Function.prototype(call, bind等方法都是從它繼承而來):
// f ---> Function.prototype ---> Object.prototype ---> null
相關文章
相關標籤/搜索