Object.defineproperty
对象不支持此操作
如果,使用了 import
、require
加载代码, 那么 ie8 会提示:
第一反应:
- 加
Object.defineProperty
的 polyfill - 说的就是你!
core-js
因为是 bootstrap
里执行的, 所以 polyfill 得要比入口文件更早执行。
引发了异常但未捕获
或 Accessors not supported!
如果,额外并提前的引用了 core-js
, 那么会提示:
【core-js issue】IE8 and FF3.6.28 parse error for core-js/es5
Looks like you uses Object.defineProperty / Object.defineProperties / Object.create with getters / setters. In ES3 is no way to add accessors, so we generate this error.
因为 ie8 不支持、模拟不了 Object.defineProperty / Object.defineProperties / Object.create
的 getters / setters
属性, 所以 core-js
会提示上图所示错误。
但是
说是说不能在ie8里实现,这个“实现”是指较完美、完美的实现, 其实个别功能还是可以模拟的。 比如:接受参数、赋值。Object.defineProperty ie8
if (!supportsDescriptors) {
Object.defineProperty = function (a, b, c) {
//IE8支持修改元素节点的属性
if (origDefineProperty && a.nodeType == 1) {
return origDefineProperty(a, b, c);
} else {
a[b] = c.value || (c.get && c.get());
}
};
}
其实它模拟的场景很有限, 就这一句 a[b] = c.value || (c.get && c.get());
而正好就是这一句, 它把 __webpack_require__.r
场景里的需求满足了, 所以, 提前 (在core-js
前) 引用好上面那个 polyfill, 是没有问题的。
所以:
- 用 @babel/plugin-transform-modules-commonjs 换成
commonjs
加载就可以避免这个问题,但是也失去了tree shaking(推荐,都ie8了, tree个锤子tree) - 清楚了
Object.defineProperty
polyfill 的原理后, 也可以酌情使用
对象不支持“bind”属性或方法
明明引用了 core-js
, 却还提示这个错误
发现错误跟 chunk
有关, 在代码中用了 dynamic import
或者 webpack 配置了 splitChunks
后会把对应的模块单独分出 chunk
文件。
即使在入口文件的第一行引用了 core-js
, 但是这个 chunk loading
执行时机显然在入口文件之前。
所以:
core-js
要比入口文件更早执行,就是额外使用script
引用- 仅仅额外引用一个
bind
的 polyfill mdn Function.bind - 不要触发
chunk
- 滚tmd ie8(白日做梦)
无法获取未定义或 null 引用的属性“appendChild”
使用了 dynamic import
, 就会有这个问题
import(/* webpackChunkName: 'ie-polyfill'*/ './ie-polyfill')
ie8 不支持 document.head
, 用 document.getElementsByTagName('head')[0]
代替。
所以,加 加 polyfill:
if (document.head === undefined) {
document.head = document.getElementsByTagName('head')[0]
}
同样的, 这需要提前到入口文件之前
console
ie8/9 没有唤出开发者工具的时候调用 console
会提示错误的, 为了避免这种情况要增加对 console
的检验, 加段 console polyfill 就好了。
对象不支持此操作 console.log(...[arr]) => console.log.apply(console, arr)
解构赋值是 es6
推出的语法糖, 好用也常用。解构赋值会经babel
转译成.apply
应用。但是对于 ie8/9 下的console
来说, console[log|error|...].apply
都会提示 对象不支持此操作
。
console.log.apply not working in IE9-
摘要:
console 对象其实不是 ES 的标准, 它实际上是文档对象模型的扩展(像其它 DOM 对象一样)。
所以,它就不像 ES 的普通对象、函数一样继承 Object,也不会继承 Function 的方法。
IE 9 已经对大部分的 DOM 对象改进成会继承原生 ES 类型了, 但是console控制台被认为是 ie 的扩展, 所以没有进行同样的修改。
所以, 还是加 polyfill
结论
- 用
@babel/plugin-transform-modules-commonjs
避免Object.defineProperty
- 额外引用一个
bind
的 polyfill, 因为用npm装库太方便了... - 兼容
document.head
- 兼容
console
- 整理ie相关 polyfill 打包成单独的文件
ie-chore-polyfill.js
实际应用我是这样做的:webpack 设置两个文件 entry: { main: './src/index.js', 'ie-chore-polyfill': './src/ie-chore-polyfill.js' }
, 页面先引用 ie-chore-polifill
, 再 main.js
main 里包含着 core-js
实践的项目地址 pbb
整理的 ie-chore-polyfill.js
ie-chore-polyfill.js
/** * polyfill 主要以 `core-js`为主,这里辅助一些其它情况,如:帮助在 webpack 构建下运行 * - insureConsole: 兼容找不到 console 对象的情况。未打开 devtools 的时候会因为 console 报错。 因为 console 不是 ES 的标准, 要保证 console 的运行某些环境要检验以保证安全的使用 // https://www.jianshu.com/p/85a4319e3bf4 * - ie9ConsoleDeconstructionAssignment: 兼容 console 没有继承 Function 方法的情况,e.g. console.log.apply(), 常见于 babel 转换后的代码。 * - ie8ImperfectObjectDefineProperty: ie8 下简易的模拟 Object.defineProperty,可满足 __webpack_require__.r * - ie8DocumentHead: ie8 不支持 document.head * - ie9FunctionBind: ie9-、node < 0.6 不支持 Function.prototype.bind。 core-js 有, 但是懒得把 core-js 单独提前引用。。。 */