?一、先吃个小栗子
?
class Person {
}
使用 class 定义的 Person 类,经过 Babel转化为 ES5 生成的代码如下?
"use strict";
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
var Person = function Person() {
// 检查当前 this 实例是不是 Person 创建出来的
_classCallCheck(this, Person); // 目的:区别普通函数
};
可以看到 class 定义的 Person类,在es5 中是使用 function 来定义的,里面调用了_classCallCheck(this, person) 。这个方法的目的是:把 Person这个函数和普通函数区别开来,主要是希望通过 new 去调用,而不是随随便便调用,如下
如果当前一个普通函数调用,可以看到在严格模式下 this 是 undefined,,非严格模式下是 window,于是会判断 undefined或者 window 并不能作为 Person 的实例,因此会报错。
二、再吃个中栗子
class Person {
constructor (name, age) {
this.name = name
this.age = age
}
eating() {
console.log(this.name + ' 在吃栗子')
}
}
经过 Babel 转化并美化代码如下:这次东西比较多,不要被吓到,我们一步步来
"use strict";
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof 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;
}
var Person = /*#__PURE__*/ (function () {
function Person(name, age) {
_classCallCheck(this, Person);
this.name = name;
this.age = age;
}
_createClass(Person, [
{
key: "eating",
value: function eating() {
console.log(this.name + " 在吃栗子");
}
}
]);
return Person;
})();
?首先用了一个立即执行函数,把 function 定义的 Person 类放在立即执行函数中,最后并返回了。这里为什么要用到立即执行函数?
- 防止全局变量名冲突,这个没什么好说的,以前用立即执行函数实现模块化的道理
- 在立即执行函数上面加了一个魔法注释 /*#__PURE__*/,后面在进行代码优化压缩的时候碰到这个标记,知道这个函数是个纯函数没有产生任何可见的副作用,在进行 webpack压缩的时候会进行 tree-shaking,如果没有用到的话就会直接删掉,最后压缩的包体积就会小很多
立即执行函数里面放的是一个 function 实现的Person类,以及类中的方法_classCallCheck这个前面讲过,然后下面执行了 _createClass(Person, [{ ... }]) ,这个方法的目的又是什么呢?
在 es6以前,给类添加公共方法,是在原型上添加的?
Person.prototype.running = function () {
console.log(this.name + ' 在跑步')
}
因此 _createClass() 这个方法的作用是往Person的原型上添加方法,第一个参数是类,第二个参数接受一个数组,数组里面存放着描述方法的对象们,
_createClass(Person, [
{
key: "eating",
value: function eating() {
console.log(this.name + " 在吃栗子");
}
},
{
key: "running",
value: function running() {
console.log(this.name + " 在跑步")
}
}
]);
那为什么不直接在 Person 的原型上直接加而是搞一个方法添加,这就是提高代码的复用,真实开发中,我不可能直接Person一个类?
_createClass 方法
- 首先判断第二个参数有没有值,如果有值,把Person的原型对象 和 描述方法的对象数组传递进_defineProperties,然后调用,遍历数组取到每个属性,然后设置可枚举属性和可配置属性,判断是否有值,来设置是否可写。最后通过 Object.defineProperty 往原型上设置方法
- 其次判断有没有静态方法,有就直接把静态方法定义到Person上面
- 返回Person对象
?
|