由于有些浏览器版本的发布是在 es6 定稿和发布之前的,因此对于老版本的浏览器是没有对 es6 的特性进行兼容的,针对 es6 的兼容问题,许多团队也做出了相应的开发,将 es6 的语法转换成针对浏览器可以识别的 es5 语法,充当一个翻译官的角色;比较通用的工具有:babel、jsx、traceur、es6-shim 等。
一上车就遇到的梗!!!开发中,不管你是大佬还是小菜,一定会晕倒ES6的兼容问题,因为现在ES6用的比较潮流的。下面来总结一下不同环境下有关ES6的相关兼容。
1. ES6浏览器的兼容问题
2. vue cli 解决ES6的兼容问题
3. 小程序中ES6的兼容问题
一、ES6浏览器的兼容问题
刚开始的时候一边解决问题,一边想着:用 IE8 的都是神经病,到后来,我发现完了,I LOVE IE。
移动端主要用 ES6 + Webpack + Babel 的方式,如果项目并没有使用任何框架,只引入 zepto 作为一个标准支撑库。
而 PC 端跟移动端基本保持一致,把 zepto 换成了 jQuery。
//基本的开发依赖
{
"devDependencies": {
"babel-core": "~6.3.15",
"babel-loader": "~6.2.0",
"babel-preset-es2015": "~6.3.13",
"babel-preset-stage-0": "~6.3.13",
"babel-runtime": "~6.3.13",
"extract-text-webpack-plugin": "~0.9.1",
"less-loader": "~2.2.1",
"nunjucks-loader": "~1.0.7",
"style-loader": "~0.10.2",
"webpack": "~1.12.9",
"webpack-dev-server": "^1.10.1"
}
}
Babel 默认只转换转各种 ES5 语法,而不转换新的 API,比如 Promise,以及 Object.assign、Array.from 这些新方法,这时我们需提供 ployfill 来模拟出一个提供原生支持功能的浏览器环境。
1.1、有两种方法:babel-runtime 和 babel-polyfill
babel-runtime是模拟 ES5 环境,包含各种分散的 polyfill 模块,可以在自己的模块里单独引入,比如 promise:
import 'babel-runtime/core-js/promise'
它们不会在全局环境添加未实现的方法,只是这样手动引用每个 polyfill 会非常低效,我们可以借助 Runtime transform 插件来自动化处理这一切。
//先 npm 安装:
npm install babel-plugin-transform-runtime --save-dev
//然后webpack配置babel-loader:
loader: ["babel-loader"],
query: {
plugins: [
"transform-runtime"
],
presets: ['es2015', 'stage-0']
}
babel-polyfill 是针对全局环境,引入它浏览器就好像具备了规范里定义的完整的特性,一引入,就会跑一个 babel-polyfill 实例。用法如下:
//1.安装 babel-polyfill
npm install babel-polyfill --save
//2.在入口文件中引用:
import 'babel-polyfill'
上面配置基本大部分浏览器就可以正常跑,但遇到 IE8,又是一个坑!!!结果在 IE8 上一跑一堆问题。
把 jQuery 换成 1.12.1 ,因为 2.X 已不再支持 IE8--------但是事实部署那么简单的,兼容性测试过程中会遇到的情况:
function _interopRequireDefault(obj) { return obj && obj.__esModule ?
obj : { default: obj }; }
或者
module.exports = _main2.default;
在 IE8 下会直接报”缺少标识符、字符串或数字”的错。我们可在对象的属性上加 ‘’
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : { 'default': obj };
}
module.exports = _main2['default'];
并不是 IE8 下对象的属性必须加 ‘’ ,而是 default 作为一个关键字,同样的问题还包括 catch
这两种情况,可使用 transform-es3-property-literals 和 transform-es3-member-expression-literals 这两个插件搞定。
总之,平时写代码时避免使用关键字,或者保留字作为对象的属性值,尤其是在习惯不加引号的情况下。
加粗样式
1.2、es5-shim、es5-sham
为兼容像 IE8 这样的老版本浏览器,我们引入 es5-shim 作为 polyfill。会遇到 Object.defineProperty 仍提示 “对象不支持此操作”
es5-shim 明确说明,这个方法的 polyfill 在 IE8 会失败,因为 IE8 已经有个同名的方法,但只是用于 DOM 对象。
同样的问题还包括 Object.create,上述问题可以再引入 es5-sham 解决.
1.3、addEventListener
项目中直接使用 addEventListener 这个 API,但 IE8 下事件绑定并不是这个方法。
这个问题无需去写额外的 polyfill。我们已经把 jQuery 换成 1.x,所以只需把代码中 addEventListener 换成 jQuery 写法就 Ok
1.4、无法获取未定义或 null 引用的属性
这个问题是【转人工】出现的,出现问题不是 IE8,而是 IE9 和 IE10。因为ocs 实例创建失败,因为没有调用父类的构造函数。通过安装 transform-es2015-classes 和 transform-proto-to-assign 解决。
配置项加上这两个插件的配置:
{
"plugins": [
["transform-es2015-classes", { "loose": true }],
"transform-proto-to-assign"
]
}
1.5、postMessage
虽然 postMessage 是 HTML5 的特性,但 IE8 和 Firefox3 很早就实现了这个 API,当然,跟后来的标准并不一致。这其实也不能怪 IE8。
我们可能会这样去使用:
parent.postMessage({success: 'ok', name: ‘mirreal’}, ‘*’);
但为了兼容 IE8,我们得转成字符串:
parent.postMessage(JSON.stringify({success: 'ok', name: "mirreal"}), ‘*’
另个需要注意点是:在 IE8 下 window.postMessage 是同步的。
var syncronouse = true;
window.onmessage = function () {
console.log(syncronouse); // 在 IE8 下会在控制台打印 true
};
window.postMessage('test', '*');
syncronouse = false;
1.6、IE8/IE9 的控制台
IE8 IE9 无法加载。在 IE8 浏览器的左下角,好像也是唯一会在页面提示脚本错误的浏览器,提示 script error
原因就是我们在代码中添加了一些控制信息会打印在控制台,而 IE8/IE9 要开启 IE Dev Tools 才能使用 console 对象。
切忌把 IE8/9 想成 Chrome/Firefox,以为永远有 window.console 可用.IE10就改邪归正,console 不再像段誉的六脉神剑时有时无。
console.log is there in IE8, but the console object isn’t created
until you open DevTools. Therefore, a call to console.log may result
in an error, for example if it occurs on page load before you have a
chance to open the dev tools.
只要IE8/9还在一天,console 检查还是不能少的,事实上,IE8/9 从未死去,所以就像这样:
if (window.console) {
console.log('log here');
}
要是有一堆 console.log, console.count, console.error, console.time, console.profile,… 这样去写,那还不把人写到恶心死。
写个简单的 console polyfill 吧,检测是否存在 console,不存在可以常见一个同名的空方法达到不报错的目的。当然,生产环境的代码其实也不会有那么多奇奇怪怪的 console。
17、定义文档兼容性
X-UA-Compatible 当初是针对 IE8 新加的一个配置。用于为 IE8 指定不同的页面渲染模式,比如使用 IE7 兼容模式,或者是采用最新的引擎。
现在基本也不需要前者的降级模式,更多的是写入 IE=edge 支持最新特性。而 chrome=1 则会激活 Google Chrome Frame,前提是你的 IE 安装过这个插件。
有什么用呢,当然有用,有些 API 是作为新特性存在于 IE8 中的,比如 JSON,不开启的话就用不了。
为什么要用 X-UA-Compatible?
在 IE8 刚推出的时候,很多网页由于重构的问题,无法适应较高级的浏览器,所以使用 X-UA-Compatible 强制 IE8 采用低版本方式渲染。
比如:使用下面这段代码后,开发者无需考虑网页是否兼容 IE8 浏览器,只要确保网页在 IE6、IE7 下的表现就可以了。
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
而这段代码:
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
IE=edge 告诉 IE 使用最新的引擎渲染网页,chrome=1 则可以激活 Chrome Frame[1]。
0x0a 条件注释 or 条件编译
最后说说 IE 的条件注释,用法如下:
! [if !IE] The NOT operator. This is placed immediately in front of the feature, operator, or subexpression to reverse the Boolean meaning of the expression.
lt [if lt IE 5.5] The less-than operator. Returns true if the first argument is less than the second argument.
lte [if lte IE 6] The less-than or equal operator. Returns true if the first argument is less than or equal to the second argument.
gt [if gt IE 5] The greater-than operator. Returns true if the first argument is greater than the second argument.
gte [if gte IE 7] The greater-than or equal operator. Returns true if the first argument is greater than or equal to the second argument.
( ) [if !(IE 7)] Subexpression operators. Used in conjunction with boolean operators to create more complex expressions.
& [if (gt IE 5)&(lt IE 7)] The AND operator. Returns true if all subexpressions evaluate to true
| [if (IE 6)|(IE 7)] The OR operator. Returns true if any of the subexpressions evaluates to true.
另外一个类似的东西是在 Javascript 中的条件编译(conditional compilation)。我们可以使用这段简单的代码来做浏览器嗅探:
var isIE = /*@cc_on!@*/false
在其他浏览器中,false 被视为注释,而在 IE 中,/@cc_on … @/ 之间的部分可以被 IE 识别并作为程序执行,同时启用 IE 的条件编译。
常用变量如下:
* @_win32 如果在 Win32 系统上运行,则为 true。
* @_win16 如果在 Win16 系统上运行,则为 true。
* @_mac 如果在 Apple Macintosh 系统上运行,则为 true。
* @_alpha 如果在 DEC Alpha 处理器上运行,则为 true。
* @_x86 如果在 Intel 处理器上运行,则为 true。
* @_mc680x0 如果在 Motorola 680x0 处理器上运行,则为 true。
* @_PowerPC 如果在 Motorola PowerPC 处理器上运行,则为 true。
* @_jscript 始终为 true。
* @_jscript_build 包含 JavaScript 脚本引擎的生成号。
* @_jscript_version 包含 major.minor 格式的 JavaScript 版本号。
Internet Explorer 11 之前的所有版本的 Internet Explorer 都支持条件编译。从 Internet Explorer 11 标准模式开始,Windows 8.x 应用商店应用不支持条件编译。
。。。。
有两种方法:babel-runtime 和 babel-polyfill
//npm安装:
npm install babel-plugin-transform-runtime --save-dev
//webpack 配置文件的 babel-loader 增加选项:
loader: ["babel-loader"],
query: {
plugins: [
"transform-runtime"
],
presets: ['es2015', 'stage-0']
}
babel-polyfill 是针对全局环境的,引入它浏览器会具备规范里定义的完整的特性,一旦引入,就会运行一个 babel-polyfill 实例
//npm安装
npm install babel-polyfill --save
//在入口文件中引用:
import 'babel-polyfill'
会遇到这样的问题:vue-cli创建的项目,run 正常,build报错:Unexpected token name «i», expected punc «;»
这是在 babel 转换的时候发生的问题
// 在package.json文件里修改
"devDependencies": {
"uglify-js": "git://github.com/mishoo/UglifyJS2#harmony-v2.8.22",
"uglifyjs-webpack-plugin": "0.4.3",
//在webpack.config.js里面使用
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
new UglifyJSPlugin()
以替换webpack自带的UglifyJsPlugin插件可以解决问题。
。。。。https://blog.csdn.net/webKris/article/details/83625673
三、小程序中ES6的兼容问题
1.1、记得勾选上微信开发工具的ES6转ES5的功能
1.2、引入第三方库Bluebird .js或者Runtime.js
。。。。