浏览器环境 兼容运行ES6语法

亲测可用,若有疑问请私信

ES6语言的普及

2015年6月, ES2015(即 ECMAScript 6、ES6) 正式发布。ES2015 是该语言的一个显著更新,也是自 2009年 ES5 标准确定后的第一个重大更新。伴随着ES6的普及,大量的js框架都采用了最新的语法,并且也使前端开发大量采用工程化开发方式使用es6语法。但是工程化前端开发由于其babel编译的处理,已经很好的把ES6的代码编译为ES5的版本,使得各种浏览器都能很好的兼容。

浏览器的兼容性

然而纯浏览器端使用ES6语法还是存在浏览器支持度的差异,要特殊处理才能正常运行。

桌面端浏览器对ES2015的支持情况

  • Chrome:51 版起便可以支持 97% 的 ES6 新特性。
  • Firefox:53 版起便可以支持 97% 的 ES6 新特性。
  • Safari:10 版起便可以支持 99% 的 ES6 新特性。
  • IE:Edge 15可以支持 96% 的 ES6 新特性。
  • Edge 14 可以支持 93% 的 ES6 新特性。(IE7~11 基本不支持 ES6)

详细参见:http://kangax.github.io/compat-table/es6/

可以看到IE11又拖了后腿,对ES6彻底放弃,由Edge 来支撑它的未来。

IE11下有效兼容ES6

那么如何让纯ES6脚本在IE11下运行呢,还是babel,提供了有效的解决办法
引入两个脚本:

https://cdn.bootcss.com/babel-core/5.8.35/browser.min.js
该脚本转换的是es6语法层面的语句

https://cdn.bootcss.com/babel-core/5.8.35/browser-polyfill.min.js
该脚本转换了新语法的API,比如Set Map Promise等的方法

标记脚本块的 type = "text/babel"

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>IE11 With ES6</title>
    <script src="./browser-polyfill.min.js"></script>
    <script src="./browser.min.js"></script>
    <script type="text/babel">
        const list = ['one', 'two', 'three'];
        list.forEach((item, index) => {
            alert(item + (index + 1));
        });


        let promise = new Promise(function (resolve, reject) {
            alert('Promise');
            resolve();
        });

        promise.then(function () {
            alert('resolved.');
        });


        const items = new Set([1, 2, 3, 4, 5, 5, 5, 5]);
        alert(items.size)


        const map = new Map();

        const k1 = ['a'];
        const k2 = ['a'];

        map.set(k1, 111).set(k2, 222);

        alert(map.get(k2))

    </script>
</head>

<body>

</body>

</html>

那么这里有两个困惑:

第一:<script type="text/babel"> 和我们平时用的<script type="text/javascript">有什么区别。

第二:polyfill到底干了什么

我们分别来说明下,我们来看一个未压缩的代码:https://cdn.bootcss.com/babel-core/5.8.38/browser.js
发现如下几个代码片段:

//页面加载后,执行runScripts方法
if (global.addEventListener) {
  global.addEventListener("DOMContentLoaded", runScripts, false);
} else if (global.attachEvent) {
  global.attachEvent("onload", runScripts);
}


var runScripts = function runScripts() {
  var scripts = [];
  //识别类型
  var types = ["text/ecmascript-6", "text/6to5", "text/babel", "module"];
  var index = 0;

  /**
   * Transform and execute script. Ensures correct load order.
   */

  var exec = function exec() {
    var param = scripts[index];
    if (param instanceof Array) {
      transform.run.apply(transform, param);
      index++;
      exec();
    }
  };

  /**
   * Load, transform, and execute all scripts.
   */

  var run = function run(script, i) {
    var opts = {};

    if (script.src) {
      transform.load(script.src, function (param) {
        scripts[i] = param;
        exec();
      }, opts, true);
    } else {
      opts.filename = "embedded";
      scripts[i] = [script.innerHTML, opts];
    }
  };

  // Collect scripts with Babel `types`.

  var _scripts = global.document.getElementsByTagName("script");
  //按照类别加载
  for (var i = 0; i < _scripts.length; ++i) {
    var _script = _scripts[i];
    if (types.indexOf(_script.type) >= 0) scripts.push(_script);
  }
  //执行
  for (i in scripts) {
    run(scripts[i], i);
  }

  exec();
};

我想我们关注的text/babel就在这里:var types = ["text/ecmascript-6", "text/6to5", "text/babel", "module"];

获取页面上标记为以上三项的脚步,然后用transform库进行加载和翻译成ES5进行执行。

那么polyfill又干了什么呢,继续阅读代码https://cdn.bootcss.com/babel-core/5.8.38/browser-polyfill.js
同样定位到一段代码:

$export($export.P, 'Array', {
  // 22.1.3.10 / 15.4.4.18 Array.prototype.forEach(callbackfn [, thisArg])
  forEach: $.each = $.each || methodize(createArrayMethod(0)),
  // 22.1.3.15 / 15.4.4.19 Array.prototype.map(callbackfn [, thisArg])
  map: methodize(createArrayMethod(1)),
  // 22.1.3.7 / 15.4.4.20 Array.prototype.filter(callbackfn [, thisArg])
  filter: methodize(createArrayMethod(2)),
  // 22.1.3.23 / 15.4.4.17 Array.prototype.some(callbackfn [, thisArg])
  some: methodize(createArrayMethod(3)),
  // 22.1.3.5 / 15.4.4.16 Array.prototype.every(callbackfn [, thisArg])
  every: methodize(createArrayMethod(4)),
  // 22.1.3.18 / 15.4.4.21 Array.prototype.reduce(callbackfn [, initialValue])
  reduce: createArrayReduce(false),
  // 22.1.3.19 / 15.4.4.22 Array.prototype.reduceRight(callbackfn [, initialValue])
  reduceRight: createArrayReduce(true),
  // 22.1.3.11 / 15.4.4.14 Array.prototype.indexOf(searchElement [, fromIndex])
  indexOf: methodize(arrayIndexOf),
  // 22.1.3.14 / 15.4.4.15 Array.prototype.lastIndexOf(searchElement [, fromIndex])
  lastIndexOf: function(el, fromIndex /* = @[*-1] */){
    var O      = toIObject(this)
      , length = toLength(O.length)
      , index  = length - 1;
    if(arguments.length > 1)index = Math.min(index, toInteger(fromIndex));
    if(index < 0)index = toLength(length + index);
    for(;index >= 0; index--)if(index in O)if(O[index] === el)return index;
    return -1;
  }
});


var createArrayReduce = function(isRight){
  return function(callbackfn, memo){
    aFunction(callbackfn);
    var O      = IObject(this)
      , length = toLength(O.length)
      , index  = isRight ? length - 1 : 0
      , i      = isRight ? -1 : 1;
    if(arguments.length < 2)for(;;){
      if(index in O){
        memo = O[index];
        index += i;
        break;
      }
      index += i;
      if(isRight ? index < 0 : length <= index){
        throw TypeError('Reduce of empty array with no initial value');
      }
    }
    for(;isRight ? index >= 0 : length > index; index += i)if(index in O){
      memo = callbackfn(memo, O[index], index, this);
    }
    return memo;
  };
};

可以发现ployfill给Arrary添加了很多新方法,比如createArrayReduce就是实现reduce用的。

注意

引入以上两个文件基本就解决了浏览器对ES6的大部分支持问题。

不过再次强调:即使使用了转换工具,还是不建议在生产环境大量地使用浏览器对ES6支持度较低的新特性的特性。毕竟这是在线转换后才执行的,效率比较低。而且随着浏览器对ES6的支持的变化,这些转换脚本也需要经常更新,势必对后期的维护带来影响。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值