JS原型和原型鏈
1. 前言
JS中原型和原型鏈的概念一直都是混淆不清,確實需要時間,偶爾回頭看看。對於原型和原型鏈的理解,其實一直處於比較淺的概念。有句話說,沒理解透原型和原型鏈,就算還沒有真正入門的前端。希望通過總結這篇文章,我算的上入門前端了,沒入門也能偶爾翻翻看看/(ㄒoㄒ)/~~。
在理解原型之前,需要弄清楚幾個概念:函式物件、普通物件、原型物件(prototype)、__proto__屬性和構造器constructor。
2. 函式物件
顧名思義,由函式new Function()建立得來的物件都是函式物件。函式物件擁有__proto__屬性和prototype屬性。
注意:只有函式物件才有prototype屬性!
系統內建的函式物件有
Function、Object、Array、Date、String、自定義函式等
//函式物件
function f1(){};
var f2 = function(){};
console.log(typeof f1); //function
console.log(typeof f2); //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
思考: js的引用資料型別都屬於函式物件嗎?
3. 普通物件
除函式物件外的物件都是普通物件。且只有指向原型鏈的__proto__屬性,沒有prototype屬性。
//普通物件
var a = 123;
var b = {};
var c = new Object();
console.log(typeof a); //Object
console.log(typeof b); //Object
console.log(typeof c); //Object
思考:js有五種基本型別:Undefined,Null,Boolean,Number和String,他們都是屬於普通物件嗎?
4. 原型物件
JS設計之初為了實現簡單繼承,引入了prototype屬性,也叫原型物件。
//原型物件
function animal(){};
console.log(typeof animal.prototype) //Object
console.log(typeof Object.prototype) // Object
從本質上來講,原型物件是一個普通物件,是函式物件的建構函式建立的一個例項。相當於在person建立的時候,自動建立了一個它的例項,並且把這個例項賦值給了prototype。
但是存在一個特例Function, Function.prototype是原型物件,本質卻是函式物件。作為一個函式物件,又沒有prototype屬性。
console.log(typeof Function.prototype) // 特殊 Function
console.log(typeof Function.prototype.prototype) //undefined 函式物件卻沒有prototype屬性
思考:原型物件prototype 屬於函式物件嗎?
5. __proto__屬性
__proto__屬性在本質上為一個指標,指向創造obj物件的函式物件的prototype屬性。所有的物件obj都具有proto屬性(null和undefined除外)。
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和物件dog2中的__proto__屬性指向創造其例項的函式物件Dog的原型物件即Dog.prototype,如下所示:
dog1.__proto__ === Dog.prototype //true
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 //推薦
思考一下,var obj={}; obj.prototype.proto指向誰?
6.構造器constructor
constructor 屬性返回對建立此物件的函式物件的引用。
function a(){};
console.log(a.constructor===Function); //true
console.log(a.prototype.constructor===a); //true
函式a是由Function創造出來,那麼它的constructor指向的Function,a.prototype是由new a()方式創造出來,那麼a.prototype.constructor理應指向a
思考:a.prototype.proto.constructor指向誰?
7. 原型鏈
每個建構函式都有一個原型物件,原型物件都包含一個指向建構函式想指標(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
8.思考解答
函式物件思考題解答
思考: js的引用資料型別都屬於函式物件嗎?
引用型別值:指的是那些儲存在堆記憶體中的物件,意思是,變數中儲存的實際上只是一個指標,這個指標執行記憶體中的另一個位置,由該位置儲存物件
那麼陣列,普通物件,函式物件都算是引用資料型別,引用資料類型範圍包含函式物件的範圍
普通物件思考題解答
思考:js有五種基本型別:Undefined,Null,Boolean,Number和String,他們都是屬於普通物件嗎?
基本型別值:指的是儲存在棧記憶體中的簡單資料段;除開函式物件之外的物件都是普通物件,那麼普通物件範圍是包含基本資料型別的。
事實上(函式物件,普通物件)以及(基本資料型別,引用資料型別)是在不同角度對js變數進行的定義
原型物件思考題解答
思考:原型物件prototype 屬於函式物件嗎?
事實上 這個問題要進行分別回答:
Function.prototype 屬於函式物件,其他物件的prototype屬於普通物件
function a(){};
console.log(typeof Function.prototype); // function
console.log(typeof a.prototype); //object
原型物件prototype的創造過程為:
var temp = new a();
a.prototype = temp;
temp當然是普通物件,但是看下Function的prototype創造過程:
var a = new Function();
Function.prototype = a;
現在不難理解,Function的prototype為什麼是函式物件了。
指標_proto_思考題解答
思考一下,var obj={}; obj.prototype.proto指向誰?
這裡分步思考:
1、obj是是一個普通物件
2、什麼型別的物件是由prototype屬性的?當然是函式物件
3、所以obj是沒有prototype屬性的
4、所以obj.prototype===undefined
5、所以此題的最終問題是:undefined.proto指向什麼
6、所有的物件obj都具有proto屬性(null和undefined除外)!所以答案是 js報錯
構造器constructor思考題解答
思考:a.prototype.proto.constructor指向誰?
function a(){};
這裡繼續分解題目:
1、a.prototype指向a的一個例項,我們已經多次強調了,而且屬於普通物件
2、proto定義為:指向創造obj物件的函式物件的prototype屬性,所以看下誰創造了a.prototype,因為a.prototype是普通物件,型別為object,那麼是Object創造了它。
3、那麼顯而易見a.prototype.proto指向了Object.prototype
4、那麼題目簡化為Object.prototype.constructor指向誰
5、繼續分解題目,Object.prototype為基本物件,那麼就是Object創造了它,那麼它的constructor就指向了Object
Object.prototype.constructor===Object //true
繼續之,到了盡頭
Object.prototype.__proto__===null //true