JS 的 Reflection and Extend

Reflection

一個物件可以列出自己有哪些成員。

利用 Reflection可以實現一個有用的模式,叫做 extend用來將一個物件的所有成員複製到另一個物件裡。

1
2
3
4
5
6
7
8
9
10
11
12
var A = {
firstname: 'Dylan',
lastname: 'Liu',
getFullName: function(){
return this.firstname + ' ' + this.lastname;
}
}

var B = {
firstname: 'Eva',
lastname: 'Lin'
}

for in可以將目標內的屬性全都遍歷、loop一輪,而現在要把 B每個 屬性 property值 value都取出來

1
2
3
4
5
B.__proto__ = A;

for (var prop in B) {
console.log(prop + ':' + B[prop])
}

B[prop]"."運算子的另一種寫法,並不是陣列。
B.fristname 也可以寫做 B['firstname'],因為這邊採用變數做歷遍的關係,因此只能使用[]運算子。( 關於這部分可以參考 SimonAllen - Day12 物件與點 )

B其實沒有getFullName這個方法,因為B的原型物件A有,for in還是順著原型鏈把其他屬性都取出來了。

我們可以用JavaScript物件內建的方法hasOwnProperty來幫助我們篩選,將for in程式碼改成這樣

hasOwnProperty可以檢查屬性,若是該物件本身的成員才會回傳 true,.__proto__內的屬則回傳 false,因此這裡的 if判斷,console.log只會印出 B本身有的屬性。


Extend

利用 Reflection 可以列出自己所有成員的方法,就可以實做 extend功能,用來合併多個物件的所有成員。
extend 在各種函式庫都有實做,所以這邊我們不自己寫而是使用 underscore.js 提供的。

使用 extend後,物件john獲得了另外兩個物件janejim的屬性與方法,並不是說john去原型鏈查找,而是利用extend函式新增了原本沒有的屬性,我們現在可以直接操作john最初沒有的屬性了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var john = {
firstname: 'John',
lastname: 'Doe'
}

var jane = {
address: '111 Main St.',
getFormalFullName: function(){
return this.lastname + ', ' + this.firstname;
}
}

var jim = {
getFirstName: function(){
return firstname;
}
}

// 要先載入 underscore.js
_.extend(john, jane, jim);

// 使用 extend 後,物件 john 就雍有另外兩個物件的所有成員了
console.log(john.address); // 顯示 111 Main St.
console.log(john.getFormalFullName()); // 顯示 Doe, John
console.log(john.getFirstName()); // 顯示 John

結語

  • extend(s) 是 JavaScript 物件導向很重要的觀念、語法,ES6已有新增內建的extends函數,另外 ES6的 extends和 underscore.js的 extend並未衝突,因為差了一個 s字母。
  • extend 可以用的話,就不需要每次都使用原型鏈了。

資料來源: