ES6的语法:
class People { #id = 1 // 私有字段,约定以单个的`#`字符为开头 name = 'Tom' // 公共字段 constructor(id, name, age) { this.#id = id this.name = name this.age = age // 实例属性 age } }转化为ES5:
... // 设置(修改)类的私有字段 function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = privateMap.get(receiver); if (!descriptor) { throw new TypeError("attempted to set private field on non-instance"); } if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } return value; } var People = function People(id, name, age) { _classCallCheck(this, People); _id.set(this, { writable: true, value: 1 }); _defineProperty(this, "name", 'Tom'); // constructor 从这开始执行 _classPrivateFieldSet(this, _id, id); this.name = name; this.age = age; }; var _id = new WeakMap();对比转化前后的代码可以看出:
类的构造函数(constructor)里面的代码的执行时机是在字段定义(字段映射为实例对象的属性)之后。而对私有字段的赋值(修改)是专门通过 _classPrivateFieldSet 函数来实现的。
第四组:给类添加原型方法和静态方法
ES6的语法:
class People { #id = 1 name = 'Tom' constructor(id, name, age) { this.#id = id this.name = name this.age = age } // 原型方法 getName() { return this.name } // 静态方法 static sayHello() { console.log('hello') } }转化为ES5:
... // 设置对象的属性 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); } } // 将类的方法映射到构造函数的原型(Constructor.prototype)的属性上 // 将类的静态方法映射到构造函数(Constructor)的属性上 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } var People = function () { function People(id, name, age) { // ... } // 设置类的方法和静态方法 _createClass(People, [{ key: "getName", value: function getName() { return this.name; } }], [{ key: "sayHello", value: function sayHello() { console.log('hello'); } }]); return People; }(); var _id = new WeakMap();对比一下第三组和第四组转化后的代码,可以明显发现:
类的字段通过 _defineProperty 函数映射到实例对象(this)的属性上。
类的方法则通过 _createClass 函数映射到构造函数的原型(Constructor.prototype)的属性上,
类的静态方也通过 _createClass 函数映射到构造函数(Constructor)的属性上。
第五组:类的继承
ES6的语法:
// 父类(superClass) class People {} // 子类(subClass)继承父类 class Man extends People {}转化为ES5:
... var People = function People() { _classCallCheck(this, People); }; var Man = function (_People) { // Man 继承 _People _inherits(Man, _People); // 获取 Man 的父类的构造函数 var _super = _createSuper(Man); function Man() { _classCallCheck(this, Man); // 实现了父类构造函数的调用, 子类的 this 继承父类的 this 上的属性 return _super.apply(this, arguments); } return Man; }(People);在 _inherits 函数中,实现了原型链和静态属性的继承:
// 实现继承关系 function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } // Object.create(proto, propertiesObject) 方法 // 创建一个新对象,使用 proto 来提供新创建的对象的__proto__ // 将 propertiesObject 的属性添加到新创建对象的不可枚举(默认)属性(即其自身定义的属性,而不是其原型链上的枚举属性) subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } // 设置对象 o 的原型(即 __proto__ 属性)为 p function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }通过 Object.create 函数调用可知:
(1)subClass.prototype.__proto__ === superClass.prototype ,相当于实现了原型链的继承
(2)subClass.prototype.constructor === subClass ,表明 subClass 构造函数的显示原型对象(prototype)的 constructor 属性指向原构造函数
通过调用 _setPrototypeOf(subClass, superClass)可知:
(1)subClass.__proto__ === superClass,相当于实现了静态属性的继承