//仅在ES5中通过对象属性的帮助,并且仅在全局上下文中,而不在块范围中
Object.defineProperty(typeof global === "object" ? global : window, "PI", {
value: 3.141593,
enumerable: true,
writable: false,
configurable: false
})
PI > 3.0;
二. 作用域
scoping
1.块范围变量
块范围的变量(和常量)没有提升。
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
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;
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?`
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?";
"𠮷".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
obj = {
foo: function (a, b) {
…
},
bar: function (x, y) {
…
},
// quux:在ES5中没有相应的功能
…
};
九. 解构赋值
destructuring-assignment
1.数组匹配
在分配过程中直观且灵活地将阵列解构成单个变量。
var list = [ 1, 2, 3 ]
var [ a, , b ] = list
[ b, a ] = [ a, b ]
var list = [ 1, 2, 3 ];
var a = list[0], b = list[2];
var tmp = a; a = b; b = tmp;
2.对象匹配,速记符号
在分配过程中直观且灵活地将对象解构成单个变量。
var { op, lhs, rhs } = getASTNode()
var tmp = getASTNode();
var op = tmp.op;
var lhs = tmp.lhs;
var rhs = tmp.rhs;
3.对象匹配,深度匹配
在分配过程中直观且灵活地将对象解构成单个变量。
var { op: a, lhs: { op: b }, rhs: c } = getASTNode()
var tmp = getASTNode();
var a = tmp.op;
var b = tmp.lhs.op;
var c = tmp.rhs;
4.对象和数组匹配,默认值
简单直观的默认值,用于解构对象和数组。
var obj = { a: 1 }
var list = [ 1 ]
var { a, b = 2 } = obj
var [ x, y = 2 ] = list
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];
5.参数上下文匹配
在函数调用期间,将数组和对象直观且灵活地解构成单个参数。
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 })
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 });
6.失败软解构
失效软解构,可选择默认值。
var list = [ 7, 42 ]
var [ a = 1, b = 2, c = 3, d ] = list
a === 7
b === 42
c === 3
d === undefined
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
1.值导出/导入
支持从/向模块输出/输入值,而不会造成全局命名空间污染。
// 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))
// 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));
2.默认和通配符
将值标记为默认导出值和值的质量混合。
// 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))
// 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
1.类定义
更直观,面向对象的风格和空模板的类。
class Shape {
constructor (id, x, y) {
this.id = id
this.move(x, y)
}
move (x, y) {
this.x = x
this.y = y
}
}
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;
};
2.类继承
更直观,OOP风格和空模板继承。
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
}
}
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;
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);
};
5.静态成员
简单支持静态类成员。
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()
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();
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)
}
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);
}
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)
}
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);
}
2.生成器函数,直接使用
支持生成器函数,这是函数的一个特殊变体,可以暂停和恢复控制流,以生成序列值(有限或无限)。
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
}
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
}
3.生成器匹配
支持生成器函数,即可以暂停和恢复控制流的函数,以生成和传播值序列(有限或无限)。
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)
// 通用异步控制流驱动程序
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()
})
}
// 特定于应用程序的异步构建器
function makeAsync (text, after) {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(text), after)
})
}
// 应用程序特定的异步过程
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"
})
// 在ES5中没有等价物
5.生成器方法
基于生成器函数,支持生成器方法,即类和对象中的方法。
class Clz {
* bar () {
…
}
}
let Obj = {
* foo () {
…
}
}
// 在ES5中没有等价物
十五. Map/Set & WeakMap/WeakSet
map-set-weak-map-weak-set
1.设置数据结构
基于集合的常用算法的更清晰的数据结构。
let s = new Set()
s.add("hello").add("goodbye").add("hello")
s.size === 2
s.has("hello") === true
for (let key of s.values()) // 插入指令
console.log(key)
var s = {};
s["hello"] = true; s["goodbye"] = true; s["hello"] = true;
Object.keys(s).length === 2;
s["hello"] === true;
for (var key in s) // 任意的顺序
if (s.hasOwnProperty(key))
console.log(s[key]);
2.map 数据结构
基于 map 的常用算法的更清晰的数据结构。
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)
var m = {};
// 在ES5中没有任何等价物
m["hello"] = 42;
// 在ES5中没有任何等价物
// 在ES5中没有任何等价物
Object.keys(m).length === 2;
for (key in m) {
if (m.hasOwnProperty(key)) {
var val = m[key];
console.log(key + " = " + val);
}
}
3. 弱链数据结构
无内存泄漏的Object-key'd并排数据结构。
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
// 在ES5中没有等价物
十六. 键入数组
typed-arrays
支持任意字节数据结构来实现网络协议,密码算法,文件格式操作等。
// 相当于以下C结构的ES6类:
// 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
// 在ES5中没有等价物
// (只有HTML5中的一个等效项)
十七. 新的内置方法
new-built-in-methods
1.对象属性分配
将一个或多个源对象的枚举属性分配到目标对象的新函数。
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
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;
// 在德语中,“ä”与“a”
// 在瑞典语中,“ä”在“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", "ä" ]
// 在ES5中没有等价物
2.数字格式
使用数字分组和本地化分隔符格式化数字。
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"
// 在ES5中没有等价物
3.货币格式
使用数字分组格式化数字,本地化分隔符和附加的货币符号。
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 €"
// 在ES5中没有等价物
4.日期/时间格式
使用本地化排序和分隔符格式化日期/时间。
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"