Stories

Detail Return Return

__proto__,constructor,prototype - Stories Detail

__proto__(實際原型)和prototype(原型屬性)不一樣!!!
constructor屬性(原型對象中包含這個屬性,實例當中也同樣會繼承這個屬性)
prototype屬性(constructor.prototype原型對象)
__proto__屬性(實例指向原型對象的指針)

首先弄清楚幾個概念:

什麼是對象?

若干屬性的集合

什麼是原型?

原型是一個對象,其他對象可以通過它實現繼承。

哪些對象有原型?

所有的對象在默認情況下都有一個原型,因為原型本身也是對象,所以每個原型自身又有一個原型(只有一種例外,默認的對象原型在原型鏈的頂端)

任何一個對象都可以成為原型

接下來就是最核心的內容:

constructor 屬性
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屬性
注意: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上的屬性和方法

constructor屬性和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{}

Add a new Comments

Some HTML is okay.