閱讀845 返回首頁    go 阿裏雲 go 技術社區[雲棲]


Js中Prototype、__proto__、Constructor、Object、Function關係介紹總結

Prototype

1 js的對象都擁有內部屬性 [[prototype]] 指向其原型對象。[[prototype]] 被稱為原型屬性。

2 內部屬性不可以直接訪問.error: obj[[prototype]],但是可以間接訪問 [[prototype]]

a ECMA:標準對象原型訪問器Object.getPrototype(object)(到目前為止隻有Firefox和chrome實現了此訪問器);

b 非標準訪問器:__proto__(除了IE)

c obj.constructor.prototype

js的一切皆是對象,所以 函數也是對象.又因為對象擁有內部屬性 [[prototype]],所以
函數也擁有內部屬性 [[prototype]].

其次:函數同時擁有屬性 prototype.prototype屬性和 [[prototype]]並非同一個屬性。

prototype屬性指向一個對象,稱為原型對象。所以:一個函數的原型屬性(function’s prototype property ) 和函數實際的原型(prototype)沒有關係

原型對象的作用:當函數fn被用作構造函數時,其所創建的所有實例的內部屬性 [[prototype]] 指向 fn 的 prototype屬性。

原型的作用:

1 構建原型鏈

當對象調用某個方法時,如果其本身不存在此方法,就會往其原型中尋找,直到原型鏈的頂端

原型鏈的作用:多個實例都需要的方法可以被抽出放到原型中,從而隻需要定義一次,實現多個對象共享方法

Constructor

JS的所有對象都擁有constructor屬性,指向其構造函數。函數的原型對象也是對象,所以原型對象也擁有constructor屬性。並且JS定下了規則:

fn.prototype.constructor == fn;

即: 函數的prototype屬性的constructor字段,指向當前prototype屬性的擁有者,也就是構造函數本身

由 fn.prototype.constructor == fn;推導出來的結論:構造函數的實例的 constructor屬性 指向其構造函數

推導:

var a = new fn();

首先在a本身尋找:沒有找到 constructor屬性.再往原型鏈向上查找,找到a的原型,也就是 fn.prototype,發現了 constructor屬性。所以就相當於 構造函數的實例的 constructor屬性始終指向其構造函數

Prototype、__proto__與Object、Function關係介紹

Function、Object:Js自帶的函數對象

prototype,每一個函數對象都有一個顯示的prototype屬性,它代表了對象的原型(Function.prototype函數對象是個例外,沒有prototype屬性)

proto:每個對象都有一個名為__proto__的內部隱藏屬性,指向於它所對應的原型對象(chrome、firefox中名稱為__proto__,並且可以被訪問到)。原型鏈正是基於__proto__才得以形成(note:不是基於函數對象的屬性prototype)。

關於上麵提到的函數對象,我們來看以下例子,來說明:

var o1 = {};
var o2 =new Object();
function f1(){}
var f2 = function(){}
var f3 = new Function('str','console.log(str)');
f3('aabb');   // aabb
console.log('typeof Object:'+typeof Object);            //function
console.log('typeof Function:'+typeof Function);        //function
console.log('typeof o1:'+typeof o1);   //object
console.log('typeof o2:'+typeof o2);   //object
console.log('typeof f1:'+typeof f1);   //function
console.log('typeof f2:'+typeof f2);   //function
console.log('typeof f3:'+typeof f3);   //function

通常我們認為o1、o2是對象,即普通對象;f1、f2、f3為函數。但是其實函數也是對象,是由Function構造的,f3這種寫法就跟對象的創建寫法一樣。f1、f2最終也都像f3一樣是有Function這個函數構造出來的
f1、f2、f3為函數對象,Function跟Object本身也是函數對象

Js中每個對象(null除外)都和另一個對象相關聯,通過以下例子跟內存效果圖來分析Function、Object、Prototype、__proto__對象間的關係

function Animal(){}
var  anim = new Animal();
console.log(typeof Animal.prototype);    //object 
console.log(anim.__proto__===Animal.prototype);    //true
console.log(Animal.__proto__===Function.prototype);    //true
console.log(Animal.prototype.__proto__===Object.prototype);    //true
console.log(typeof Function.prototype);    //function
console.log(typeof Function.__proto__);    //function
console.log(typeof Function.prototype.prototype);   //undefined
console.log(typeof Function.prototype.__proto__);     //object
console.log(Function.prototype===Function.__proto__);   //true
console.log(typeof Object.prototype);    //object
console.log(typeof Object.__proto__);    //function
console.log(Object.prototype.prototype);    //undefied
console.log(Object.prototype.__proto__===null);    //null
console.log(Function.prototype===Object.__proto__);     //true
console.log(Function.__proto__===Object.__proto__);     //true
console.log(Function.prototype.__proto__===Object.prototype);     //true
var array = new Array();
var date = new Date();
console.log(array.__proto__===Array.prototype);     //true
console.log(Array.__proto__===Function.prototype);    //true
console.log(date.__proto__===Date.prototype);      //true
console.log(Date.__proto__===Function.prototype);      //true

通過上麵代碼可以得出:

所有對象包括函數對象的原型鏈最終都指向了Object.prototype,而object.prototype.__proto__===null,原型鏈至此結束。

Animal.prototype是一個普通對象。

Object是一個函數對象,也是Function構造的,Object.prototype是一個普通對象。

Object.prototype.__type__指向null。

Function.prototype是一個函數對象,前麵說函數對象都有一個顯示的prototype屬性,但是Function.prototype卻沒有prototype屬性,即Function.prototype.prototype===undefined,所有Function.prototype函數對象是一個特例,沒有prototype屬性

Object雖是Function構造的一個函數對象,但是Object.prototype沒有指向Function.prototype,即Object.prototype!==Function.prototype

Prototype跟Constructor關係介紹

在 JavaScript 中,每個函數對象都有名為“prototype”的屬性(上麵提到過Function.prototype函數對象是個例外,沒有prototype屬性),用於引用原型對象。此原型對象又有名為“constructor”的屬性,它反過來引用函數本身。這是一種循環引用(i.e. Animal.prototype.constructor===Animal)

constructor 屬性是專門為 function 而設計的,它存在於每一個 function 的prototype 屬性中。這個 constructor 保存了指向 function 的一個引用

console.log(anim.constructor===Animal);    //true
console.log(Animal===Animal.prototype.constructor);    //true
console.log(Animal.constructor===Function.prototype.constructor);   //true
console.log(Function.prototype.constructor===Function);    //true
console.log(Function.constructor===Function.prototype.constructor);    //true
console.log(Object.prototype.constructor===Object);    //true
console.log(Object.constructor===Function);    //true

注意:Object.constructor===Function;本身Object就是Function函數構造出來的

如何查找一個對象的constructor,就是在該對象的原型鏈上尋找碰到的第一個constructor屬性所指向的對象

問題整理

  1. 為什麼 xx.constructor.prototype 可以訪問到當前對象的原型。

'str'.constructor.prototype

'str'.constructor 指向當前對象的構造函數

(構造函數).prototype:即函數的prototype 屬性

1) 函數有prototype屬性,所以可以訪問到

2) 函數的prototype屬性會在創建實例的時候作為實例的原型而存在。

所以 'str'.constructor.prototype 就可以訪問到當前對象實例的原型。

'str'.constructor == String

true.constructor == Boolean

(1).constructor == Number

{}.constructor == Object

[].constructor == Array

function(){}.constructor == Function

result:全部都是:function Function(){}

推論:內置對象的構造器,全部都是 function Function(){},包括Function本身。所以js所有的內置對象的構造器都是 function Function(){}

2.

Number.__proto__ === Function.prototype // true

Boolean.__proto__ === Function.prototype // true

String.__proto__ === Function.prototype // true

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

Function.__proto__ === Function.prototype // true

Array.__proto__ === Function.prototype // true

RegExp.__proto__ === Function.prototype // true

Error.__proto__ === Function.prototype // true

Date.__proto__ === Function.prototype // true

Function.prototype.__proto__ == Object.prototype

Object.prototype.__proto__ == Object.prototype

Number.prototype.__proto__ == Object.prototype

Boolean.prototype.__proto__ == Object.prototype

String.prototype.__proto__ == Object.prototype

Array.prototype.__proto__ == Object.prototype

RegExp.prototype.__proto__ == Object.prototype

Error.prototype.__proto__ == Object.prototype

Date.prototype.__proto__ == Object.prototype

推論:隻有函數才有 prototype屬性,所以上麵的 XXX.prototype 中的XXX都是構造函數,又有2中的 XXX.__proto__。所以:XXX既可以是內置對象,也可以是構造函數。根據情景判斷。Object的所有實例的原型都是 Object.prototype

Object.constructor == Function

Function.prototype.__proto__ == Object.prototype;

並且:Object.prototype.__proto__ == null;

最後更新:2017-06-20 15:01:46

  上一篇:go  神不知鬼不覺,阿裏程序員把地球多出的1秒“變沒”了
  下一篇:go  詳解雙11終極“核武器”:全鏈路壓測如何誕生?