在之前的文章[筆記][JavaScript]物件間基本的原型鏈(1)中有解釋過物件的繼承功能,他可以優先建立一個擁有function的物件,再提供給其他物件去繼承,並使用他的function,簡單的例子如下:
//建立一個有個function的物件
var printData = {
writeName:function(){
return 'Name is ' + this.name;
},
}
//再建立其他擁有特性name的物件並繼承自printData
var objA = Object.create(printData,{
name:{value:'A'}
});
var objB = Object.create(printData,{
name:{value:'B'}
});
//由這些物件去使用printData中的函式
objA.writeName(); //輸出 'Name is A'
objB.writeName(); //輸出 'Name is B'
上述的例子,objA和objB的原型物件都是printData,也共享了他的特性。
當然如果不使用這種方式,我們也可以利用[筆記][JavaScript]使用call()、apply()、bind()設定函式中的「this」這篇所講的,改變this來呼叫共用的函式,例如:
//建立一個有個function的物件
var printData = {
writeName:function(){
return 'Name is ' + this.name;
},
};
//個別建立兩個擁有特性name的物件
var objA = {
name:'A',
};
var objB = {
name:'B',
};
//使用call來呼叫printData.writeName()並將this指定為objA及bjB
printData.writeName.call(objA); //輸出 'Name is A'
printData.writeName.call(objB); //輸出 'Name is B'
上面兩個方式都可以做到相同的事情,接著我們試把printData轉為建構器,讓他可以建立像objA和objB那樣的物件,像這樣子經由建構器所創造出來的物件就被稱做為建構器的實體,這樣子的實體和objA與objB在概念上是一樣的,他們的資料(特性name)都是屬於實體的自有特性中,而他們的事件共享於同一個建構器的原型(printData)。
以下做個簡單的例子:
//因為建構器是由new調用的函式,所以先建立一個具名函式Write,第一個字大寫是因為之前看書說建構器的開頭通常是大寫,用來和一般函式做分別。
//這個函式擁有一個參數,他會在透過new去調用時把name這個參數傳入創造出來的實體中做為他的自有特性
function Write(name){
this.name = name;
};
//接著為該Write的原型添加事件,這些原型事件會被創造出來的實體繼承
Write.prototype.writeName = function(){
return 'Name is ' + this.name;
};
//最後我們使用new來調用Write讓他建立一個繼承了Write.prototype的實體物件,這時候A會被傳入objA裡執行this.name = 'A',也就是objA.name = 'A'
var objA = new Write('A');
//現在呼叫建構器的原型(Write.prototype)方法(writeName)
objA.writeName(); //輸出 'Name is A'
//第二個物件也可以使用建構器去創造
var objB = new Write('B');
objB.writeName(); //輸出 'Name is B'
//每個透過建構器產生出來的實體的特性constructor都會指向建構器本身
objA.constructor == Write; //回傳true
//但是constructor特性的值是可以修改的,所以也可以使用instanceof檢查物件是否為建構器的實體
objA instanceof Write //回傳true
以上就是用建構器創造實體物件的做法,如果我有觀念錯誤或解釋不清楚的地方,還麻煩各位大大指點了,謝謝大家!
因為好奇 instanceof 是如何判斷 object 是屬於哪個建構器的,
所以我去 Google 了一下,
物件在 new 的時候,會將 object.__proto__ 指向建構器的 prototype,
也就是將物件的原型鏈指向建構器的原型鏈,用來達到繼承的目的,
object 的 constructor 屬性也是由此繼承來的,constructor 其實是存在於建構器上,
而 instanceof 運算子檢測的邏輯也是判斷原型鏈,
它會檢查 object 的原型鏈上,是否存在建構器的 prototype,
也就是 objA.__proto__ === Write.prototype
下圖為我試著修改 objA.__proto__ 的結果。
所以的確如大大所說,用 instanceof 判斷物件是否為建構器的實體,比較準確。
JS 好燒腦啊!!!
哈哈,其實JavaScrupt的prototype
真的滿尷尬的,
我下一篇會提到這個部分,現在書本也還沒看到那裡,只是有稍微翻了一下