文档章节

Babel下的ES6兼容性与规范

ouven
 ouven
发布于 2015/12/09 11:04
字数 2977
阅读 568
收藏 0
点赞 0
评论 0

ES6标准发布后,前端人员也开发渐渐了解到了es6,但是由于兼容性的问题,仍然没有得到广泛的推广,不过业界也用了一些折中性的方案来解决兼容性和开发体系问题,但大家仍很疑惑,使用ES6会有哪些兼容性问题。

一、兼容性问题现状

  针对ES6的新特性兼容性问题,目前解决的方案是使用语法解析转换工具将es6语法转化为大部分浏览器识别的es5语法,通用的转化方案有babel,traceur,jsx,typescript,es6-shim。当然es6在服务器端也存在兼容性问题,这里由于只考虑到浏览器端的开发,暂不讨论。下面有一些常用的解决方案和兼容es6的兼容性比较~

https://github.com/babel/babel/issues/596

http://kangax.github.io/compat-table/es6/

考虑到解决方案的多样性,我么会着重考虑以下几个问题: 1,兼容性:是否能解决目前常见的所有语法兼容转换 2,易用性:能够很方便的接入到现有的开发构建体系中 3,通用性:业界有较大认可,目前没有很大问题 4,持续性:有较权威的团队维护,并能不断更新

  综合四点,我们仍然考虑使用babel作为我们的兼容性解决方案。即使以后需要更换,只需要更换更换工具就可以了,原有代码的写法可以不动。   除了后面三点,我们可能比较关注babel处理es6时的兼容性问题。因为es6里面增加了较多的内容,转换为es5没有对应语法与之对应,所以使用时要尤为注意。为此也没有很好的方法进行判断,只能对于es6里的新增内容进行编译,判断是否可以转为es5语法。

ES6新特性在Babel下的兼容性列表

ES6特性兼容性
箭头函数支持
类的声明和继承部分支持,IE8不支持
增强的对象字面量支持
字符串模板支持
解构支持,但注意使用方式
参数默认值,不定参数,拓展参数支持
let与const支持
for ofIE不支持
iterator, generator不支持
模块 module、Proxies、Symbol不支持
Map,Set 和 WeakMap,WeakSet不支持
Promises、Math,Number,String,Object 的新API不支持
export & import支持
生成器函数不支持
数组拷贝支持

在es6的新特性中,复杂结构的仍然不支持对es5转换的兼容,具体兼容性可以从下面实例来看~

1.1 箭头操作符

箭头操作符可以简洁的描述一个函数

// ES6
var fn= (v=>console.log(v));

转换后

// ES6
"use strict";

var fn = function fn(v) {
  return console.log(v);
};

该用法可以放心使用。

1.2 类的声明和继承

//类的定义
class Animal {
    //ES6中新型构造器
    constructor(name) {
        this.name = name;
    }
    //实例方法
    sayName() {
        console.log('My name is '+this.name);
    }
}
//类的继承
class Programmer extends Animal {
    constructor(name) {
        //直接调用父类构造器进行初始化
        super(name);
    }
    program() {
        console.log("I'm coding...");
    }
}
//测试我们的类
var animal=new Animal('dummy'),
wayou=new Programmer('wayou');
animal.sayName();//输出 ‘My name is dummy’
wayou.sayName();//输出 ‘My name is wayou’
wayou.program();//输出 ‘I'm coding...’

转换后


'use strict';
 
var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
 
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
 
function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
 
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
 
var Animal = (function () {
    //ES6中新型构造器
 
    function Animal(name) {
        _classCallCheck(this, Animal);
 
        this.name = name;
    }
 
    //类的继承
 
    //实例方法
 
    _createClass(Animal, [{
        key: 'sayName',
        value: function sayName() {
            console.log('My name is ' + this.name);
        }
    }]);
 
    return Animal;
})();
 
var Programmer = (function (_Animal) {
    _inherits(Programmer, _Animal);
 
    function Programmer(name) {
        _classCallCheck(this, Programmer);
 
        //直接调用父类构造器进行初始化
        _get(Object.getPrototypeOf(Programmer.prototype), 'constructor', this).call(this, name);
    }
 
    //测试我们的类
 
    _createClass(Programmer, [{
        key: 'program',
        value: function program() {
            console.log("I'm coding...");
        }
    }]);
 
    return Programmer;
})(Animal);
 
var animal = new Animal('dummy'),
    wayou = new Programmer('wayou');
animal.sayName(); //输出 ‘My name is dummy’
wayou.sayName(); //输出 ‘My name is wayou’
wayou.program(); //输出 ‘I'm coding...’

转换过程使用了Object.defineProperty,在ie8下不兼容,除此外可以任意使用

1.3 增强的对象字面量


//通过对象字面量创建对象
var human = {
    breathe() {
        console.log('breathing...');
    }
};
var worker = {
    __proto__: human, //设置此对象的原型为human,相当于继承human
    company: 'freelancer',
    work() {
        console.log('working...');
    }
};
human.breathe();//输出 ‘breathing...’
//调用继承来的breathe方法
worker.breathe();//输出 ‘breathing...’

转换后


//通过对象字面量创建对象
'use strict';
 
var human = {
    breathe: function breathe() {
        console.log('breathing...');
    }
};
var worker = {
    __proto__: human, //设置此对象的原型为human,相当于继承human
    company: 'freelancer',
    work: function work() {
        console.log('working...');
    }
};
human.breathe(); //输出 ‘breathing...’
//调用继承来的breathe方法
worker.breathe(); //输出 ‘breathing...’

这个可以任意使用

1.4 字符串模板


//产生一个随机数
var num=Math.random();
console.log(`your num is ${num}`);

转换后

//产生一个随机数
"use strict";

var num = Math.random();
console.log("your num is " + num);

1.5 解构

var [name,gender,age]=['wayou','male','secrect'];//数组解构
console.log('name:'+name+', age:'+age);//输出: name:wayou, age:secrect 

转化后

'use strict';
 
var name = 'wayou';
var gender = 'male';
var age = 'secrect';
//数组解构
console.log('name:' + name + ', age:' + age); //输出: name:wayou, age:secrect

此方法可以使用。但是尽量不要使用 var [a, b] = getVal(); 的方式,尽管getVal返回一个数组。因为此时会用到isArray,IE8上不能支持。

1.6 参数默认值,不定参数,拓展参数

  • 参数默认值
function sayHello(age, name='dude'){
    console.log(`Hello ${name}`);
}
sayHello(12);

转换后


'use strict';
 
function sayHello(age) {
    var name = arguments.length <= 1 || arguments[1] === undefined ? 'dude' : arguments[1];
 
    console.log('Hello ' + name);
}
sayHello(12);
  • 不定参数
//将所有参数相加的函数
function add(...x){
    return x.reduce((m,n)=>m+n);
}
//传递任意个数的参数
console.log(add(1,2,3));//输出:6
console.log(add(1,2,3,4,5));//输出:15

转换后

//将所有参数相加的函数
"use strict";
 
function add() {
    for (var _len = arguments.length, x = Array(_len), _key = 0; _key < _len; _key++) {
        x[_key] = arguments[_key];
    }
 
    return x.reduce(function (m, n) {
        return m + n;
    });
}
//传递任意个数的参数
console.log(add(1, 2, 3)); //输出:6
console.log(add(1, 2, 3, 4, 5)); //输出:15
  • 扩展参数
var people=['Wayou','John','Sherlock'];
//sayHello函数本来接收三个单独的参数人妖,人二和人三
function sayHello(people1,people2,people3){
    console.log(`Hello ${people1},${people2},${people3}`);
}
//但是我们将一个数组以拓展参数的形式传递,它能很好地映射到每个单独的参数
sayHello(...people);//输出:Hello Wayou,John,Sherlock
 
//而在以前,如果需要传递数组当参数,我们需要使用函数的apply方法
sayHello.apply(null,people);//输出:Hello Wayou,John,Sherlock

转换后

'use strict';
 
var people = ['Wayou', 'John', 'Sherlock'];
//sayHello函数本来接收三个单独的参数人妖,人二和人三
function sayHello(people1, people2, people3) {
    console.log('Hello ' + people1 + ',' + people2 + ',' + people3);
}
//但是我们将一个数组以拓展参数的形式传递,它能很好地映射到每个单独的参数
sayHello.apply(undefined, people); //输出:Hello Wayou,John,Sherlock
 
//而在以前,如果需要传递数组当参数,我们需要使用函数的apply方法
sayHello.apply(null, people); //输出:Hello Wayou,John,Sherlock

参数默认值,不定参数,拓展参数都可以完全使用

1.7 let与const

let和const完全支持,将都会被转为var,但是要理解let、var、const的区别。

1.8 for of

var someArray = [ "a", "b", "c" ];
 
for (v of someArray) {
    console.log(v);//输出 a,b,c
}

转换后

"use strict";
 
var someArray = ["a", "b", "c"];
 
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
 
try {
  for (var _iterator = someArray[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
    v = _step.value;
 
    console.log(v); //输出 a,b,c
  }
} catch (err) {
  _didIteratorError = true;
  _iteratorError = err;
} finally {
  try {
    if (!_iteratorNormalCompletion && _iterator["return"]) {
      _iterator["return"]();
    }
  } finally {
    if (_didIteratorError) {
      throw _iteratorError;
    }
  }
}

这里IE下面没有throw,所以无法支持

1.9 iterator, generator

var ids = {
  *[Symbol.iterator]: function () {
    var index = 0;
 
    return {
      next: function () {
        return { value: 'id-' + index++, done: false };
      }
    };
  }
};```

转换后

```javascript

'use strict';
 
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
 
var ids = _defineProperty({}, Symbol.iterator, function () {
  var index = 0;
 
  return {
    next: function next() {
      return { value: 'id-' + index++, done: false };
    }
  };
});

不建议使用,转换后仍需要浏览器支持

1.10 模块 module、Proxies、Symbol

// point.js
module "point" {
    export class Point {
        constructor (x, y) {
            public x = x;
            public y = y;
        }
    }
}

完全不支持,import也不支持,解析报错,所以建议不使用,使用原来的require

1.11 Map,Set 和 WeakMap,WeakSet

Map,Set 和 WeakMap,WeakSet在es5中都没有对应的类型与之对应,所以均不支持转换,由浏览器决定兼容性

1.12 Promises、Math,Number,String,Object 的新API

不做语法转换,由浏览器决定兼容性

1.13 export & import

export function myModule(someArg) {
  return someArg;
}```

转换后

```javascript
"use strict";
 
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.myModule = myModule;
 
function myModule(someArg) {
  return someArg;
}
import * as baz from 'myModule';

转换后

'use strict';
 
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
 
var _myModule = require('myModule');
 
var baz = _interopRequireWildcard(_myModule);

所以可以使用export和import等方法来进行模块的加载处理依赖,同时export使用到了defineProperty,IE8兼容性存在问题。

1.14 生成器函数


function* foo() { };
var bar = foo();
bar.next(); // Object {value: undefined, done: true}

转换后


"use strict";
 
var marked0$0 = [foo].map(regeneratorRuntime.mark);
function foo() {
  return regeneratorRuntime.wrap(function foo$(context$1$0) {
    while (1) switch (context$1$0.prev = context$1$0.next) {
      case 0:
      case "end":
        return context$1$0.stop();
    }
  }, marked0$0[0], this);
};
var bar = foo();
bar.next(); // Object {value: undefined, done: true}

regeneratorRuntime在IE下面不能支持,所以不建议使用。

  ES6新特性用到的就这些,其它的基本由浏览器本身决定。这部分代码Babel会像处理es5代码一样,不进行加工处理。对于部分ES6的语法,Babel会解析抛错,即使不抛错也不进行处理,建议不使用。 1.15 数组拷贝

const items = [1,2,3];
const itemsCopy = [...items];

转换后

"use strict";

var items = [1, 2, 3];
var itemsCopy = [].concat(items);

可以使用

二、ES6打包体系

  使用babel处理了一部分ES6的兼容性转换问题,但是ES6的打包依然必须依赖目前通用的打包管理方案。目前流行的打包方案有以下几种 1,webpack+babel+browsify+gulp gulp负责构建、使用webpack打包、browsify管理组件,babel转换 这目前被说的最多的解决方案,因为github上一大堆例子,而且可以很简单的支持到react,但是这样不能形成一个完整的开发体系;另外过于统一,和所在团队使用的技术差异较大。

2,fis3 + babel + Qjs + lego 选择这样的方案一方面是因为团队目前的主要技术选型,另一方面则是每个工具的特有优势。目前这块仍在不断完善当中。

三、小结

  所以使用ES6这一方案来进行实际开发是否有一定的必要性仍需要进行考虑,因为es6的高等特性在es5中没有对应的特性去代替,即使能够代替也是使用一些复杂的自定义函数去做,而部分可转换实现的特性仍然较少,而且写起来确实很简洁,这也是es6的一大优势。

  另外为了让Babel能在实际的开发中使用,我们也自己总结了一份关于ES6部分的规范:

  https://github.com/ouvens/ecmaScript-2015-babel-rules

原文出处:https://ouvens.github.io/frontend-javascript/2015/10/16/es6-under-babel.html

© 著作权归作者所有

共有 人打赏支持
ouven

ouven

粉丝 105
博文 30
码字总数 77829
作品 0
深圳
高级程序员
Nodejs下的ES6兼容性与性能分析

ES6标准发布后,前端人员也开发渐渐了解到了es6,但是由于兼容性的问题,仍然没有得到广泛的推广,不过业界也用了一些折中性的方案来解决兼容性和开发体系问题,但大家仍很疑惑,使用ES6会有...

ouven ⋅ 2015/12/09 ⋅ 13

张成文——ECMAScript 6 开发体系实践

2016年04月23日14:00時,在武汉市东湖高新技术开发区民院路38号纽宾凯鲁广国际酒店(光谷步行街地铁C出口省测绘局斜对面),舉行的规模在800人左右的2016源创会武汉站。由张成文(腾讯SNG web)分...

yunwangjun ⋅ 2016/04/24 ⋅ 1

react+webpack构建步骤

一、安装全局组件 用于转译 es6、react 到 es5,打包工程,启动 webpack-dev-server 服务 npm install babel-core babel-loader babel-preset-es2015 babel-preset-react webpack-dev-serve......

阿祥_开源中国 ⋅ 2016/10/12 ⋅ 0

nodejs下babel编译es6后异常定位助手:source-map-support

使用es6甚至es7写代码是愉快的,然而由于兼容性原因,我们不得不使用babel把es6代码转成es5的,但这样会有一个问题,那就是出现错误的时候错误栈根据编译后代码而不是es6代码中的位置,这就给...

吾爱 ⋅ 2016/04/05 ⋅ 2

WebStorm ES6 语法支持设置

ECMAScript 6是JavaScript语言的下一代标准,已经在2015年6月正式发布了。Mozilla公司将在这个标准的基础上,推出JavaScript 2.0。 ES6的目标,是使得JavaScript语言可以用来编写大型的复杂的...

hhj187 ⋅ 2016/10/10 ⋅ 0

ECMAScript 6 学习笔记(1)--编译环境搭建(VScode)

参考文档:http://es6.ruanyifeng.com/#docs/intro https://www.w3cschool.cn/ecmascript/ ECMAScript是一种定义脚本语言的规范,Javascript正是基于这种规范的一种实现。JavaScript是一种弱...

wx599c47c7bdcad ⋅ 05/18 ⋅ 0

webpack 1——核心概念的理解

引子 为什么要写这篇文章?因为今天掘金的早报有一篇关于 Webpack 的入门的文章,读完之后发现自己确实该学习一下 Webpack 了,所以有了这篇文章。 我对于 webpack 的了解仅限于在 vue-cli ...

AdityaSui ⋅ 05/17 ⋅ 0

2015-2016前端知识体系

本文作者总结了这两年前端的主流技术,对应技术博客地址:http://ouvens.github.io 一、框架与组件 bootstrap等UI框架设计与实现 伸缩布局:grid网格布局 基础UI样式:元素reset、按钮、图片...

数通畅联 ⋅ 2016/03/30 ⋅ 0

2015-2016前端知识体系

一、框架与组件 bootstrap等UI框架设计与实现 伸缩布局:grid网格布局 基础UI样式:元素reset、按钮、图片、菜单、表单 组件UI样式:按钮组、字体图标、下拉菜单、输入框组、导航组、面包屑、...

情人情人 ⋅ 2016/03/29 ⋅ 0

Kenny小狼/validator-js

Validator-js 前端的验证工具,无其他包依赖无样式,可以适合任何环境,可根据项目环境自行组装提示信息反馈给用户。 兼容IE6以上版及目前流行的浏览器。 usage: 在 和 元素上,添加 属性,然...

Kenny小狼 ⋅ 2017/09/05 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

笔试题之Java基础部分【简】【一】

基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语法,集合的语法,io 的语法,虚拟机方面的语法,其他 1.length、length()和size() length针对...

anlve ⋅ 30分钟前 ⋅ 2

table eg

user_id user_name full_name 1 zhangsan 张三 2 lisi 李四 `` ™ [========] 2018-06-18 09:42:06 星期一½ gdsgagagagdsgasgagadsgdasgagsa...

qwfys ⋅ 54分钟前 ⋅ 0

一个有趣的Java问题

先来看看源码: public class TestDemo { public static void main(String[] args) { Integer a = 10; Integer b = 20; swap(a, b); System.out......

linxyz ⋅ 59分钟前 ⋅ 0

十五周二次课

十五周二次课 17.1mysql主从介绍 17.2准备工作 17.3配置主 17.4配置从 17.5测试主从同步 17.1mysql主从介绍 MySQL主从介绍 MySQL主从又叫做Replication、AB复制。简单讲就是A和B两台机器做主...

河图再现 ⋅ 今天 ⋅ 0

docker安装snmp rrdtool环境

以Ubuntu16:04作为基础版本 docker pull ubuntu:16.04 启动一个容器 docker run -d -i -t --name flow_mete ubuntu:16.04 bash 进入容器 docker exec -it flow_mete bash cd ~ 安装基本软件 ......

messud4312 ⋅ 今天 ⋅ 0

OSChina 周一乱弹 —— 快别开心了,你还没有女友呢。

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @莱布妮子 :分享吴彤的单曲《好春光》 《好春光》- 吴彤 手机党少年们想听歌,请使劲儿戳(这里) @clouddyy :小萝莉街上乱跑,误把我认错成...

小小编辑 ⋅ 今天 ⋅ 8

Java 开发者不容错过的 12 种高效工具

Java 开发者常常都会想办法如何更快地编写 Java 代码,让编程变得更加轻松。目前,市面上涌现出越来越多的高效编程工具。所以,以下总结了一系列工具列表,其中包含了大多数开发人员已经使用...

jason_kiss ⋅ 昨天 ⋅ 0

Linux下php访问远程ms sqlserver

1、安装freetds(略,安装在/opt/local/freetds 下) 2、cd /path/to/php-5.6.36/ 进入PHP源码目录 3、cd ext/mssql进入MSSQL模块源码目录 4、/opt/php/bin/phpize生成编译配置文件 5、 . ./...

wangxuwei ⋅ 昨天 ⋅ 0

如何成为技术专家

文章来源于 -- 时间的朋友 拥有良好的心态。首先要有空杯心态,用欣赏的眼光发现并学习别人的长处,包括但不限于工具的使用,工作方法,解决问题以及规划未来的能力等。向别人学习的同时要注...

长安一梦 ⋅ 昨天 ⋅ 0

Linux vmstat命令实战详解

vmstat命令是最常见的Linux/Unix监控工具,可以展现给定时间间隔的服务器的状态值,包括服务器的CPU使用率,内存使用,虚拟内存交换情况,IO读写情况。这个命令是我查看Linux/Unix最喜爱的命令...

刘祖鹏 ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部