0%

JavaScript 核心 (48) - 物件屬性延伸 - 屬性列舉與原型的關係

原型屬性顏色判斷

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Person() {};
Person.prototype.name = '人類';
var Cloud = new Person();
Cloud.a = undefined;
console.log(Cloud);

console.log(Cloud.hasOwnProperty('a')); /* true */
console.log(Cloud.hasOwnProperty('b')); /* false */
console.log(Cloud.hasOwnProperty('name')); /* false */

for (var key in Cloud) {
console.log(key);
/* a */
/* name */
}

使用 hasOwnProperty() 只針對當下物件是否有該屬性,但使用 for in 卻可以顯示出 name,究竟是為什麼呢?

由下圖可知,Cloud 的 aname 顏色都是相同的,而原型功能的顏色卻不一樣
屬性顏色判斷

屬性列舉影響

新增原型的屬性預設其特徵都是會全開的(configurable: true, enumerable: true, writable: true),而原型本身的功能其實是 enumerable: false 不可列舉

1
2
3
4
5
6
7
8
9
10
11
12
13
function Person() {};
Person.prototype.name = '人類';
var Cloud = new Person();
Cloud.a = undefined;

for (var key in Cloud) {
console.log(key);
/* a */
/* name */
}

console.log(Object.getOwnPropertyDescriptor(Cloud.__proto__, 'name'));
console.log(Object.getOwnPropertyDescriptor(Cloud.__proto__.__proto__, 'toString'));

enumerable 比對

列舉正確做法

由上述可知,新增原型屬性若是沒有做好特徵定義,當依照建構式新增物件後使用迴圈時,就會有問題產生。
有兩種方法可以避免問題產生:

  • 重新設定原型特徵(不推薦)
1
2
3
4
5
6
7
8
9
10
11
12
function Person() {};
Person.prototype.name = '人類';
Object.defineProperty(Person.prototype, 'name', {
enumerable: false,
});
var Cloud = new Person();
Cloud.a = undefined;

for (var key in Cloud) {
console.log(key);
/* a */
}
  • 迴圈判定(推薦)
1
2
3
4
5
6
7
8
9
10
11
function Person() {};
Person.prototype.name = '人類';
var Cloud = new Person();
Cloud.a = undefined;

for (var key in Cloud) {
if (Cloud.hasOwnProperty(key)) {
console.log(key);
/* a */
}
}

參考資料

六角學院 - JavaScript 核心篇