JS重點整理之JS原型鏈徹底搞清楚
物件
要清楚原型鏈,首先要弄清楚物件:
- 普通物件
- 最普通的物件:有__proto__屬性(指向其原型鏈),沒有prototype屬性。
- 原型物件(person.prototype 原型物件還有constructor屬性(指向建構函式物件))
擁有__proto__、prototype屬性(指向原型物件)。
- 函式物件:
- 凡是通過new Function()建立的都是函式物件。
Function、Object、Array、Date、String、自定義函式
特例: Function.prototype(是原型物件,卻是函式物件,下面會有解釋)
函式物件 function f1(){}; var f2 = function(){}; var f3 = function("n1","n2","return n1+n2"); console.log(typeof f1); //function console.log(typeof f2); //function console.log(typeof f3); //function console.log(typeof Object); //function console.log(typeof Array); //function console.log(typeof String); //function console.log(typeof Date); //function console.log(typeof Function); //function
Array是函式物件,是Function的例項物件,Array是通過newFunction創建出來的。因為Array是Function的例項,所以Array.__proto__ === Function.prototype
普通物件
var o1 = new f1();
var o2 = {};
var o3 = new Object();
console.log(typeof o1); //Object
console.log(typeof o2); //Object
console.log(typeof o3); //Object
原型物件
每建立一個函式都會有一個prototype屬性,這個屬性是一個指標,指向一個物件(通過該建構函式建立例項物件的原型物件)。原型物件是包含特定型別的所有例項共享的屬性和方法。原型物件的好處是,可以讓所有例項物件共享它所包含的屬性和方法。 第一塊中有提到,原型物件屬於普通物件。Function.prototype是個例外,它是原型物件,卻又是函式物件,作為一個函式物件,它又沒有prototype屬性。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屬性
解釋:
functionperson(){};
其實原型物件就是建構函式的一個例項物件。person.prototype就是person的一個例項物件。相當於在person建立的時候,自動建立了一個它的例項,並且把這個例項賦值給了prototype。
function person(){}; var temp = new person(); person.prototype = temp; function Function(){}; var temp = new Function(); Function.prototype = temp; //由new Function()產生的物件都是函式物件
從一張圖看懂原型物件、建構函式、例項物件之間的關係
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); // 小黑 來自例項
//圖中的一些關係 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)。假如另一個原型又是另一個型別的例項……這就構成了例項與原型的鏈條。
原型鏈基本思路(圖解):
舉例說明:
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();
//原型鏈關係 xiaohuang.__proto__ === dog.prototype dog.prototype.__proto__ === animal.prototype animal.prototype.__proto__ === Object.prototype Object.prototype.__proto__ === null
圖解:
詳細圖
從xiaohuang這個例項,看出整個鏈條
總結:
Xiaohuang這個Dog的例項物件繼承了Animal,Animal繼承了Object。