ECMAScript 之 for...in 與 class 研究

栏目: JavaScript · 发布时间: 7年前

内容简介:若ECMAScript 2015

Object.keys()for...in 的差異在於 Object.keys() 只能顯示目前 Object 的 Property Key,而 for...in 會連同 Prototype 的 Property Key 一併顯示。

for...in 搭配 Constructor Function 或 Object.create() 時一切正常,但搭配 class 時,就無法顯示 Prototype 的 Property Key 了,為什麼會這樣呢 ?

Version

ECMAScript 2015

Constructor Function

function Person(firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
}

Person.prototype.fullName = function() {
  return this.firstName + ' ' + this.lastName;
};
 
const person = new Person('Sam', 'Xiao');

for(let key in person)
  console.log(key);

// firstName
// lastName
// fullName

由 Constructor Function 建立 object,並將 method 定義在 Prototype,這是 ECMAScript OOP 標準寫法。

當對 object 使用 for...in ,會顯示所有的 Property Key,連 Prototype 也會顯示。

ECMAScript 之 for...in 與 class 研究

fullName()
for...in
fullName

Object.create

const prototype = {
  fullName: function() {
    return this.firstName + ' ' + this.lastName;
  },
};

const person = Object.create(prototype);
person.firstName = 'Sam';
person.lastName = 'Xiao';

for(let key in person)
  console.log(key);

// firstName
// lastName
// fullName

Prototype 除了事後在 Constructor Function 動態指定外,也可以事先建立 Prototype object,然後傳入 Object.create()

一樣使用 for...in ,也如預期列出 Prototype 的 Property Key。

ECMAScript 之 for...in 與 class 研究

Object.create()
for...in
fullName

Class

class Person {
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }

  fullName() {
    return this.firstName + ' ' + this.lastName;
  }
}

const person = new Person('Sam', 'Xiao');

for(let key in person)
  console.log(key);

// firstName
// lastName

ECMAScript 2015 導入 class 語法後,method 可以直接定義在 class 內,會自己幫我們定義在 Prototype。

但使用 for..in ,卻發現 Prototype 的 fullName 無法顯示,退化成與 Object.keys() 功能一樣,為什麼會這樣呢 ?

ECMAScript 之 for...in 與 class 研究

for...in
fullName

Why ?

for...inObject.keys() 都僅能列出 Enumerable Property,所以很有可能 class 的寫法,造成 Prototype 的 property 為 Non Enumerable Property,造成 for...in 無法顯示。

class Person {
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }

  fullName() {
    return this.firstName + ' ' + this.lastName;
  }
}

const person = new Person('Sam', 'Xiao');
console.log(Object.getOwnPropertyDescriptor(person, 'firstName'));
console.log(Object.getOwnPropertyDescriptor(person, 'lastName'));
console.log(Object.getOwnPropertyDescriptor(person.__proto__, 'fullName'));

for(let key in person)
  console.log(key);

Object.getOwnPropertyDescriptor() 會傳回每個 property 的屬性,藉此觀察是否為 Non Enumerable。

ECMAScript 之 for...in 與 class 研究

  1. 特別加上 Object.getOwnPropertyDescriptor() 觀察之
  2. 果然如假設所言,Prototype 的 fullNameenumerablefalse ,因此 for...in 無法顯示
'use strict';

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var Person = function () {
  function Person(firstName, lastName) {
    _classCallCheck(this, Person);

    this.firstName = firstName;
    this.lastName = lastName;
  }

  _createClass(Person, [{
    key: 'fullName',
    value: function fullName() {
      return this.firstName + ' ' + this.lastName;
    }
  }]);

  return Person;
}();

var person = new Person('Sam', 'Xiao');

for (var key in person) {
  console.log(key);
}
//# sourceMappingURL=es6class.js.map

從另外一個角度,我們由 Babel 所 transpile 的 ES5 觀察。

descriptor.enumerable = descriptor.enumerable || false;

對於 Prototype 的 property,Babel 也是將 enumerable 設定為 false

由這兩點都可以證明,當使用 class 寫法時,根據 ECMAScript 2015 規格,都會將 Prototype 的 property 設定為 Non Enumerable Property,也就是 for...in 功能將等同 Object.keys()

Conclusion

  • for...in 為 ECMAScript 3 所定義,而 Object.keys() 為 ECMAScript 5.1 所加入,理論上兩者的差異就在於 Prototype 部分,但 ECMAScript 2015 支援 class 後,又使得 for..inObject.keys() 功能趨於一至,個人是不太喜歡這種改變,這使得 for...in 與過去的觀念不同,算 breaking change,但既然 ECMAScript 2015 規格就是這樣定義,也只能自己注意這個微小的差異了

以上所述就是小编给大家介绍的《ECMAScript 之 for...in 與 class 研究》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Pragmatic Programmer

The Pragmatic Programmer

Andrew Hunt、David Thomas / Addison-Wesley Professional / 1999-10-30 / USD 49.99

本书直击编程陈地,穿过了软件开发中日益增长的规范和技术藩篱,对核心过程进行了审视――即根据需求,创建用户乐于接受的、可工作和易维护的代码。本书包含的内容从个人责任到职业发展,直至保持代码灵活和易于改编重用的架构技术。从本书中将学到防止软件变质、消除复制知识的陷阱、编写灵活、动态和易适应的代码、避免出现相同的设计、用契约、断言和异常对代码进行防护等内容。一起来看看 《The Pragmatic Programmer》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具