写 ES6+ 一定逃不开 babel,也避不开调试 babel 生成的一些代码。
当输入一段 ES6 Class 代码时:
|
问题
在开发常用的浏览器 Chrome 和 Firefox 里正常工作,但是在 IE10 下会报错 Uncaught TypeError: Developer.speakForAll is not a function
刨根问底
.babelrc
配置如下:
|
看 babel 编译出的一串代码 blahblah, 重点下面说:
|
关键是此段实现继承的部分:
|
subClass.prototype
这一段比较简单,操作原型链来实现实例方法和属性的继承。顺带还用 object descriptor 重写了 constructor
这一属性,调用 myself.constructor
时才会拿到正确的值 Developer
,而不是 Person
。
接下来的一段比较有趣。
|
这个写法还是比较讨巧的,将父类的构造函数 superClass
作为子类构造函数 subClass
的原型。
知识回顾
Object.setPrototypeOf
这是个 ES2015 新提出的函数,函数签名:
|
对比 Object.create
,可以在对象创建出来之后替换其原型。
|
浏览器兼容性
Feature | Chrome | Edge | Firefox | IE | Opera | Safari |
---|---|---|---|---|---|---|
Basic Support | 34 | (Yes) | 31 | 11 | (Yes) | 9 |
注意到从 IE11 才开始支持此方法。
既然第一条路行不通,那就第二条呗。
__proto__
_inherits
函数中回退到 subClass.__proto__ = superClass
。__proto__
指向的是对象构造函数的 prototype
,通过重设 subClass
的原型来使其获得父类构造函数上的方法(此例中是 class 上的静态方法)。
关键在于,__proto__
是个非标准的属性,根据微软的文档,IE10 及其以下都没有支持。
Not supported in the following document modes: Quirks, Internet Explorer 6 standards, Internet Explorer 7 standards, Internet Explorer 8 standards, Internet Explorer 9 standards, Internet Explorer 10 standards. Not supported in Windows 8.
Babel 的一个 issue 中有人提过类似问题,回答是:babel 6 不考虑兼容 IE。没碰上问题算幸运,碰上问题只好自己解决。
解决方案
就这个事情来说,添加一个 polyfill 能够解决。以 这个实现 来说:
|
先探测 Object 上是否原生支持,然后检测更改 __proto__
是否有作用,最后回退到简单暴力的遍历赋值。