可以看到,转换后的 class A 就是一个函数,所以理论上就可以把 A 当作函数调用,但 _classCallCheck 的作用就是禁止将类作为普通函数调用:
1 2 3 4 5 6 7 8 9
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
A() // throw a error const a = new A(); // work well
然后看下 _createClass 都做了什么:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
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; }; }();
上文有提到,类的继承依然是基于原型的。上文也分析过 babel 转换过的代码,常规的写法中,类的非静态属性都是定义在类的原型对象上,而不是类的实例上的。但箭头函数不一样,通过箭头函数定义的方法时绑定在 this 上,而 this 是指向当前创建的类实例对象,而不是类的原型对象。可以查看类 B 转换后的代码:
1 2 3 4 5 6 7 8
var B = function B() { _classCallCheck(this, B);
this.print = function () { console.log('print b'); }; };
可以看到,print 方法是定义在 this 上的,而不是定义在 B.prototype 上。
类 D 继承 B,不仅会继承类 B 原型上的属性和方法,也会继承其实例上的属性和方法。那么,此时类 D 等效的伪代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
function D () { // 继承自 B this.print = function () { console.log('print b'); } }