要清楚原型鏈,首先要弄清楚對象:javascript
- 普通對象
- 最普通的對象:有__proto__屬性(指向其原型鏈),沒有prototype屬性。
- 原型對象(person.prototype 原型對象還有constructor屬性(指向構造函數對象))
擁有__proto__、prototype屬性(指向原型對象)。
- 函數對象:
- 凡是經過new Function()建立的都是函數對象。
Function、Object、Array、Date、String、自定義函數java
特例: Function.prototype(是原型對象,倒是函數對象,下面會有解釋)
[javascript] view plain copyapp
Array是函數對象,是Function的實例對象,Array是經過newFunction建立出來的。由於Array是Function的實例,因此Array.__proto__ === Function.prototype函數
[javascript] view plain copythis
每建立一個函數都會有一個prototype屬性,這個屬性是一個指針,指向一個對象(經過該構造函數建立實例對象的原型對象)。原型對象是包含特定類型的全部實例共享的屬性和方法。原型對象的好處是,能夠讓全部實例對象共享它所包含的屬性和方法。spa
第一塊中有提到,原型對象屬於普通對象。Function.prototype是個例外,它是原型對象,卻又是函數對象,做爲一個函數對象,它又沒有prototype屬性。.net
[javascript] view plain copy
- function person(){};
- console.log(typeof person.prototype) //Object
- console.log(typeof Object.prototype) // Object
- console.log(typeof Function.prototype) // 特殊 Function
- console.log(typeof Function.prototype.prototype) //undefined 函數對象卻沒有prototype屬性
解釋:prototype
functionperson(){};指針
其實原型對象就是構造函數的一個實例對象。person.prototype就是person的一個實例對象。至關於在person建立的時候,自動建立了一個它的實例,而且把這個實例賦值給了prototype。對象
[javascript] view plain copy
- function person(){};
- var temp = new person();
- person.prototype = temp;
- function Function(){};
- var temp = new Function();
- Function.prototype = temp; //由new Function()產生的對象都是函數對象
從一張圖看懂原型對象、構造函數、實例對象之間的關係
[javascript] view plain copy
- function Dog(){};
- Dog.prototype.name = "小黃";
- Dog.prototype.age = 13;
- Dog.prototype.getAge = function(){
- return this.age;
- }
- var dog1 = new Dog();
- var dog2 = new Dog();
- dog2.name = "小黑";
- console.log(dog1.name); // 小黃 來自原型
- console.log(dog2.name); // 小黑 來自實例
[javascript] view plain copy
- //圖中的一些關係
- dog1.__proto__ === Dog.prototype
- Dog.prototype.__proto__ === Object.prototype //繼承Object 下面原型鏈說
- dog1.__proto__.__proto__ === Object.prototype
- Dog.prototype.constructor === Dog
- Dog.prototype.isPrototypeOf(dog1)
- 獲取對象的原型
- dog1.__proto__ //不推薦
- Object.getPrototypeOf(dog1) === Dog.prototype //推薦
原型鏈是實現繼承的主要方法。
先說一下繼承,許多OO語言都支持兩張繼承方式:接口繼承、實現繼承。
|- 接口繼承:只繼承方法簽名
|- 實現繼承:繼承實際的方法
因爲函數沒有簽名,在ECMAScript中沒法實現接口繼承,只支持實現繼承,而實現繼承主要是依靠原型鏈來實現。
原型鏈基本思路:
利用原型讓一個引用類型繼承另外一個引用類型的屬性和方法。
每一個構造函數都有一個原型對象,原型對象都包含一個指向構造函數想指針(constructor),而實例對象都包含一個指向原型對象的內部指針(__proto__)。若是讓原型對象等於另外一個類型的實例,此時的原型對象將包含一個指向另外一個原型的指針(__proto__),另外一個原型也包含着一個指向另外一個構造函數的指針(constructor)。假如另外一個原型又是另外一個類型的實例……這就構成了實例與原型的鏈條。
原型鏈基本思路(圖解):
舉例說明:
[javascript] view plain copy
- function animal(){
- this.type = "animal";
- }
- animal.prototype.getType = function(){
- return this.type;
- }
- function dog(){
- this.name = "dog";
- }
- dog.prototype = new animal();
- dog.prototype.getName = function(){
- return this.name;
- }
- var xiaohuang = new dog();
[javascript] view plain copy
- //原型鏈關係
- xiaohuang.__proto__ === dog.prototype
- dog.prototype.__proto__ === animal.prototype
- animal.prototype.__proto__ === Object.prototype
- Object.prototype.__proto__ === null
圖解:
詳細圖
從xiaohuang這個實例,看出整個鏈條
總結:
Xiaohuang這個Dog的實例對象繼承了Animal,Animal繼承了Object。