通过 babel 看 class
1. 前言
最近在写单元测试,在使用jest.spyOn
测试生命周期方法和函数时,发现箭头函数无法使用下列代码进行测试
//Error: Cannot spy the handleCardClick property because it is not a function; undefined given instead
const handleCardClick = jest.spyOn(App.prototype, "handleCardClick");
const wrapper = shallow(<App />);
报错提示说明App.prototype.handleCardClick
为undefined
,这就有意思了
2. 编译简化
通过babel tranfer online编译,发现箭头函数与普通函数处理有点不同
为了易于理解,以下编译后代码经过简化,如果对非简化部分感兴趣,建议自行编译查看
class App {
fn() {}
handleCardClick = () => {};
}
↓↓↓ 相当于 ↓↓↓
function App() {
this.handleCardClick = function () {};
}
App.prototype.fn = function () {};
可以看到,函数fn
绑定在App.prototype
上,而箭头函数handleCardClick
绑定在App
的实例上
问题解决了,但秉持着学习的心态,我把class
里大部分定义变量和函数的情况都列举了出来
class App {
v1 = "v1";
static v2 = "v2";
constructor() {
this.v1 = "fake v1";
this.v2 = "fake v2";
this.v3 = "v3";
}
fn1() {}
fn2 = () => {};
static fn3() {}
static fn4 = () => {};
}
↓↓↓ 相当于 ↓↓↓
function App() {
this.v1 = "v1";
this.v1 = "fake v1";
this.v2 = "fake v2";
this.v3 = "v3";
this.fn2 = function () {};
}
App.prototype.fn1 = function () {};
App.fn3 = function () {};
App.v2 = "v2";
App.fn4 = function () {};
有一点需要注意,constructor
在class
里定义的上下位置对编译结果无影响
class App {
v1 = "v1";
constructor() {
this.v1 = "fake v1";
}
}
class App {
constructor() {
this.v1 = "fake v1";
}
v1 = "v1";
}
上面两个类编译后结果一致
function App() {
this.v1 = "v1";
this.v1 = "fake v1";
}
总结:
- 具有 static 属性的变量和函数会直接定义在构造函数上,优先级最高
- 箭头函数在构造函数内,会定义在实例上面
- constructor 的定义会覆盖类上的定义
3. 继承
最后再研究下继承以及super
编译后的结果
class A {}
class B extends A {}
var A = function A() {};
var B = (function B(_A) {
//super相当于new关键字
var super = function () {
var Super = _B.__proto__;
var result = Super.apply(this, arguments);
if (
result &&
(_typeof(result) === "object" || typeof result === "function")
) {
return result;
}
return this;
};
function _B() {
//相当于new B(...arguments)
return super.apply(this, arguments);
}
//继承_A的prototype,并将原型指向_A
_B.prototype = {
..._A.prototype,
constructor: _B,
};
_B.__proto__ = _A;
return _B;
})(A);