本文爲了解決如下問題:javascript
__proto__
(實際原型)和prototype
(原型屬性)不同!!!java
constructor
屬性(原型對象中包含這個屬性,實例當中也一樣會繼承這個屬性)函數
prototype
屬性(constructor.prototype
原型對象)this
__proto__
屬性(實例指向原型對象的指針)spa
首先弄清楚幾個概念:.net
若干屬性的集合prototype
原型是一個對象,其餘對象能夠經過它實現繼承。指針
全部的對象在默認狀況下都有一個原型,由於原型自己也是對象,因此每一個原型自身又有一個原型(只有一種例外,默認的對象原型在原型鏈的頂端)code
接下來就是最核心的內容:htm
constructor
屬性始終指向建立當前對象的構造函數。
var arr=[1,2,3]; console.log(arr.constructor); //輸出 function Array(){} var a={}; console.log(arr.constructor);//輸出 function Object(){} var bool=false; console.log(bool.constructor);//輸出 function Boolean(){} var name="hello"; console.log(name.constructor);//輸出 function String(){} var sayName=function(){} console.log(sayName.constrctor)// 輸出 function Function(){} //接下來經過構造函數建立instance function A(){} var a=new A(); console.log(a.constructor); //輸出 function A(){}
以上部分即解釋了任何一個對象都有constructor屬性,指向建立這個對象的構造函數
注意:prototype是每一個函數對象
都具備的屬性,被稱爲原型對象,而__proto__
屬性纔是每一個對象纔有的屬性。一旦原型對象被賦予屬性和方法,那麼由相應的構造函數建立的實例會繼承prototype
上的屬性和方法
//constructor : A //instance : a function A(){} var a=new A(); A.prototype.name="xl"; A.prototype.sayName=function(){ console.log(this.name); } console.log(a.name);// "xl" a.sayName();// "xl" //那麼由constructor建立的instance會繼承prototype上的屬性和方法
每一個函數都有prototype
屬性,而這個prototype
的constructor
屬性會指向這個函數。
function Person(name){ this.name=name; } Person.prototype.sayName=function(){ console.log(this.name); } var person=new Person("xl"); console.log(person.constructor); //輸出 function Person(){} console.log(Person.prototype.constructor);//輸出 function Person(){} console.log(Person.constructor); //輸出 function Function(){}
若是咱們重寫(從新定義)這個Person.prototype
屬性,那麼constructor
屬性的指向就會發生改變了。
Person.prototype={ sayName:function(){ console.log(this.name); } } console.log(person.constructor==Person); //輸出 false (這裏爲何會輸出false後面會講) console.log(Person.constructor==Person); //輸出 false console.log(Person.prototype.constructor);// 輸出 function Object(){} //這裏爲何會輸出function Object(){} //還記得以前說過constructor屬性始終指向建立這個對象的構造函數嗎? Person.prototype={ sayName:function(){ console.log(this.name); } } //這裏其實是對原型對象的重寫: Person.prototype=new Object(){ sayName:function(){ console.log(this.name); } } //看到了吧。如今Person.prototype.constructor屬性其實是指向Object的。 //那麼我如何能將constructor屬性再次指向Person呢? Person.prototype.constructor=Person;
接下來解釋爲何,看下面的例子
function Person(name){ this.name = name; } var personOne=new Person("xl"); Person.prototype = { sayName: function(){ console.log(this.name); } }; var personTwo = new Person('XL'); console.log(personOne.constructor == Person); //輸出true console.log(personTwo.constructor == Person); //輸出false //你們可能會對這個地方產生疑惑?爲什麼會第二個會輸出false,personTwo不也是由Person建立的嗎?這個地方應該要輸出true啊? //這裏就涉及到了JS裏面的原型繼承 //這個地方是由於person實例繼承了Person.prototype原型對象的全部的方法和屬性,包括constructor屬性。當Person.prototype的constructor發生變化的時候,相應的person實例上的constructor屬性也會發生變化。因此第二個會輸出false; //固然第一個是輸出true,由於改變構造函數的prototype屬性是在personOne被建立出來以後。
接下解釋__proto__
和prototype
屬性
一樣拿上面的代碼來解釋:
function Person(name){ this.name=name; } Person.prototype.sayName=function(){ console.log(this.name); } var person=new Person("xl"); person.sayName(); //輸出 "xl" //constructor : Person //instance : person //prototype : Person.prototype
首先給構造函數的原型對象Person.prototype
賦給sayName
方法,由構造函數Person
建立的實例person
會繼承原型對象上的sayName
方法。
由於ECMAscript的發明者爲了簡化這門語言,同時又保持繼承性,採用了鏈式繼承的方法。
由constructor
建立的每一個instance
都有個__proto__
屬性,它指向constructor.prototype
。那麼constrcutor.prototype
上定義的屬性和方法都會被instance
所繼承.
function Person(name){ this.name=name; } Person.prototype.sayName=function(){ console.log(this.name); } var personOne=new Person("a"); var personTwo=new Person("b"); personOne.sayName(); // 輸出 "a" personTwo.sayName(); //輸出 "b" console.log(personOne.__proto__==Person.prototype); // true console.log(personTwo.__proto__==Person.prototype); // true console.log(personOne.constructor==Person); //true console.log(personTwo.constructor==Person); //true console.log(Person.prototype.constructor==Person); //true console.log(Person.constructor); //function Function(){} console.log(Person.__proto__.__proto__); // Object{}
參考文章: