繼承方面,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