1. 程式人生 > >JS原型和原型鏈

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