几个问题:
instanceof的工作原理?
ES6可以extend build-in类型,然而使用babel转码的ES6代码却不能extend build-in类型,为何?
在babel中,如何extend build-in class?(如Error,Array,Date等类型)
Babel转码引发的问题
vip系统的开发过程中,我们希望自定义一些Error类型,以便根据服务端的errorCode抛出不同类型的Error进行处理。
由于前端使用Babel对ES6进行转码,自然而然的,我们采用了新的class语法去继承Error:
1 |
|
构建完成后,在浏览器中运行这段代码时,却惊奇的发现输出的结果如下:
1 |
|
由于Node 8.x增加了对ES6语法的支持,不信邪的我们在当Node 8.x环境下再次运行这段代码,得到了:
1 |
|
完全符合预期!这意味着ES6应该是支持对Error对象的继承的。
为什么同样的代码,经过Babel转码后却得到了截然不同的结果呢?google后,发现因为一些bug,babel默认不允许extend buildin class:
***Extending native classes is not supported by Babel. It was removed in version 5.2.17 (see this commit)
It was removed because it was not working properly, see the bug: https://phabricator.babeljs.io/T1424
It’s unlikely it will be ever added because it’s not a feature that can be simulated. We will have to wait for native support in browsers (some already support it now in experimental mode). That also means it will currently behave differently in different browsers. ***
解决办法
解决这个问题的办法有两个:
在babel的配置文件中添加babel-plugin-transform-buildin-extend插件
手动实现一个用于extend buildIn对象的函数:
1 |
|
如果我们希望extend Error,现在可以这么做了:
1 |
|
上面的代码为什么能起作用?那么我们需要看看:
JS中实现继承的方式
我们知道,JS中没有真正的“继承”,但是它的对象,都存在原型链这一概念:
1 |
|
function Bird(name) { this.name = name; }
function Chiken() {
}
Chiken.prototype = new Bird(‘chiken’);
Chiken.prototype.fly = function() { console.log(‘cannot fly’); }
const chiken = new Chiken(‘jj’);
1 |
|
function Bird(name) { this.name = name; }
function Chiken(name) {
Bird.call(this, arguments);
}
Chiken.prototype = Object.create(Bird && Bird.prototype);
Chiken.proto = Bird;
// or
// Chiken.prototype = new Bird();
1 |
|
new Chiken() instanceof Chiken // true
new Chiken() instanceof Bird // true
1 |
|
function instance_of(L, R) {//L 表示左表达式,R 表示右表达式
var O = R.prototype;// 取 R 的显示原型
L = L.proto;// 取 L 的隐式原型
while (true) {
if (L === null)
return false;
if (O === L)// 这里重点:当 O 严格等于 L 时,返回 true
return true;
L = L.proto;
}
}
`
也就是说,instanceof判断是否存在L.__proto__.__proto__ ....._proto__ === R.prototype
的情况。一旦存在,那么它就会返回true。对于我们这里,我们就希望new Chiken().__proto__ === Chiken.prototype
同时new Chiken().__proto__.__proto__ === Bird.prototype
。
在实现继承的时候我们定义了:
Chiken.prototype = Object.create(Bird.prototype);
该函数会返回一个对象O,其中:
O = {}; O.__proto__ = Bird.prototype
看到这里,是不是恍然大悟呢?事实上,Chiken.prototype = new Bird()
也可以达到同样的效果。
参考: