资讯专栏INFORMATION COLUMN

ES6和Babel你不知道的事儿

nidaye / 2185人阅读

摘要:版本截图当然,搜狗浏览器市场份额也不低,官方最新版本是,内核版本是,为之一惊。上面代码的和分别是什么含义呢如果是下面的配置有何不可呢首先来明确一个概念是一系列的集合。比如做移动端开发不需要考虑之类的端产品线只考虑指定的浏览器等。

因babel的版本从5升级到6有很多改动,比如babel本身不再提供任何transform的工作,都需要借助插件来完成,本文的所有讨论都是建立在babel 6之上的。如果只想看结论,直接跳到文章最后。 ---写在前面

ES6即ECMAScript 6,是前端开发的JS最新规范,现在大家的开发都在使用ES6,对此并不陌生了。只是浏览器对ES6的支持并不完整,想要更好让ES6在各个平台完美运行还需一番折腾,特此一叙。下图是ES6的浏览器兼容性一览表(已ES6的Number为例):

另外国内浏览器都号称是“双核”,实际上浏览器的版本号较新,打包的Webkit内核确很低,比如市场份额很高的360安全浏览器,最新版本是9.1,Webkit内核版本才是55.0.2883,要知道Chrome官方最新版本已是62.0.3202,相差之远不甚理解。

版本截图:

userAgent:
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36 QIHU 360SE"

当然,搜狗浏览器市场份额也不低,官方最新版本是7.1,内核版本是49.0.2623,为之一惊。

版本截图:

userAgent:
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0"

因此,我们想要在所有的浏览器上平稳、完美的运行ES6代码,必须要了解它的忠实伴侣 Babel。

大家可能对此也并不陌生,但是对babel的内部机制、插件的作用、兼容的配置还缺乏一些认识,本文就是特意尝试来补全这些内容。

使用babel无非要用到.babelrc文件或者在package.json增加babel字段。我们以.babelrc文件为例:

{
  "presets":["es2015","stage-0"],
  "plugins": ["transform-runtime"]
}

这是最常见的babel配置,然后结合webpack下的babel-loader完成对JS代码的babel编译。

上面代码的presets和plugins分别是什么含义呢?如果是下面的配置有何不可呢?

{
  "presets":["es2015","stage-0"]
}

首先来明确一个概念: presets是一系列plugin的集合。比如上述配置中es2015表示babel-preset-es2015,它包含以下plugin:

check-es2015-constants

transform-es2015-arrow-functions

transform-es2015-block-scoped-functions

transform-es2015-block-scoping

transform-es2015-classes

transform-es2015-computed-properties

transform-es2015-destructuring

transform-es2015-duplicate-keys

transform-es2015-for-of

transform-es2015-function-name

transform-es2015-literals

transform-es2015-modules-commonjs

transform-es2015-object-super

transform-es2015-parameters

transform-es2015-shorthand-properties

transform-es2015-spread

transform-es2015-sticky-regex

transform-es2015-template-literals

transform-es2015-typeof-symbol

transform-es2015-unicode-regex

transform-regenerator

使用presets的好处就是不用再plugins配置里一个一个的写了。

然后,我们通过对代码的编译来看下上面两个配置的区别。源码如下:

let a=1;
let b=(item)=>{return item+1};
let c="1".padStart(2,"0");
let d=Object.assign({k:2},{t:4});
let e=new Set();

我们使用第二种配置,得到的编译结果如下:

"use strict";
var a = 1;
var b = function b(item) {
  return item + 1;
};
var c = "1".padStart(2, "0");
var d = Object.assign({ k: 2 }, { t: 4 });
var e = new Set();

从编译结果来看,let、箭头函数都被编译了,然而padStart和Object.assign原样输出了。原因很简单,let被编译是使用了es2015中的transform-es2015-block-scoping,箭头函数编译是使用了es2015的transform-es2015-arrow-functions。padStart、Object.assign和Set并未在es2015和state-0中找到对应plugin。我们再使用第一种配置编译,结果如下:

"use strict";
var _set = require("babel-runtime/core-js/set");
var _set2 = _interopRequireDefault(_set);
var _assign = require("babel-runtime/core-js/object/assign");
var _assign2 = _interopRequireDefault(_assign);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var a = 1;
var b = function b(item) {
  return item + 1;
};
var c = "1".padStart(2, "0");
var d = (0, _assign2.default)({ k: 2 }, { t: 4 });
var e = new _set2.default();

从编译结果看,let、箭头函数、Object.assign、Set都被正确编译,padStart仍岿然不动。在这友情提醒一下,babel-plugin-transform-runtime是依赖babel-runtime的。那么如何让padStart方法也能被成功编译呢,这么大的开场白终于聊到了我们今天的主题:babel的polyfill方案。

官方推荐的方式是使用babel-polyfill。

This will emulate a full ES2015+ environment and is intended to be used in an application rather than a library/tool. This polyfill is automatically loaded when using babel-node.

This means you can use new built-ins like Promise or WeakMap, static methods like Array.from or Object.assign, instance methods like Array.prototype.includes, and generator functions (provided you use the regenerator plugin). The polyfill adds to the global scope as well as native prototypes like String in order to do this.

用最简单的方式概括官方的说法就是:只要引入了babel-polyfill你可以大胆的用ES6。基本方法如下:

先安装

npm install --save babel-polyfill

后使用

// 在代码中显示调用
require("babel-polyfill");
// or
import "babel-polyfill";

或者在webpack中配置

module.exports = {
  entry: ["babel-polyfill", "./index.js"]
};

那么问题来了,既然使用这么简单,有啥弊端没?这个问题的答案也很简单:它无疑大大增加了代码的体积,即使你只有1k的代码,也会打包出几百k出来。如果不在意这个代码的体积,肆意大胆的去用吧。如果想做到代码清爽、合理的利用babel的功能还请继续阅读。

使用babel-polyfill可以不使用presets和transform-runtime,但是不意味着presets和transform-runtime没有用武之地。在此总结了几个原则:

纯业务开发

第一、先要考虑所有兼容的平台和环境,选择性的使用babel-polyfill和transform-runtime
通常情况下业务代码较重,再加上业务逻辑复杂的话,使用的ES6语法比较全面很频繁,还要考虑到各个小伙伴的代码兼容性,使用babel-polyfill结合webpack抽离出公共代码库,整体上还是能节省代码体积的。如果想全盘使用babel-polyfill并且在此基础上进行优化的话,请参考第二点。

第二、放弃使用preset-es2015、preset-state-0,请使用preset-env
babel-polyfill的引入会自动加入很多代码,有时候我们并不完全需要。比如:做移动端开发不需要考虑IE之类的、B端产品线只考虑指定的浏览器等。这个时候使用prest-env就可以了。配置如下:

{
  "presets": [
    ["env", {
      "targets": {
        "browsers": ["last 2 versions", "safari >= 7"]
      }
    }]
  ]
}

browsers的可选值参考 browserslist;有几个点要提醒一下:

上述的"last 2 versions"是主版本,这样配置会引入很多代码,建议针对性的配置。

虽然使用了preset-env会针对指定的平台进行编译代码,但是要注意,即使你的代码都是ES5,打包出来的体积也不会小,因为它不是根据你的代码来选择性的编译,而是根据平台。如果想进一步优化,如根据平台也要根据代码来选择性的polyfill,请参考 @babel/preset-env

类库和工具开发

第一、尽量避免使用babel-polyfill而使用tranform-runtime

If you are looking for something that won"t modify globals to be used in a tool/library, checkout the transform-runtime plugin. This means you won"t be able to use the instance methods mentioned above like Array.prototype.includes.

官方这句话换个角度讲就是类库的开发建议使用transform-runtime,它的原则是不改变原型链上的方法,但是通过babel-runtime或者core-js手动引入,这样不仅代码优雅编译的包体积会小很多。

第二、选择性的使用ES6语法

ES6虽然很强大,但是很多方法使用ES5仍可轻松实现。看下刚才提及的 Array.prototype.includes方法:

// ES6写法
let a=[1,2,3];
if(a.includes(1)){
  console.log("1 is finded");
}
// ES5写法
let a=[1,2,3];
if(a.some((item)=>{return item===1})){
  console.log("1 is finded");
}

这两个写法区别并不大,但是如果使用ES6的写法再加上polyfill的引入,代码要多不少。

兼容到IE8-

请老老实实使用babel-polyfill。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/90263.html

相关文章

  • babel学习笔记

    摘要:经过一番折腾,总算是把自己项目里的配置调整好了,所有文件从原来的缩小到。折腾了不少时间,改动其实就一个地方,就是配置文件,记录一下自己折腾的过程。本以为那这两种方式取其一就行了。这感觉和想象中的不一样啊,说好的一个搞定一切的呢。。。 先是看到前端早读课【第1065期】再见,babel-preset-2015,听说现在有了babel-preset-env,别的什么preset都不需要了,...

    Aomine 评论0 收藏0
  • 第一眼——ES6

    摘要:别色眯眯的不想走啦行行行,再看一眼瞧得咋地半夜看的同学,对不起不很酥胡。解决了以前那些无处安放的对象和作用域问题。要是您忘不了,之后还有的。。。 越来越多的框架推荐使用ES6进行高效开发,node也早已支持ES6,那不如就偷偷瞄一眼儿这性感的编程语言?献给初学者 Go~ ES6的一些特性 检测本地是否支持ES6环境简便方法:直接在浏览器调试工具下尝试输入Promise(ES6的新API...

    617035918 评论0 收藏0
  • 揭秘babel魔法之class魔法处理

    摘要:年,很多人已经开始接触环境,并且早已经用在了生产当中。我们发现,关键字会被编译成构造函数,于是我们便可以通过来实现实例的生成。下一篇文章我会继续介绍如何处理子类的并会通过一段函数桥梁,使得环境下也能够继承定义的。 2017年,很多人已经开始接触ES6环境,并且早已经用在了生产当中。我们知道ES6在大部分浏览器还是跑不通的,因此我们使用了伟大的Babel来进行编译。很多人可能没有关心过,...

    wqj97 评论0 收藏0
  • webpack4.0实战那些事儿

    摘要:刚刚发布,官网自称最大的特点就是零配置。本文就详细介绍一下实战那些事儿。自动刷新监听本地源代码的变化,自动重新构建刷新浏览器。自动发布更新完代码后,自动构建出线上发布代码并传输给发布系统。代码块,一个由多个模块组合而成,用于代码合并与分割。 webpack4.0刚刚发布,官网自称4.0最大的特点就是零配置。本文就详细介绍一下webpack4.0实战那些事儿。 1 什么是WebPack ...

    褰辩话 评论0 收藏0
  • 2019前端面试那些事儿

    摘要:虽然今年没有换工作的打算但为了跟上时代的脚步还是忍不住整理了一份最新前端知识点知识点汇总新特性,语义化浏览器的标准模式和怪异模式和的区别使用的好处标签废弃的标签,和一些定位写法放置位置和原因什么是渐进式渲染模板语言原理盒模型,新特性,伪 虽然今年没有换工作的打算 但为了跟上时代的脚步 还是忍不住整理了一份最新前端知识点 知识点汇总1.HTMLHTML5新特性,语义化浏览器的标准模式和怪...

    JeOam 评论0 收藏0

发表评论

0条评论

nidaye

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<