最近由于在找工作,又拿起《JavaScript進階程式設計》看了起來,從中也發現了自己确實還是有很多地方不懂,剛剛看到原型模式這裡,今天終于搞懂了,當然,我也不知道自己的了解是否有錯。
1、prototype
開頭第一句話說,我們每建立一個函數,就會有一個prototype屬性,這個屬性是一個指針,指向一個對象,而這個對象的用途是包含由特定類型或者執行個體共享的屬性和方法。
function fn(){};
console.log(fn.prototype);
其實
其實我們建立函數就是調用構造函數Function來實作的,其原型對象就是Object(),而這裡,fn的原型對象就是Object()。
2、constructor
在預設情況下,所有的原型對象都會獲得一個constructor屬性,這個屬性包含一個指向prototype屬性所在的函數指針。
這句話怎麼了解呢?其實很簡單,先看代碼:
function Parent(name,age){
Parent.prototype.name=name;
Parent.prototype.age=age;
Parent.prototype.arr=["123","we"];
Parent.prototype.sayHi=function(){
console.log("Hi");
};
}
console.log(Parent.prototype.constructor===Parent);//true
這裡Parent是構造函數,Parent.prototype才是原型對象。當哦們建立了自定義構造函數之後,Parent.prototype就會預設獲得constructor屬性,并且Parent.prototype.construtor=Parent,而上面的代碼也說明了這一點。
我也測試了一下其他函數,看了下結果:
var t= new Parent("huan",12);
console.log(Parent.constructor);//function Function
console.log(t.constructor);//function Parent()
那這裡又要如何解釋呢?這裡先放一個疑問,後面再來解釋。
3、__proto__
3
當采用構造函數建立一個執行個體之後,該執行個體内部都會有一個指針(_proto_)指向構造函數的原型對象。
即:它是連接配接執行個體和原型對象的,而不是執行個體和構造函數。也就是存在下面這種關系:
t.__proto__=Parent.prototype
這樣我們就可以來解答上面留下的疑問了:
函數Parent,t都是自身本身沒有construtor屬性,這屬性是從原型對象上繼承下來的。
因為t的原型對象是Parent.prototype,而Parent.prototype.construtor=Parent,是以最後輸出的就是Parent。
同理,Parent的原型對象是Function.prototype,而Function.prototype.construtor=Function,是以最後輸出的就是Function。
ba
4、總結
Parent.prototype指向了原型對象,而Parent.prototype.construtor又指回了Parent;Parent的每一個執行個體都包含一個内部屬性__proto__,該屬性指向Parent.prototype。執行個體雖然不包含方法和屬性,但卻可以通過查找獲得。
注意事項:
1、用新對象替換prototype屬性,會删除預設構造函數屬性。也就會破壞construtor屬性的值。
2、用新對象替換prototype屬性不會更新以前的執行個體。
具體可看下面的代碼
var Foo=function Foo(){};
Foo.prototype.x=1;
var foo=new Foo();
Foo.prototype={x:2,constructor:Parent};
var foo1=new Foo();
console.log(foo.x); //1
console.log(foo1.x);//2
console.log(foo1.constructor===Foo);//flase
console.log(foo.constructor===Foo);//true
console.log(foo1.constructor===Parent);//true
console.log(foo.constructor===Parent);//flase
樹林美麗、幽暗而深邃,但我有諾言尚待實作,還要奔行百裡方可沉睡。 -- 羅伯特·弗羅斯特