1. 程式人生 > >深入解析javascript原型鏈

深入解析javascript原型鏈

首先我們要弄清楚幾個概念:

一、函式物件和普通物件

我們定義的function,其實是Function物件的一個例項,如:function a(name){this.name=name}相當於var a=new Function('name','this.name=name');

每個函式物件都prototype屬性,通過它可以實現原型繼承。

由new Object()生成的物件我們稱之為普通物件,我們非常熟悉的json變數,其實是Object的一個例項,如:var person={name:'張三'},相當於var person=new Object(),person.name='張三'。普通物件沒有prototype屬性。

二、原型物件

我們定義了一個函式後,系統會自動為其加上prototype屬性物件,可以在它上面新增屬性和方法, 例項化後可以直接呼叫。

原型物件包含:

1、constructor:指向建構函式

2、可以自定義方法和屬性。如fun.prototype.diyMethod=function(){}

3、__proto__:指向Object.prototype

var Person=function(){};
Person.prototype.say=function(){};
var onePerson=new Person();
onePerson.say();

三、原型繼承

原型的設計使得javascrip具有面向物件程式設計的能力。通過原型賦值可以輕鬆實現繼承。

var Person=function(){};
console.log(Person.toString());//A 輸出'function(){}' 
Person.prototype.say=function(){};
Person.prototype.eat=function(){};
var Man=function(){};
Man.prototype=new Person();//B
Man.prototype.constructor=Man; //執行B後Man.prototype.constructor指向Person,需要把構成函式指向自己,雖然不影響C行呼叫Man建構函式進行例項化
Man.prototype.makeMoney=function(){};
var oneMan=new Man();//C
oneMan.say();
oneMan.eat();
oneMan.makeMoney();

Man可以呼叫Person的say,eat方法,並在此基礎上擴充套件了makeMoney方法。這就是js通過原型實現繼承。

 四、原型鏈

js每個物件都有一個__proto__屬性,它指向建立例項的物件的prototype。當要方位物件的屬性時,首先判斷物件本身有沒有,有的話執行,沒有的話會到它的__proto__中找。

我們來分析下上例中的程式碼:

Person.toString():Person-->自己沒有-->Person.__proto__-->Function.prototype-->沒有-->Function.prototype.__proto__-->Object.prototype-->toString()

oneMan.say():oneMan-->自己沒有-->oneMan.__proto__-->Man.prototype-->new Person()-->自己沒有-->new Person().__proto__-->Person.prototype-->say()

oneMan.makeMoney():oneMan-->自己沒有-->oneMan.__proto__-->Man.prototype-->makeMoney()

可以看出原型都是通過__proto__來傳遞的,形成原型鏈。

下面是一張我自己畫的原型鏈的關係圖


可以看出,js中任何物件都由Object.prototype產生的。

五、Objec和Function的關係

Function.__proto__===Function.prototype true

Function.prototype.__proto__===Object.prototype true

Object.__proto__===Function.prototype true

Function instanceof Function true

Function.prototype instanceof Object true

Object instanceof Function true

可以看出Function、Function.prototype都是Object例項,Object又是Function的例項。看似有點你中有我我中有你的感覺。那到底是先有Function還是先有Object呢?

實際上幾者的關係是:

Object.prototype-->Function.prototype-->Function-->function

Object.prototype-->Function.prototype-->Object-->{}

所以Function和Object沒有先後關係,只是它們都是由Object.prototype產生,它在原型鏈的頂端,然後各自產生函式物件和普通物件

六、instanceof

用於判斷左邊是否為右邊的例項,遵循一個規則:只要左邊物件__proto__==右邊物件prototype,則返回true

如:Function.prototype.__proto__===Object.prototype 

Function instanceof Object true

Function.prototype instanceof Object true

七、不用new關鍵字實現物件例項化

理解了原型鏈後其實我們可以不用new就可以獲得例項物件,原理就是手動對__proto__賦值

var Person=function(){};
console.log(Person.toString());//A 輸出'function(){}' 
Person.prototype.say=function(){};
Person.prototype.eat=function(){};
var Man=function(){};
Man.__proto__=Person.prototype;
Man.makeMoney=function(){};
Man.say();
Man.eat();
Man.makeMoney();
不過有些瀏覽器不支援手動修改物件的__proto__屬性,為了相容性建議大家使用傳統的new方法例項化物件

講的不對的對方歡迎大家指出,如果覺得對自己有幫助記得點個贊哦^_^