iT邦幫忙

3

[筆記][JavaScript]使用建構器創造實體物件

在之前的文章[筆記][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

以上就是用建構器創造實體物件的做法,如果我有觀念錯誤或解釋不清楚的地方,還麻煩各位大大指點了,謝謝大家!


1 則留言

0
fysh711426
iT邦研究生 4 級 ‧ 2018-03-26 13:48:35

因為好奇 instanceof 是如何判斷 object 是屬於哪個建構器的,
所以我去 Google 了一下,

物件在 new 的時候,會將 object.__proto__ 指向建構器的 prototype,
也就是將物件的原型鏈指向建構器的原型鏈,用來達到繼承的目的,
object 的 constructor 屬性也是由此繼承來的,constructor 其實是存在於建構器上,

而 instanceof 運算子檢測的邏輯也是判斷原型鏈,
它會檢查 object 的原型鏈上,是否存在建構器的 prototype,
也就是 objA.__proto__ === Write.prototype

下圖為我試著修改 objA.__proto__ 的結果。
https://ithelp.ithome.com.tw/upload/images/20180326/20106865eKldw0GG8a.jpg

所以的確如大大所說,用 instanceof 判斷物件是否為建構器的實體,比較準確。

JS 好燒腦啊!!!
/images/emoticon/emoticon46.gif

哈哈,其實JavaScrupt的prototype真的滿尷尬的,
我下一篇會提到這個部分,現在書本也還沒看到那裡,只是有稍微翻了一下/images/emoticon/emoticon37.gif

我要留言

立即登入留言