原文地址:http://babeljs.io/docs/learn-...
本文基于Luke Hoban精妙的文章《es6features》,请把star献给他,你能够在此尝试这些特性REPL。javascript
ECMAScript 2015 是 ECMAScript 在2015年6月正式发布的一套标准。ES2015是对语言的一次富有意义的更新,也是自2009年ES5标准发布以来,对于该门语言第一次主要的更新。主流JS引擎正在逐步完善对该标准的支持。html
查看ECMAScript 2015的详尽文档java
箭头函数经过 => 语法简化函数的书写。其与C#,Java 8和CoffeeScript中相关特性有着类似的语法。同时支持表达式和语句。与函数不一样,箭头函数与上下文共享词法做用域中的thisjquery
(注:为函数指ES5中函数)git
// 表达式 var odds = evens.map(v => v + 1); var nums = evens.map((v, i) => v + i); // 语句 nums.forEach(v => { if (v % 5 === 0) fives.push(v); }); // 词法this var bob = { _name: "Bob", _friends: [], printFriends() { this._friends.forEach(f => console.log(this._name + " knows " + f)); } };
ES2015中的类是一个基于面向对象原型链模式简单的语法糖。经过简单方便的声明模式使得类模式更易用,并鼓励交互操做。同时,类支持基于原型链的继承,super调用,实例与静态方法,构造函数。es6
(注:ES5中经过原型链模式来实现其余语言中经过类实现的逻辑,这种模式能够看做一种类模式)github
class SkinnedMesh extends THREE.Mesh { constructor(geometry, materials) { super(geometry, materials); this.idMatrix = SkinnedMesh.defaultMatrix(); this.bones = []; this.boneMatrices = []; //... } update(camera) { //... super.update(); } static defaultMatrix() { return new THREE.Matrix4(); } }
在ES6中对象被增强以支持诸如:构造时的原型设定,简化foo: foo声明的写法,定义方法,进行super调用。总之,这使得对象与类的联系更加紧密,也让基于对象的设计从中获得了一样的便利。web
var obj = { // 设置原型,"__proto__" or '__proto__' 写法一样适用 __proto__: theProtoObj, // Computed property name does not set prototype or trigger early error for // 复制 __proto__ 属性 ['__proto__']: somethingElse, // ‘handler: handler’格式的简写 handler, // 方法声明 toString() { // Super 调用 return "d " + super.toString(); }, // 计算(动态的)属性名称 [ "prop_" + (() => 42)() ]: 42 };
__proto__
属性须要原生的支持(注:这里应该指的是运行环境的支持),而且在前代版本中是 不推荐 使用的。虽然大多数JS引擎现已支持该属性,但还有一些并不支持。所以,只有在web浏览器须要属性支持时才执行该属性,就像附件B中所述。在Node环境中也可使用。算法
模版字符串是在构造字符串时使用的语法糖,其与Perl,Python等语言中字符串插值特性相似。有选择性的添加标签来定制字符串结构,这样能够防止注入攻击也能基于字符串去构建更高层次的数据结构。编程
// 基本字面量的建立 `This is a pretty little template string.` // 多行字符串 `In ES5 this is not legal.` // 绑定插值变量 var name = "Bob", time = "today"; `Hello ${name}, how are you ${time}?` // 非转移的模版字符串 String.raw`In ES5 "\n" is a line-feed.` // 构造一个HTTP格式的请求前缀用来解释替换和构造 GET`http://foo.org/bar?a=${a}&b=${b} Content-Type: application/json X-Credentials: ${credentials} { "foo": ${foo}, "bar": ${bar}}`(myOnReadyStateChangeHandler);
解构容许在绑定时使用模式匹配,其支持匹配数组与对象。与标准的foo["bar"]
查询相似,解构是故障弱化的,即当没有匹配值时返回undefined
// 匹配数组 var [a, ,b] = [1,2,3]; a === 1; b === 3; // 匹配对象 var { op: a, lhs: { op: b }, rhs: c } = getASTNode() // 匹配对象简写 // 在做用域中绑定 `op`, `lhs` 与 `rhs` var {op, lhs, rhs} = getASTNode() // 做为参数使用的场景 function g({name: x}) { console.log(x); } g({name: 5}) // 故障弱化的解构 var [a] = []; a === undefined; // 有默认值状况下的故障弱化的解构 var [a = 1] = []; a === 1; // 解构与默认参数联用 function r({x, y, w = 10, h = 10}) { return x + y + w + h; } r({x:1, y:2}) === 23
设置被调用函数(callee)的默认参数值。在函数调用时,可将数组各项做为连续参数传入。在函数末尾的参数,能够绑定一个用数组传入的不定长度的参数。Rest参数取代arguments更直接地应用于常见例子中。
function f(x, y=12) { // 当没有输入或输入为undefined时y的值是12 return x + y; } f(3) == 15 function f(x, ...y) { // y是一个数组 return x * y.length; } f(3, "hello", true) == 6 function f(x, y, z) { return x + y + z; } // 将数组中的每一项做为参数传入 f(...[1,2,3]) == 6
let或const声明后在解构体中绑定 块级做用域 。let
是新版的var
,const
是单次赋值,静态化限制了在const赋值后再对变量赋值。
function f() { { let x; { // 块级做用域 const x = "sneaky"; // 报错,不能改变常量 x = "foo"; } // x已由let建立 x = "bar"; // 报错, 已经用let建立过变量x let x = "inner"; } }
迭代器对象容许像CLR IEnumerable或Java Iterable同样定义迭代器。将for..in
转换成常见的使用for..of
实现的基于迭代器的迭代。不须要实现数组,支持如LINQ式的懒惰设计模式。
let fibonacci = { [Symbol.iterator]() { let pre = 0, cur = 1; return { next() { [pre, cur] = [cur, pre + cur]; return { done: false, value: cur } } } } } for (var n of fibonacci) { // 1000处中止 if (n > 1000) break; console.log(n); }
迭代器基于鸭子模型接口(这里使用TypeScript语法仅仅为了说明问题):
interface IteratorResult { done: boolean; value: any; } interface Iterator { next(): IteratorResult; } interface Iterable { [Symbol.iterator](): Iterator }
使用 polypill 支持:为了使用迭代器属性须要引入Babel polyfill。
经过使用function 与 yield,生成器简化了迭代器的编写。当函数声明时使用function格式时返回一个生成器实例。生成器是迭代器的子类,包含了附加的next与throw。这使得值能够回流进生成器,因此yield是一个能够返回或抛出值的表达式。
值得注意的是在ES7的草案中,使用'await'一样可以达到这种异步编程的效果。
var fibonacci = { [Symbol.iterator]: function*() { var pre = 0, cur = 1; for (;;) { var temp = pre; pre = cur; cur += temp; yield cur; } } } for (var n of fibonacci) { // truncate the sequence at 1000 if (n > 1000) break; console.log(n); }
生成器接口定义(这里使用TypeScript语法仅仅为了说明问题):
interface Generator extends Iterator { next(value?: any): IteratorResult; throw(exception: any); }
使用 polypill 支持:为了使用迭代器属性须要引入Babel polyfill。
在Babel6.0中已删除
非破坏性地添加以支持更全面的unicode,这包括:字符串中新的unicode字面量格式以及处理代码断点的新正则符号u
,同时,新的API能够在21位的级别上处理字符串。依赖这些新增的支持使得JavaScript构建全球化应用成为可能。
从语言层面对组件定义模块进行支持。将主流的JavaScript模块加载方式(AMD, CommonJS)变成标准。由运行环境中的默认加载器决定模块运行时的行为。直到获取并执行完请求的模块,才执行隐式异步模型中的代码。
// lib/math.js export function sum(x, y) { return x + y; } export var pi = 3.141593; // app.js import * as math from "lib/math"; console.log("2π = " + math.sum(math.pi, math.pi)); // otherApp.js import {sum, pi} from "lib/math"; console.log("2π = " + sum(pi, pi));
一些额外的特性包括export default
与export *
:
// lib/mathplusplus.js export * from "lib/math"; export var e = 2.71828182846; export default function(x) { return Math.exp(x); } // app.js import exp, {pi, e} from "lib/mathplusplus"; console.log("e^π = " + exp(pi));
模块模式:Babel能够将ES2015 编译成多种不一样的模式,诸如Common.js,AMD,System和UMD。你甚至能够创造你本身的模式。更多细节请参考
不存在于ES2015中:因为在以前的ES2015草案中被废弃,其并未在ECMAScript2015年的规范中实现定义。不过目前这是一项正在进行的工做,而且最终的标准将会写入WHATWG's Loader规则中。
模块的加载器支持:
动态加载 Dynamic loading
状态隔离 State isolation
全局命名空间隔离 Global namespace isolation
可编译的钩子函数 Compilation hooks
嵌套虚拟化技术 Nested virtualization
默认的模块是可配置的,构建的新模块能够在孤立/受限的上下文代码进行代码的求值和引用。
// 动态加载 – ‘System’ 是默认加载器 System.import("lib/math").then(function(m) { alert("2π = " + m.sum(m.pi, m.pi)); }); // 建立一个执行沙盒即新的加载器 var loader = new Loader({ global: fixup(window) // 替代 ‘console.log’ }); loader.eval("console.log(\"hello world!\");"); // 直接操控模块的缓存 System.get("jquery"); System.set("jquery", Module({$: $})); // 警告:还未完成
须要添加polypill:因为Babel默认使用common.js规范,因此并无包含polypill的模块加载API。详情查阅。
使用模块加载器:为了使用模块加载器,须要告诉Babel使用模块模式系统。同时,确认检查System.js。
用于提升常见算法中数据结构的高效性。
WeakMap接受对象做为键名(WeakMap的设计目的在于,键名是对象的弱引用(垃圾回收机制不将该引用考虑在内),因此其所对应的对象可能会被自动回收。)
(注:红字部分原文翻译过来有点变扭,这里借用ES6入门的描述)
// Sets var s = new Set(); s.add("hello").add("goodbye").add("hello"); s.size === 2; s.has("hello") === true; // Maps var m = new Map(); m.set("hello", 42); m.set(s, 34); m.get(s) == 34; // Weak Maps var wm = new WeakMap(); wm.set(s, { extra: 42 }); wm.size === undefined // Weak Sets var ws = new WeakSet(); ws.add({ data: 42 }); // 因为添加的对象没有别的引用,所以不会被set保留
使用 polypill 支持:为了在全部环境中正常使用Map,Set,WeakMap和WeakSet须要引入Babel polyfill。
代理能够建立包括宿主对象全部可用行为的对象。其被应用于拦截,对象虚拟化,日志/描述等多个方面。
// 代理一个普通对象 var target = {}; var handler = { get: function (receiver, name) { return `Hello, ${name}!`; } }; var p = new Proxy(target, handler); p.world === "Hello, world!"; // 代理一个函数对象 var target = function () { return "I am the target"; }; var handler = { apply: function (receiver, ...args) { return "I am the proxy"; } }; var p = new Proxy(target, handler); p() === "I am the proxy";
对于全部运行级别的原操做,都有许多坑要注意:
var handler = { // target.prop get: ..., // target.prop = value set: ..., // 'prop' in target has: ..., // delete target.prop deleteProperty: ..., // target(...args) apply: ..., // new target(...args) construct: ..., // Object.getOwnPropertyDescriptor(target, 'prop') getOwnPropertyDescriptor: ..., // Object.defineProperty(target, 'prop', descriptor) defineProperty: ..., // Object.getPrototypeOf(target), Reflect.getPrototypeOf(target), // target.__proto__, object.isPrototypeOf(target), object instanceof target getPrototypeOf: ..., // Object.setPrototypeOf(target), Reflect.setPrototypeOf(target) setPrototypeOf: ..., // for (let i in target) {} enumerate: ..., // Object.keys(target) ownKeys: ..., // Object.preventExtensions(target) preventExtensions: ..., // Object.isExtensible(target) isExtensible :... }
没法支持的特性:因为ES5的局限,Proxies没法被编译或polyfilled.详见JavaScript引擎支持
符号可以实现对对象状态的控制。字符串(与ES5中一致)与符号都能做为键来访问属性。符号是一种新的原始类型。可选的名称参数能够用于调试,但并不是特性的一部分。符号是独一无二的(就像gensym生成的同样)但并不是是私有的,由于能够用诸如Object.getOwnPropertySymbols这样的方法使它暴露出来。
(function() { // 模块做用域符号 var key = Symbol("key"); function MyClass(privateData) { this[key] = privateData; } MyClass.prototype = { doStuff: function() { ... this[key] ... } }; // 在Babel中部分支持,全支持须要本地环境的实现 typeof key === "symbol" })(); var c = new MyClass("hello") c["key"] === undefined
经过polyfill实现有限支持:有限支持须要Babel polypill。因为语言的局限,一些特性没法被编译或polyfilled。查阅core.js's caveats部分得到更多细节.
在ES2015中像Array,Date和DOM元素均可以被继承来构建子类。
// 数组子类的用户代码 class MyArray extends Array { constructor(...args) { super(...args); } } var arr = new MyArray(); arr[1] = 12; arr.length == 2
许多新加入的库,包括核心数学工具库,数组转换助手与用于复制的 Object.assign。
Number.EPSILON Number.isInteger(Infinity) // false Number.isNaN("NaN") // false Math.acosh(3) // 1.762747174039086 Math.hypot(3, 4) // 5 Math.imul(Math.pow(2, 32) - 1, Math.pow(2, 32) - 2) // 2 "abcde".includes("cd") // true "abc".repeat(3) // "abcabcabc" Array.from(document.querySelectorAll("*")) // 返回一个真的数组 Array.of(1, 2, 3) // 与new Array(...)相似,但没有单一参数的特殊表现。 [0, 0, 0].fill(7, 1) // [0,7,7] [1,2,3].findIndex(x => x == 2) // 1 ["a", "b", "c"].entries() // iterator [0, "a"], [1,"b"], [2,"c"] ["a", "b", "c"].keys() // iterator 0, 1, 2 ["a", "b", "c"].values() // iterator "a", "b", "c" Object.assign(Point, { origin: new Point(0,0) })
在polypill中有限的支持:这些APIs中大多数 都能经过Babel polypill实现支持。然而,某些对特性的支持因为一些缘由被去掉了。(例如
String.prototype.normalize
须要一些额外的代码来支持)详情请参阅。
添加两种新的数字字面量格式来支持二进制(b)与十进制(o)。
0b111110111 === 503 // true 0o767 === 503 // true
仅支持字面量格式:Babel仅支持对0o767的转换但并不支持
Number("0o767")
格式。
Promises是一个异步编程库。 are a library for asynchronous programming. Promises是对那些未来可能被使用的值的第一类描述。Promises被使用在许多JavaScript库中.
function timeout(duration = 0) { return new Promise((resolve, reject) => { setTimeout(resolve, duration); }) } var p = timeout(1000).then(() => { return timeout(2000); }).then(() => { throw new Error("hmm"); }).catch(err => { return Promise.all([timeout(100), timeout(200)]); })
经过polyfill实现支持:为了实现Promises你必须引用Babel polypill。
完整的Reflect API经过对象暴露运行级别的元操做。这其实是一种反代理的API的模式,并容许调用与代理陷阱中相同的元操做。所以,在实现代理方面特别有用。
var O = {a: 1}; Object.defineProperty(O, 'b', {value: 2}); O[Symbol('c')] = 3; Reflect.ownKeys(O); // ['a', 'b', Symbol(c)] function C(a, b){ this.c = a + b; } var instance = Reflect.construct(C, [20, 22]); instance.c; // 42
经过polyfill实现支持:为了实现Reflect API你必须引用Babel polypill。
用在尾部的调用能保证棧不会无限地增加。使得递归算法在面对无限输入时更加安全。
function factorial(n, acc = 1) { "use strict"; if (n <= 1) return acc; return factorial(n - 1, n * acc); } // 棧在如今大多数实现中会溢出 // 但在ES2015中对任何输入都是安全的 factorial(100000)
在Babel 6中暂时性移除:因为其复杂性与全局支持尾调用产生的冲突,只有在明确本身指向尾部的递归方法时才能支持。因为其余一些bug被移除并将获得重新实现。