談談JavaScript的原型、原型鏈、建構函式、prototype、__proto__和constructor
原型、原型鏈、建構函式是JavaScript比較難的知識點,但是它們又功能強大,是我們進行元件開發、模組開發必須掌握的技能,翻閱網上相關的博文,個人覺得這幾篇博文不錯,可以一讀:
1)湯姆大叔:強大的原型和原型鏈
2)深入理解JavaScript系列(10):JavaScript核心(晉級高手必讀篇)
3)三張圖搞懂JavaScript的原型物件與原型鏈
4)Js中Prototype、__ proto __、Constructor、Object、Function關係介紹
5)前端基礎進階(九):詳解面向物件、建構函式、原型與原型鏈
因此,本文不再大篇幅圖文介紹JavaScript物件、原型、原型鏈、建構函式等知識點,而是力求用簡單文字、程式碼輸出剖析prototype、__proto__和constructor三者間的關係。
1、prototype和__proto__
- 1)prototype是函式(function)才有的屬性;
- 2)__proto__是每個物件(object)都有的屬性,指向物件建構函式的prototype;
var a = {}; // 等同 a = new Object();
console.log(a.prototype); //普通物件沒有prototype屬性,->undefined
console.log(a.__proto__); //建構函式原型, Object.prototype, ->Object{...}
var b = function (){}
console.log(b.prototype); //b {}
console.log(b.__proto__); // = Function.prototype, ->function() {}
說明:Function.prototype = function,是特例,下文會繼續講解。
- 3)__proto__構成原型鏈,Object.prototype.__proto __= null,原型鏈結束
var a = {};
console.log(a.__proto__); //=Object.prototype, ->Object {}
console. log(a.__proto__.__proto__); //=Object.prototype.__proto__, ->null
原型鏈從繼承角度理解就是找父類,以Java為例:
1)a是一個普通物件例項,則a的父類是基類Object;
2)基類Object沒有父類,因此可以理解其父類為null。
而JavaScript用原型連結串列示這種繼承關係,用物件的__proto__屬性構成原型鏈:
1)a.__ proto __ = Object.prototype
2)a.__ proto __ . __ proto __ = Object.prototype. __ proto __ = null
- 4)__ proto __,通常指向物件建構函式的prototype,有一種情況例外Object.create方式建立的物件。
var a1 = {};
var a2 = Object.create(a1);
console.log(a2.__proto__==a1) ->true
用Object.create(a1)建立的物件,其__proto__會指向a1,因此對於a2來說,其原型鏈為:
a2.__ proto __ = a1;
a1.__ proto __ = Object.prototype;
a2.__ proto __ . __ proto __ . __ proto __ = null
2、Prototype和Constructor
在 JavaScript 中,每個函式物件都有prototype屬性,用於引用原型物件。prototype物件又有隱藏屬性constructor,它反過來引用函式本身,是一種迴圈引用。
function Animal(){
}
var anim = new Animal();
console.log(anim.constructor===Animal); //anim由Animal構造出來,->true
console.log(Animal===Animal.prototype.constructor); //prototype物件的隱藏屬性constructor反過來引用函式本身,->true
/**
* Animal = new Function()
* 因此Animal.constructor = Function,
* 而 Function = Function.prototype.constructor
* Animal.constructor = Function.prototype.constructor
*/
console.log(Animal.constructor===Function.prototype.constructor); // ->true
console.log(Function.prototype.constructor===Function); //true
3、深入理解Function、Object
JavaScript中有幾個迷惑的地方:
1)Function、Object是函式;
2)new Function仍然是函式,new Object卻是物件;
3)new (new Function) 又是物件;
var o2 =new Object();
var f3 = new Function('str','console.log(str)');
console.log('typeof Object:'+typeof Object); //function
console.log('typeof Function:'+typeof Function); //function
console.log('typeof o2:'+typeof o2); //object
console.log('typeof f3:'+typeof f3); //function
console.log('typeof new f3:'+typeof new f3()); //object
Function.prototype = function,是一個特例
console.log(typeof Function.prototype); //這是一個特例, ->function
console.log(typeof Function.__proto__); //function
console.log(typeof Function.__proto__ == Function.prototype) ->true
console.log(typeof Function.prototype.prototype); //undefined, 正常來說Function.prototype = function, function.prototype = object
console.log(typeof Function.prototype.__proto__); //object,這個要記住,後面會詳細解釋
console.log(typeof Object.prototype); //object, 好理解,Object是一個function
console.log(typeof Object.__proto__); //function, 好理解, Object = new Function,Object.__proto__ = Function.prototype
console.log(Object.prototype.prototype); //undefied, 好理解, Object.prototype = object(只有function才有prototype,所以prototype=undefiend)
console.log(Object.prototype.__proto__===null); //null, 必須記住,原型鏈結束
console.log(Function.prototype===Object.__proto__); //true,上面程式碼已經解釋
console.log(Function.__proto__===Object.__proto__); //true, 因為Function.prototype = Function.__proto__
console.log(Function.prototype.__proto__===Object.prototype); //true,有點不明白?
Function.prototype. __ proto __=Object.prototype解釋
console.log(Function instanceof Object); // true
console.log(Object instanceof Function); // true
根據instanceof原理,我們可以得出結論:
- Object.prototype(object)在Function的原型鏈上有;
Function . __ proto __ = function, != Object.prototype
因此只有Function . __ proto__ . __ proto __ = Object.prototype,
由於Function . __ proto__ = Function.prototype, 因此:
Function.prototype. __ proto __=Object.prototype - Function.prototype在Object的原型鏈上有;