内容译自 es6-features,在介绍 ES6 新特性的同时,列举了与 ES5 的语法差异,原文很多词语都属于专业术语,避免误导,保留原文相关内容。
常量(Constants)
const
声明会阻止对于变量绑定与变量自身值的修改,这意味着 const
声明并不会阻止对成员的修改。
ECMAScript 6:
const PI| = 3.141593;
PI > 3.0;
ECMAScript 5:
// only in ES5 through the help of object properties
// and only in global context and not in a block scope
Object.|defineProperty|(typeof global === "object" ? global : window, "|PI|", {
value: 3.141593,
enumerable: true,
|writable: false|,
|configurable: false|
})
PI > 3.0
作用域(Scoping)
块级变量(Block-Scoped Variables)
let
声明会将作用域限制在当前代码块中,let
声明和 const
声明不进行提升。
ECMAScript 6:
for (let i = 0; i < a.length; i++) {
let x = a[i];
...
}
for (let i = 0; i < b.length; i++) {
let y = b[i];
...
}
let callbacks = [];
for (|let| i = 0; i <= 2; i++) {
callbacks[i] = function () { return i * 2; };
}
callbacks[0]() === 0;
callbacks[1]() === 2;
callbacks[2]() === 4;
ECMAScript 5:
var i, x, y
for (i = 0; i < a.length; i++) {
x = a[i]
…
}
for (i = 0; i < b.length; i++) {
y = b[i]
…
}
var callbacks = []
for (var i = 0; i <= 2; i++) {
(function (i) {
callbacks[i] = function() { return i * 2 }
})(i);
}
callbacks[0]() === 0
callbacks[1]() === 2
callbacks[2]() === 4
块级函数
块级作用域的函数定义。
ESMAScript 6:
{
function foo () { return 1; }
foo() === 1;
{
function foo () { return 2; }
foo() === 2;
}
foo() === 1;
}
ESMAScript 5:
// only in ES5 with the help of block-scope emulating
// function scopes and function expressions
(function () {
var foo = function () { return 1 }
foo() === 1
(function () {
var foo = function () { return 2 }
foo() === 2
})();
foo() === 1
})()
箭头函数(Arrow Functions)
表达式(Expression Bodies)
更具表现力的闭包语法。
ECMAScript 6 语法:
odds = evens.map(v => v + 1);
pairs = evens.map(v => ({ even: v, odd: v + 1 }));
nums = evens.map((v, i) => v + i);
ECMAScript 5 语法:
odds = evens.map(function (v) { return v + 1 })
pairs = evens.map(function (v) { return { even: v, odd: v + 1 } })
nums = evens.map(function (v, i) { return v + i })
变体
函数只有单个参数时,可以直接书写,不需要额外的语法。
ECMAScript 6 语法:
nums.forEach(v => {
if (v % 5 === 0)
fives.push(v);
})
ECMAScript 5 语法:
nums.forEach(function (v) {
if (v % 5 === 0)
fives.push(v)
})
词法 this
更直观地处理当前对象上下文。
ECMAScript 6 语法:
this.nums.forEach((v) => {
if (v % 5 === 0)
this.fives.push(v);
});
ECMAScript 5 语法:
// variant 1
var self = this
this.nums.forEach(function (v) {
if (v % 5 === 0)
self.fives.push(v)
})
// variant 2
this.nums.forEach(function (v) {
if (v % 5 === 0)
this.fives.push(v)
}, this)
参数处理扩展
默认参数
简单直观的函数参数默认值。
ECMAScript 6 语法:
function f (x, y = 7, z = 42) {
return x + y + z;
}
f(1) === 50;
ECMAScript 5 语法:
function f (x, y, z) {
if (y === undefined)
y = 7
if (z === undefined)
z = 42
return x + y + z
}
f(1) === 50
剩余参数(Rest Parameter)
将剩余参数聚合为变长参数函数(variadic-functions)的单个参数。
ECMAScript 6 语法:
function f (x, y, ...a) {
return (x + y) * a.length;
}
f(1, 2, "hello", true, 7) === 9;
ECMAScript 5 语法:
function f (x, y) {
var a = Array.prototype.slice.call(arguments, 2)
return (x + y) * a.length
}
f(1, 2, "hello", true, 7) === 9
展开运算符(Spread Operator)
将可迭代集合的元素(如数组、字符串)展开为字面意义的元素或函数的单个参数。
ECMAScript 6:
var params = [ "hello", true, 7 ];
var other = [ 1, 2, ...params ]; // [ 1, 2, "hello", true, 7 ]
function f (x, y, ...a) {
return (x + y) * a.length;
}
f(1, 2, ...params) === 9;
var str = "foo";
var chars = [ ...str ]; // [ "f", "o", "o" ]
ECMAScript 5:
var params = [ "hello", true, 7 ]
var other = [ 1, 2 ].concat(params) // [ 1, 2, "hello", true, 7 ]
function f (x, y) {
var a = Array.prototype.slice.call(arguments, 2)
return (x + y) * a.length
}
f.apply(undefined, [ 1, 2 ].concat(params)) === 9
var str = "foo"
var chars = str.split("") // [ "f", "o", "o" ]
模版字符串(Template Literals)
字符串插值
单行和多行字符串的插值表达式。
ECMAScript 6:
var customer = { name: "Foo" };
var card = { amount: 7, product: "Bar", unitprice: 42 };
var message = `Hello ${customer.name},
want to buy ${card.amount} ${card.product} for
a total of ${card.amount * card.unitprice} bucks?`;
ECMAScript 5:
var customer = { name: "Foo" }
var card = { amount: 7, product: "Bar", unitprice: 42 }
var message = "Hello " + customer.name + ",\n" +
"want to buy " + card.amount + " " + card.product + " for\n" +
"a total of " + (card.amount * card.unitprice) + " bucks?"
自定义插值(Custom Interpolation)
任意方法的灵活插值表达式。
ECMAScript 6 :
get`http://example.com/foo?bar=${bar + baz}&quux=${quux}`;
ECMAScript 5 :
get([ "http://example.com/foo?bar=", "&quux=", "" ],bar + baz, quux)
访问原始字符串(Raw String Access)
访问原始模板字符串内容(不解析反斜杠)。
ECMAScript 6:
function quux (strings, ...values) {
strings[0] === "foo\n";
strings[1] === "bar";
strings.raw[0] === "foo\\n";
strings.raw[1] === "bar";
values[0] === 42;
}
quux`foo\n${ 42 }bar`
String.raw`foo\n${ 42 }bar` === "foo\\n42bar";
ECMAScript 5:
// no equivalent in ES5
字面量的扩展(Extended Literals)
二进制和八进制
直接支持安全的二进制和八进制。
ECMAScript 6:
0b111110111 === 503;
0o767 === 503;
ECMAScript 5:
parseInt("111110111", 2) === 503
parseInt("767", 8) === 503
0767 === 503 // only in non-strict, backward compatibility mode
unicode 字符和正则
支持在字符串和正则表达式中使用 unicode
。
ECMAScript 6:
"𠮷".length === 2;
"𠮷".match(/./u)[0].length === 2;
"𠮷" === "\uD842\uDFB7";
"𠮷" === "\u{20BB7}";
"𠮷".codePointAt(0) == 0x20BB7;
for (let codepoint of "𠮷") console.log(codepoint);
ECMAScript 5:
"𠮷".length === 2
"𠮷".match(/(?:[\0-\t\x0B\f\x0E-\u2027\u202A-\uD7FF\uE000-\uFFFF][\uD800-\uDBFF][\uDC00-\uDFFF][\uD800-\uDBFF](?![\uDC00-\uDFFF])(?:[^\uD800-\uDBFF]^)[\uDC00-\uDFFF])/)[0].length === 2
"𠮷" === "\uD842\uDFB7"
// no equivalent in ES5
// no equivalent in ES5
// no equivalent in ES5
增强的正则表达式(Enhanced Regular Expression)
正则表达式粘性匹配
Keep the matching position sticky between matches and this way support efficient parsing of arbitrary long input strings, even with an arbitrary number of distinct regular expressions.
ECMAScript 6:
let parser = (input, match) => {
for (let pos = 0, lastPos = input.length; pos < lastPos; ) {
for (let i = 0; i < match.length; i++) {
match[i].pattern.lastIndex = pos;
let found;
if ((found = match[i].pattern.exec(input)) !== null) {
match[i].action(found);
pos = match[i].pattern.lastIndex;
break;
}
}
}
}
let report = (match) => {
console.log(JSON.stringify(match));
};
parser("Foo 1 Bar 7 Baz 42", [
{ pattern: /Foo\s+(\d+)/y, action: (match) => report(match) },
{ pattern: /Bar\s+(\d+)/y, action: (match) => report(match) },
{ pattern: /Baz\s+(\d+)/y, action: (match) => report(match) },
{ pattern: /\s*/y, action: (match) => {} }
]);
ECMAScript 5:
var parser = function (input, match) {
for (var i, found, inputTmp = input; inputTmp !== ""; ) {
for (i = 0; i < match.length; i++) {
if ((found = match[i].pattern.exec(inputTmp)) !== null) {
match[i].action(found)
inputTmp = inputTmp.substr(found[0].length)
break
}
}
}
}
var report = function (match) {
console.log(JSON.stringify(match))
}
parser("Foo 1 Bar 7 Baz 42", [
{ pattern: /^Foo\s+(\d+)/, action: function (match) { report(match) } },
{ pattern: /^Bar\s+(\d+)/, action: function (match) { report(match) } },
{ pattern: /^Baz\s+(\d+)/, action: function (match) { report(match) } },
{ pattern: /^\s*/, action: function (match) {} }
])
增强的对象(Enhanced Object Properties)
属性速记
对象属性定义的简写语法。
ECMAScript 6:
var x = 0, y = 0;
obj = { x, y };
ECMAScript 5:
var x = 0, y = 0
obj = { x: x, y: y }
计算属性名
支持对象属性定义中的计算名称。
ECMAScript 6:
let obj = {
foo: "bar",
[ "baz" + quux() ]: 42
};
ECMAScript 5:
var obj = {
foo: "bar"
}
obj[ "baz" + quux() ] = 42
方法简写
省略 :
与 function
关键字。
ECMAScript 6:
obj = {
foo (a, b) {
…
},
bar (x, y) {
…
},
*quux (x, y) {
…
}
};
ECMAScript 5:
obj = {
foo: function (a, b) {
…
},
bar: function (x, y) {
…
},
// quux: no equivalent in ES5
…
}
更方便的数据访问
数组解构(Array Matching)
在赋值过程中,直观灵活地将数组分解为单个变量。
ECMAScript 6:
var list = [ 1, 2, 3 ];
var [ a, , b ] = list;
[ b, a ] = [ a, b ];
ECMAScript 5:
var list = [ 1, 2, 3 ]
var a = list[0], b = list[2]
var tmp = a; a = b; b = tmp
对象解构
在赋值过程中直观灵活地将对象分解为单个变量。
ECMAScript 6:
var { op, lhs, rhs } = getASTNode();
ECMAScript 5:
var tmp = getASTNode()
var op = tmp.op
var lhs = tmp.lhs
var rhs = tmp.rhs
嵌套对象解构
在赋值过程中直观灵活地将对象分解为单个变量。
ECMAScript 6:
var { op: a, lhs: { op: b }, rhs: c } = getASTNode();
ECMAScript 5:
var tmp = getASTNode()
var a = tmp.op
var b = tmp.lhs.op
var c = tmp.rhs
对象/数组解构默认值
简单直观的对象和数组解构默认值。
ECMAScript 6:
var obj = { a: 1 };
var list = [ 1 ];
var { a, b = 2 } = obj;
var [ x, y = 2 ] = list;
ECMAScript 5:
var obj = { a: 1 }
var list = [ 1 ]
var a = obj.a
var b = obj.b === undefined ? 2 : obj.b
var x = list[0]
var y = list[1] === undefined ? 2 : list[1]
参数解构(Parameter Context Matching)
在函数调用期间,将数组和对象直观而灵活地分解为单个参数。
ECMAScript 6:
function f ([ name, val ]) {
console.log(name, val);
}
function g ({ name: n, val: v }) {
console.log(n, v);
}
function h ({ name, val }) {
console.log(name, val);
}
f([ "bar", 42 ]);
g({ name: "foo", val: 7 });
h({ name: "bar", val: 42 });
ECMAScript 5:
function f (arg) {
var name = arg[0]
var val = arg[1]
console.log(name, val)
}
function g (arg) {
var n = arg.name
var v = arg.val
console.log(n, v)
}
function h (arg) {
var name = arg.name
var val = arg.val
console.log(name, val)
}
f([ "bar", 42 ])
g({ name: "foo", val: 7 })
h({ name: "bar", val: 42 })
Fail-Soft 解构
Fail-soft
解构,可选择使用默认值。
ECMAScript 6:
var list = [ 7, 42 ];
var [ a = 1, b = 2, c = 3, d ] = list;
a === 7;
b === 42;
c === 3;
d === undefined;
ECMAScript 5:
var list = [ 7, 42 ]
var a = typeof list[0] !== "undefined" ? list[0] : 1
var b = typeof list[1] !== "undefined" ? list[1] : 2
var c = typeof list[2] !== "undefined" ? list[2] : 3
var d = typeof list[3] !== "undefined" ? list[3] : undefined
a === 7
b === 42
c === 3
d === undefined
模块(Modules)
值的导入导出
支持从模块导入
、导出
值,不会污染全局命名空间。
ECMAScript 6:
// lib/math.js
export function sum (x, y) { return x + y };
export var pi = 3.141593;
// someApp.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));
ECMAScript 5:
// lib/math.js
LibMath = {}
LibMath.sum = function (x, y) { return x + y }
LibMath.pi = 3.141593
// someApp.js
var math = LibMath
console.log("2π = " + math.sum(math.pi, math.pi))
// otherApp.js
var sum = LibMath.sum, pi = LibMath.pi
console.log("2π = " + sum(pi, pi))
default & 通配符 *
默认导出和全部导出。
ECMAScript 6:
// lib/mathplusplus.js
export * from "lib/math";
export var e = 2.71828182846;
export default (x) => Math.exp(x);
// someApp.js
import exp, { pi, e } from "lib/mathplusplus";
console.log("e^{π} = " + exp(pi));
ECMAScript 5:
// lib/mathplusplus.js
LibMathPP = {}
for (symbol in LibMath)
if (LibMath.hasOwnProperty(symbol))
LibMathPP[symbol] = LibMath[symbol]
LibMathPP.e = 2.71828182846
LibMathPP.exp = function (x) { return Math.exp(x) }
// someApp.js
var exp = LibMathPP.exp, pi = LibMathPP.pi, e = LibMathPP.e
console.log("e^{π} = " + exp(pi))
类 (Classes)
类的声明(Class Definition)
类声明以 class
关键字开始,其后是类的名称,剩余部分的语法看起来就像对象字面量中方法的简写,并且在方法直接不需要使用逗号。
ECMAScript 6:
class Shape {
constructor (id, x, y) {
this.id = id;
this.move(x, y);
}
move (x, y) {
this.x = x;
this.y = y;
}
}
ECMAScript 5:
var Shape = function (id, x, y) {
this.id = id
this.move(x, y)
}
Shape.prototype.move = function (x, y) {
this.x = x
this.y = y
}
类的继承
使用 extends
关键字来指定当前类所需继承的类。
ECMAScript 6:
class Rectangle extends Shape {
constructor (id, x, y, width, height) {
super(id, x, y);
this.width = width;
this.height = height;
}
}
class Circle extends Shape {
constructor (id, x, y, radius) {
super(id, x, y);
this.radius = radius;
}
}
ECMAScript 5:
var Rectangle = function (id, x, y, width, height) {
Shape.call(this, id, x, y)
this.width = width
this.height = height
}
Rectangle.prototype = Object.create(Shape.prototype)
Rectangle.prototype.constructor = Rectangle
var Circle = function (id, x, y, radius) {
Shape.call(this, id, x, y)
this.radius = radius
}
Circle.prototype = Object.create(Shape.prototype)
Circle.prototype.constructor = Circle
从表达式中继承
ECMAScript 6 中派生类的最强大能力,或许就是能够从表达式中派生类。只要一个表达式能够返回一个具有 [[Construct]]
属性以及原型的函数,你就可以对其使用 extends
。
ECMAScript 6:
var aggregation = (baseClass, ...mixins) => {
let base = class _Combined extends baseClass {
constructor (...args) {
super(...args);
mixins.forEach((mixin) => {
mixin.prototype.initializer.call(this);
});
}
};
let copyProps = (target, source) => {
Object.getOwnPropertyNames(source)
.concat(Object.getOwnPropertySymbols(source))
.forEach((prop) => {
if (prop.match(/^(?:constructor|prototype|arguments|caller|name|bind|call|apply|toString|length)$/))
return
Object.defineProperty(target, prop, Object.getOwnPropertyDescriptor(source, prop))
})
}
mixins.forEach((mixin) => {
copyProps(base.prototype, mixin.prototype);
copyProps(base, mixin);
});
return base;
};
class Colored {
initializer () { this._color = "white"; }
get color () { return this._color; }
set color (v) { this._color = v; }
}
class ZCoord {
initializer () { this._z = 0; }
get z () { return this._z; }
set z (v) { this._z = v; }
}
class Shape {
constructor (x, y) { this._x = x; this._y = y; }
get x () { return this._x; }
set x (v) { this._x = v; }
get y () { return this._y; }
set y (v) { this._y = v; }
}
class Rectangle extends aggregation(Shape, Colored, ZCoord) {}
var rect = new Rectangle(7, 42);
rect.z = 1000;
rect.color = "red";
console.log(rect.x, rect.y, rect.z, rect.color);
ECMAScript 5:
var aggregation = function (baseClass, mixins) {
var base = function () {
baseClass.apply(this, arguments)
mixins.forEach(function (mixin) {
mixin.prototype.initializer.call(this)
}.bind(this))
}
base.prototype = Object.create(baseClass.prototype)
base.prototype.constructor = base
var copyProps = function (target, source) {
Object.getOwnPropertyNames(source).forEach(function (prop) {
if (prop.match(/^(?:constructor|prototype|arguments|caller|name|bind|call|apply|toString|length)$/))
return
Object.defineProperty(target, prop, Object.getOwnPropertyDescriptor(source, prop))
})
}
mixins.forEach(function (mixin) {
copyProps(base.prototype, mixin.prototype)
copyProps(base, mixin)
})
return base
}
var Colored = function () {}
Colored.prototype = {
initializer: function () { this._color = "white" },
getColor: function () { return this._color },
setColor: function (v) { this._color = v }
}
var ZCoord = function () {}
ZCoord.prototype = {
initializer: function () { this._z = 0 },
getZ: function () { return this._z },
setZ: function (v) { this._z = v }
}
var Shape = function (x, y) {
this._x = x; this._y = y
}
Shape.prototype = {
getX: function () { return this._x },
setX: function (v) { this._x = v },
getY: function () { return this._y },
setY: function (v) { this._y = v }
}
var _Combined = aggregation(Shape, [ Colored, ZCoord ])
var Rectangle = function (x, y) {
_Combined.call(this, x, y)
}
Rectangle.prototype = Object.create(_Combined.prototype)
Rectangle.prototype.constructor = Rectangle
var rect = new Rectangle(7, 42)
rect.setZ(1000)
rect.setColor("red")
console.log(rect.getX(), rect.getY(), rect.getZ(), rect.getColor())
基类的访问
使用 super
关键字对基类构造函数和方法的直观访问。
ECMAScript 6:
class Shape {
…
toString () {
return `Shape(${this.id})`
}
}
class Rectangle extends Shape {
constructor (id, x, y, width, height) {
super(id, x, y);
…
}
toString () {
return "Rectangle > " + super.toString();
}
}
class Circle extends Shape {
constructor (id, x, y, radius) {
super(id, x, y);
…
}
toString () {
return "Circle > " + super.toString();
}
}
ECMAScript 5:
var Shape = function (id, x, y) {
…
}
Shape.prototype.toString = function (x, y) {
return "Shape(" + this.id + ")"
}
var Rectangle = function (id, x, y, width, height) {
Shape.call(this, id, x, y)
…
}
Rectangle.prototype.toString = function () {
return "Rectangle > " + Shape.prototype.toString.call(this)
}
var Circle = function (id, x, y, radius) {
Shape.call(this, id, x, y)
…
}
Circle.prototype.toString = function () {
return "Circle > " + Shape.prototype.toString.call(this)
}
静态成员
支持使用 static
关键字定义静态成员。
ECMAScript 6:
class Rectangle extends Shape {
…
static defaultRectangle () {
return new Rectangle("default", 0, 0, 100, 100);
}
}
class Circle extends Shape {
…
static defaultCircle () {
return new Circle("default", 0, 0, 100);
}
}
var defRectangle = Rectangle.defaultRectangle();
var defCircle = Circle.defaultCircle();
ECMAScript 5:
var Rectangle = function (id, x, y, width, height) {
…
}
Rectangle.defaultRectangle = function () {
return new Rectangle("default", 0, 0, 100, 100)
}
var Circle = function (id, x, y, width, height) {
…
}
Circle.defaultCircle = function () {
return new Circle("default", 0, 0, 100)
}
var defRectangle = Rectangle.defaultRectangle()
var defCircle = Circle.defaultCircle()
访问器属性 getter/setter
自有属性需要在类的构造器中创建,而类还允许你在原型上定义访问器属性。为了创建一个 getter
要使用 get
关键字,创建 setter
使用 set
关键字。
ECMAScript 6:
class Rectangle {
constructor (width, height) {
this._width = width;
this._height = height;
}
set width (width) { this._width = width; }
get width () { return this._width; }
set height (height) { this._height = height; }
get height () { return this._height; }
get area () { return this._width * this._height; }
};
var r = new Rectangle(50, 20);
r.area === 1000;
ECMAScript 5:
var Rectangle = function (width, height) {
this._width = width
this._height = height
}
Rectangle.prototype = {
set width (width) { this._width = width },
get width () { return this._width },
set height (height) { this._height = height },
get height () { return this._height },
get area () { return this._width * this._height }
}
var r = new Rectangle(50, 20)
r.area === 1000
符号(Symbol)
符号的类型
用作对象属性标识符的唯一且不可变的数据类型。符号可以有可选的描述,但仅用于调试目的。
ECMAScript 6:
Symbol("foo") !== Symbol("foo");
const foo = Symbol();
const bar = Symbol();
typeof foo === "symbol";
typeof bar === "symbol";
let obj = {};
obj[foo] = "foo";
obj[bar] = "bar";
JSON.stringify(obj); // {}
Object.keys(obj); // []
Object.getOwnPropertyNames(obj); // []
Object.getOwnPropertySymbols(obj); // [ foo, bar ]
ECMAScript 5:
// no equivalent in ES5
全局符号
全局符号,通过唯一 key
索引。
ECMAScript 6:
Symbol.for("app.foo") === Symbol.for("app.foo")
const foo = Symbol.for("app.foo");
const bar = Symbol.for("app.bar");
Symbol.keyFor(foo) === "app.foo";
Symbol.keyFor(bar) === "app.bar";
typeof foo === "symbol";
typeof bar === "symbol";
let obj = {};
obj[foo] = "foo";
obj[bar] = "bar";
JSON.stringify(obj); // {}
Object.keys(obj); // []
Object.getOwnPropertyNames(obj); // []
Object.getOwnPropertySymbols(obj); // [ foo, bar ]
ECMAScript 5:
// no equivalent in ES5
迭代器(Iterators)
迭代器和 for-of
支持 iterable
协议,允许对象自定义迭代行为。另外,支持 iterable
协议来生成 值序列(有限或无限)。最后,提供方便的 of
运算符迭代可迭代对象的所有值。
ECMAScript 6:
let fibonacci = {
[Symbol.iterator]() {
let pre = 0, cur = 1;
return {
next () {
[ pre, cur ] = [ cur, pre + cur ];
return { done: false, value: cur };
}
};
}
}
for (let n of fibonacci) {
if (n > 1000)
break;
console.log(n);
}
ECMAScript 5:
var fibonacci = {
next: (function () {
var pre = 0, cur = 1
return function () {
tmp = pre
pre = cur
cur += tmp
return cur
}
})()
}
var n
for (;;) {
n = fibonacci.next()
if (n > 1000)
break
console.log(n)
}
生成器(Generators)
生成器函数 - 迭代器协议(Iterator Protocol)
生成器是能返回一个迭代器的函数,其中可以暂停和恢复控制流,以便生成值序列(有限或无限)。
ECMAScript 6:
let fibonacci = {
*[Symbol.iterator]() {
let pre = 0, cur = 1;
for (;;) {
[ pre, cur ] = [ cur, pre + cur ];
yield cur;
}
}
}
for (let n of fibonacci) {
if (n > 1000)
break;
console.log(n);
}
ECMAScript 5:
var fibonacci = {
next: (function () {
var pre = 0, cur = 1
return function () {
tmp = pre
pre = cur
cur += tmp
return cur
}
})()
}
var n
for (;;) {
n = fibonacci.next()
if (n > 1000)
break
console.log(n)
}
生成器函数 - 直接调用(Direct Use)
对生成器函数的支持,是一种特殊的函数变体,可以暂停和恢复控制流,以生成值序列(有限或无限)。
ECMAScript 6:
function* range (start, end, step) {
while (start < end) {
yield start;
start += step;
}
}
for (let i of range(0, 10, 2)) {
console.log(i); // 0, 2, 4, 6, 8
}
ECMAScript 5:
function range (start, end, step) {
var list = []
while (start < end) {
list.push(start)
start += step
}
return list
}
var r = range(0, 10, 2)
for (var i = 0; i < r.length; i++) {
console.log(r[i]) // 0, 2, 4, 6, 8
}
生成器 - 匹配(Matching)
支持生成器函数,即可以暂停和恢复控制流的函数,以便生成和扩展值序列(有限或无限)。
ECMAScript 6:
let fibonacci = function* (numbers) {
let pre = 0, cur = 1;
while (numbers-- > 0) {
[ pre, cur ] = [ cur, pre + cur ];
yield cur;
}
};
for (let n of fibonacci(1000))
console.log(n);
let numbers = [ ...fibonacci(1000) ];
let [ n1, n2, n3, ...others ] = fibonacci(1000);
ECMAScript 5:
// no equivalent in ES5
生成器 - 控制流(Control-Flow)
可以暂停和恢复流,以协程(co-routines
)的方式结合 Promise
解决异步编程。
ECMAScript 6:
// generic asynchronous control-flow driver
function async (proc, ...params) {
let iterator = proc(...params);
return new Promise((resolve, reject) => {
let loop = (value) => {
let result;
try {
result = iterator.next(value);
}
catch (err) {
reject(err);
}
if (result.done)
resolve(result.value);
else if ( typeof result.value === "object"
&& typeof result.value.then === "function")
result.value.then((value) => {
loop(value);
}, (err) => {
reject(err);
});
else
loop(result.value);
}
loop();
});
}
// application-specific asynchronous builder
function makeAsync (text, after) {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(text), after);
});
}
// application-specific asynchronous procedure
async(function* (greeting) {
let foo = yield makeAsync("foo", 300)
let bar = yield makeAsync("bar", 200)
let baz = yield makeAsync("baz", 100)
return `${greeting} ${foo} ${bar} ${baz}`
}, "Hello").then((msg) => {
console.log("RESULT:", msg); // "Hello foo bar baz"
})
ECMAScript 5:
// no equivalent in ES5
生成器 - 方法
由于生成器就是函数,因此也可以被添加到类和对象中。
ECMAScript 6:
class Clz {
* bar () {
…
}
};
let Obj = {
* foo () {
…
}
};
ECMAScript 5:
// no equivalent in ES5
Map/Set & WeakMap/WeakSet
Set 数据结构
基于集合的常用算法的清洁数据结构。
ECMAScript 6:
let s = new Set();
s.add("hello").add("goodbye").add("hello");
s.size === 2;
s.has("hello") === true;
for (let key of s.values()) // insertion order
console.log(key);
ECMAScript 5:
var s = {}
s["hello"] = true; s["goodbye"] = true; s["hello"] = true
Object.keys(s).length === 2
s["hello"] === true
for (var key in s) // arbitrary order
if (s.hasOwnProperty(key))
console.log(s[key])
Map 数据结构
基于映射的常用算法的更清晰的数据结构。
ECMAScript 6:
let m = new Map();
let s = Symbol();
m.set("hello", 42);
m.set(s, 34);
m.get(s) === 34;
m.size === 2;
for (let [ key, val ] of m.entries())
console.log(key + " = " + val);
ECMAScript 5:
var m = {}
// no equivalent in ES5
m["hello"] = 42
// no equivalent in ES5
// no equivalent in ES5
Object.keys(m).length === 2
for (key in m) {
if (m.hasOwnProperty(key)) {
var val = m[key]
console.log(key + " = " + val)
}
}
weakSet/weakMap 数据结构
无内存泄漏,Object-key’d
并排数据结构。
ECMAScript 6:
let isMarked = new WeakSet();
let attachedData = new WeakMap();
export class Node {
constructor (id) { this.id = id; }
mark () { isMarked.add(this); }
unmark () { isMarked.delete(this); }
marked () { return isMarked.has(this); }
set data (data) { attachedData.set(this, data); }
get data () { return attachedData.get(this); }
}
let foo = new Node("foo");
JSON.stringify(foo) === '{"id":"foo"}';
foo.mark();
foo.data = "bar";
foo.data === "bar";
JSON.stringify(foo) === '{"id":"foo"}';
isMarked.has(foo) === true
attachedData.has(foo) === true
foo = null /* remove only reference to foo */
attachedData.has(foo) === false
isMarked.has(foo) === false
ECMAScript 5:
// no equivalent in ES5
类型化数组(Typed Arrays)
类型化数组
支持基于任意字节的数据结构,实现网络协议、加密算法、文件格式操作等。
ECMAScript 6:
// ES6 class equivalent to the following C structure:
// struct Example { unsigned long id; char username[16]; float amountDue; };
class Example {
constructor (buffer = new ArrayBuffer(24)) {
this.buffer = buffer;
}
set buffer (buffer) {
this._buffer = buffer;
this._id = new Uint32Array (this._buffer, 0, 1);
this._username = new Uint8Array (this._buffer, 4, 16);
this._amountDue = new Float32Array(this._buffer, 20, 1);
}
get buffer () { return this._buffer; }
set id (v) { this._id[0] = v; }
get id () { return this._id[0]; }
set username (v) { this._username[0] = v; }
get username () { return this._username[0]; }
set amountDue (v) { this._amountDue[0] = v; }
get amountDue () { return this._amountDue[0]; }
}
let example = new Example()
example.id = 7
example.username = "John Doe"
example.amountDue = 42.0
ECMAScript 5:
// no equivalent in ES5
// (only an equivalent in HTML5)
新的内置方法(New Built-In Methods)
对象属性分配
Object.assign()
分配一个或多个对象的可枚举属性到目标对象上。
ECMAScript 6:
var dest = { quux: 0 };
var src1 = { foo: 1, bar: 2 };
var src2 = { foo: 3, baz: 4 };
Object.assign(dest, src1, src2);
dest.quux === 0;
dest.foo === 3;
dest.bar === 2;
dest.baz === 4;
ECMAScript 5:
var dest = { quux: 0 }
var src1 = { foo: 1, bar: 2 }
var src2 = { foo: 3, baz: 4 }
Object.keys(src1).forEach(function(k) {
dest[k] = src1[k]
})
Object.keys(src2).forEach(function(k) {
dest[k] = src2[k]
})
dest.quux === 0
dest.foo === 3
dest.bar === 2
dest.baz === 4
数组元素查找
查找数组元素的新方法 Array.find()
、Array.findIndex()
。
ECMAScript 6:
[ 1, 3, 4, 2 ].find(x => x > 3); // 4
[ 1, 3, 4, 2 ].findIndex(x => x > 3); // 2
ECMAScript 5:
[ 1, 3, 4, 2 ].filter(function (x) { return x > 3 })[0] // 4
// no equivalent in ES5
字符串复制
String.repeat()
接受一个参数作为字符串的重复次数,返回一个将初始字符串重复指定次数的新字符串。
ECMAScript 6:
" ".repeat(4 * depth);
"foo".repeat(3);
ECMAScript 5:
Array((4 * depth) + 1).join(" ")
Array(3 + 1).join("foo")
字符串检测
-
String.startsWith()
检测字符串是否以指定的前缀开始。 -
String.endsWith()
检测字符串是否以指定的前缀结束。 -
String.includes()
检测字符串收费包含指定字符串。
ECMAScript 6:
"hello".startsWith("ello", 1); // true
"hello".endsWith("hell", 4); // true
"hello".includes("ell"); // true
"hello".includes("ell", 1); // true
"hello".includes("ell", 2); // false
ECMAScript 5:
"hello".indexOf("ello") === 1 // true
"hello".indexOf("hell") === (4 - "hell".length) // true
"hello".indexOf("ell") !== -1 // true
"hello".indexOf("ell", 1) !== -1 // true
"hello".indexOf("ell", 2) !== -1 // false
数字类型检测
-
Number.isNaN()
方法确定传递的值是否为NaN
,并且检查其类型是否为 Number。它是原来的全局isNaN()
的更稳妥的版本。 -
Number.isFinite()
方法用来检测传入的参数是否是一个有穷数(finite number)。
ECMAScript 6:
Number.isNaN(42) === false;
Number.isNaN(NaN) === true;
Number.isFinite(Infinity) === false;
Number.isFinite(-Infinity) === false;
Number.isFinite(NaN) === false;
Number.isFinite(123) === true;
ECMAScript 5:
var isNaN = function (n) {
return n !== n
}
var isFinite = function (v) {
return (typeof v === "number" && !isNaN(v) && v !== Infinity && v !== -Infinity)
}
isNaN(42) === false
isNaN(NaN) === true
isFinite(Infinity) === false
isFinite(-Infinity) === false
isFinite(NaN) === false
isFinite(123) === true
数字安全性检测
Number.isSafeInteger()
检查数字是否在安全范围内(-(253 - 1)
到 253 - 1
之间的整数,包含 -(253 - 1)
和 253 - 1
)。
ECMAScript 6:
Number.isSafeInteger(42) === true;
Number.isSafeInteger(9007199254740992) === false;
ECMAScript 5:
function isSafeInteger (n) {
return (
typeof n === 'number'
&& Math.round(n) === n
&& -(Math.pow(2, 53) - 1) <= n
&& n <= (Math.pow(2, 53) - 1)
)
}
isSafeInteger(42) === true
isSafeInteger(9007199254740992) === false
数字比较
标准 Epsilon
值的可用性,用于更精确地比较浮点数。
ECMAScript 6:
console.log(0.1 + 0.2 === 0.3); // false
console.log(Math.abs((0.1 + 0.2) - 0.3) < Number.EPSILON); // true
ECMAScript 5:
console.log(0.1 + 0.2 === 0.3) // false
console.log(Math.abs((0.1 + 0.2) - 0.3) < 2.220446049250313e-16) // true
数字截断
将浮点数截断为其整数部分,完全去掉小数部分。
ECMAScript 6:
console.log(Math.trunc(42.7)) // 42
console.log(Math.trunc( 0.1)) // 0
console.log(Math.trunc(-0.1)) // -0
ECMAScript 5:
function mathTrunc (x) {
return (x < 0 ? Math.ceil(x) : Math.floor(x))
}
console.log(mathTrunc(42.7)) // 42
console.log(mathTrunc( 0.1)) // 0
console.log(mathTrunc(-0.1)) // -0
数字符号的确认
Math.sign()
函数返回一个数字的符号, 指示数字是正数、负数还是 0
。 ECMAScript 6:
console.log(Math.sign(7)) // 1
console.log(Math.sign(0)) // 0
console.log(Math.sign(-0)) // -0
console.log(Math.sign(-7)) // -1
console.log(Math.sign(NaN)) // NaN
ECMAScript 5:
function mathSign (x) {
return ((x === 0 || isNaN(x)) ? x : (x > 0 ? 1 : -1))
}
console.log(mathSign(7)) // 1
console.log(mathSign(0)) // 0
console.log(mathSign(-0)) // -0
console.log(mathSign(-7)) // -1
console.log(mathSign(NaN)) // NaN
Promise
Promise 用法
一个值的 First-Class
(头等函数)表示,该值可以异步生成并在将来可用。
ECMAScript 6:
function msgAfterTimeout (msg, who, timeout) {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(`${msg} Hello ${who}!`), timeout);
});
}
msgAfterTimeout("", "Foo", 100).then((msg) =>
msgAfterTimeout(msg, "Bar", 200)
).then((msg) => {
console.log(`done after 300ms:${msg}`);
});
ECMAScript 5:
function msgAfterTimeout (msg, who, timeout, onDone) {
setTimeout(function () {
onDone(msg + " Hello " + who + "!")
}, timeout)
}
msgAfterTimeout("", "Foo", 100, function (msg) {
msgAfterTimeout(msg, "Bar", 200, function (msg) {
console.log("done after 300ms:" + msg)
})
})
承诺组合 - Promise.all()
将一个或多个 Promise
组合成新的承诺,而不必亲自处理底层异步操作的排序。
ECMAScript 6:
function fetchAsync (url, timeout, onData, onError) {
…
}
let fetchPromised = (url, timeout) => {
return new Promise((resolve, reject) => {
fetchAsync(url, timeout, resolve, reject);
});
}
Promise.all([
fetchPromised("http://backend/foo.txt", 500),
fetchPromised("http://backend/bar.txt", 500),
fetchPromised("http://backend/baz.txt", 500)
]).then((data) => {
let [ foo, bar, baz ] = data;
console.log(`success: foo=${foo} bar=${bar} baz=${baz}`);
}, (err) => {
console.log(`error: ${err}`);
});
ECMAScript 5:
function fetchAsync (url, timeout, onData, onError) {
…
}
function fetchAll (request, onData, onError) {
var result = [], results = 0
for (var i = 0; i < request.length; i++) {
result[i] = null
(function (i) {
fetchAsync(request[i].url, request[i].timeout, function (data) {
result[i] = data
if (++results === request.length)
onData(result)
}, onError)
})(i)
}
}
fetchAll([
{ url: "http://backend/foo.txt", timeout: 500 },
{ url: "http://backend/bar.txt", timeout: 500 },
{ url: "http://backend/baz.txt", timeout: 500 }
], function (data) {
var foo = data[0], bar = data[1], baz = data[2]
console.log("success: foo=" + foo + " bar=" + bar + " baz=" + baz)
}, function (err) {
console.log("error: " + err)
})
元编程
代理 - Proxy
挂接到运行时级对象的元操作。
ECMAScript 6:
let target = {
foo: "Welcome, foo"
};
let proxy = new Proxy(target, {
get (receiver, name) {
return name in receiver ? receiver[name] : `Hello, ${name}`;
}
});
proxy.foo === "Welcome, foo";
proxy.world === "Hello, world";
ECMAScript 5:
// no equivalent in ES5
反射 - Reflect
根据对象元操作进行调用。
ECMAScript 6:
let obj = { a: 1 };
Object.defineProperty(obj, "b", { value: 2 });
obj[Symbol("c")] = 3;
Reflect.ownKeys(obj); // [ "a", "b", Symbol(c) ]
ECMAScript 5:
var obj = { a: 1 }
Object.defineProperty(obj, "b", { value: 2 })
// no equivalent in ES5
Object.getOwnPropertyNames(obj) // [ "a", "b" ]
国际化与本地化
Collation
Sorting a set of strings and searching within a set of strings. Collation is parameterized by locale and aware of Unicode.
ECMAScript 6:
// in German, "ä" sorts with "a"
// in Swedish, "ä" sorts after "z"
var list = [ "ä", "a", "z" ];
var l10nDE = new Intl.Collator("de");
var l10nSV = new Intl.Collator("sv");
l10nDE.compare("ä", "z") === -1;
l10nSV.compare("ä", "z") === +1;
console.log(list.sort(l10nDE.compare)); // [ "a", "ä", "z" ]
console.log(list.sort(l10nSV.compare)); // [ "a", "z", "ä" ]
ECMAScript 5:
// no equivalent in ES5
Number Formatting
Format numbers with digit grouping and localized separators.
ECMAScript 6:
var l10nEN = new Intl.NumberFormat("en-US");
var l10nDE = new Intl.NumberFormat("de-DE");
l10nEN.format(1234567.89) === "1,234,567.89";
l10nDE.format(1234567.89) === "1.234.567,89";
ECMAScript 5:
// no equivalent in ES5
Currency Formatting
Format numbers with digit grouping, localized separators and attached currency symbol.
ECMAScript 6:
var l10nUSD = new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" });
var l10nGBP = new Intl.NumberFormat("en-GB", { style: "currency", currency: "GBP" });
var l10nEUR = new Intl.NumberFormat("de-DE", { style: "currency", currency: "EUR" });
l10nUSD.format(100200300.40) === "$100,200,300.40";
l10nGBP.format(100200300.40) === "£100,200,300.40";
l10nEUR.format(100200300.40) === "100.200.300,40 €";
ECMAScript 5:
// no equivalent in ES5
日期/时间格式化(Date/Time Formatting)
Format date/time with localized ordering and separators.
ECMAScript 6:
var l10nEN = new Intl.DateTimeFormat("en-US");
var l10nDE = new Intl.DateTimeFormat("de-DE");
l10nEN.format(new Date("2015-01-02")) === "1/2/2015";
l10nDE.format(new Date("2015-01-02")) === "2.1.2015";
ECMAScript 5:
// no equivalent in ES5
本文分享自微信公众号 - 像素摇摆(pxDance)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。
来源:oschina
链接:https://my.oschina.net/u/4582094/blog/4388518