ES6 中的 class 有哪些特性呢?下面通过 babel 在线转换 将 class 转换成 ES5 语法,来分析 class 的特性。
class 代码:
class HelloES6 {
a = 'hello';
constructor() {
this.b = 'ES6';
}
sayToES6() {
console.log(`${this.a} ${this.b}`);
}
static sayToWorld() {
console.log('hello world');
}
}
通过 babel 在线转换 转换而成的 ES5 代码:
"use strict";
function _instanceof(left, right) {
if (
right != null &&
typeof Symbol !== "undefined" &&
right[Symbol.hasInstance]
) {
return !!right[Symbol.hasInstance](left);
} else {
return left instanceof right;
}
}
function _classCallCheck(instance, Constructor) {
if (!_instanceof(instance, Constructor)) {
throw new TypeError("Cannot call a class as a 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);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
var HelloES6 =
/*#__PURE__*/
(function() {
function HelloES6() {
_classCallCheck(this, HelloES6);
_defineProperty(this, "a", "hello");
this.b = "ES6";
}
_createClass(
HelloES6,
[
{
key: "sayToES6",
value: function sayToES6() {
console.log("".concat(this.a, " ").concat(this.b));
}
}
],
[
{
key: "sayToWorld",
value: function sayToWorld() {
console.log("hello world");
}
}
]
);
return HelloES6;
})();
分析转换而成的 ES5 代码:
- 转换而成的 ES5 代码,首先声明代码是运行在严格模式下,然后声明了 5 个函数,_instanceof、_classCallCheck、_defineProperties、_createClass、_defineProperty,最后声明了一个变量 HelloES6,这个变量的值是一个立即函数的返回值,这个返回值就是 HelloES6 类对应的构造函数,所以 HelloES6 类不存在变量提升,如果在 HelloES6 类申明之前访问 HelloES6 类,HelloES6 类的值是 undefined。
- 这个立即执行函数,首先声明了一个函数 HelloES6,这个函数就是 HelloES6 类对应的构造函数,然后执行了 _createClass 函数,最后返回函数 HelloES6,赋值给变量 HelloES6。_createClass 的作用有 2 个,第一个,根据 HelloES6 类中是否声明方法,来决定是否执行 _defineProperties 函数,第二个,根据 HelloES6 类中是否声明静态方法,来决定是否执行 _defineProperties 函数。
- _defineProperties 函数的作用有 2 个,第一个,将 HelloES6 类中声明的方法,声明到构造函数 HelloES6 的原型 prototype 对象上,第二个,将 HelloES6 类中通过 static 声明的静态方法,声明到构造函数 HelloES6 上。注意,_defineProperties 函数在构造函数 HelloES6 和构造函数 HelloES6 原型 prototype 对象上声明方法的时候,同时默认将这些方法对应数据属性中的 enumerable 特性设置为了 false,所以这些方法都是不可遍历的。
小结:通过分析转换而成的 ES5 代码可知,1、class 类采用严格模式,2、class 类就是一个构造函数,3、class 类中声明的方法,其实是声明到构造函数的原型 prototype 对象上,并且这些方法不可遍历,4、class 类中通过 static 声明的静态方法,其实是声明到构造函数上,并且这些方法不可遍历。
通过转换而成的 ES5 代码,分析 new HelloES6 类:
当 new HelloES6 类时:
- 执行 _classCallCheck 函数,_classCallCheck 函数根据 _instanceof 函数的返回结果,决定是否抛出错误。抛出这个错误的时机就是没有用 new 使用 HelloES6 类,而是把 HelloES6 类当做普通函数使用。
- 执行 _instanceof 函数,_instanceof 函数的作用是,如果 HelloES6 类是通过 new 来使用的,返回 true,如果 HelloES6 被当做普通函数使用,返回 false。
- 执行 _defineProperty 函数,_defineProperty 函数的作用是将定义在 HelloES6 类中最顶层的属性 a 声明到 HelloES6 的实例上。注意,通过 _defineProperty 函数的定义,可以看出,如果在类中最顶层声明多个同名属性,以最后一次声明为准。
- 执行 this.b = "ES6",相当于是在执行 HelloES6 类中 constructor 函数的内容。
- 结束。
小结:通过转换而成的 ES5 代码,分析 new HelloES6 类可知,1、class 类必须通过 new 来调用,否则报错,2、在 class 类中最顶层声明的属性,其实是声明到了 class 类的实例上,并且声明多个同名属性,以最后一次声明为准。
总结
- class 类采用严格模式。
- class 类就是一个构造函数。
- class 类中声明的方法,其实是声明到构造函数的原型 prototype 对象上,并且这些方法不可遍历。
- class 类中通过 static 声明的静态方法,其实是声明到构造函数上,并且这些方法不可遍历。
- class 类必须通过 new 来调用,否则报错。
- 在 class 类中最顶层声明的属性,其实是声明到了 class 类的实例上,并且声明多个同名属性,以最后一次声明为准。