ES6 特性

本文转载自:众成翻译 译者:萧暮 链接:http://www.zcfy.cc/article/2596 原文:https://codetower.github.io/es6-features/

箭头函数(Arrow Functions)

function() 的简写符号,但不会绑定 this

no-eval
var odds = evens.map(v => v + 1); // 没有小括号和花括号
var nums = evens.map((v, i) => v + i);
var pairs = evens.map(v => ({even: v, odd: v + 1}));
// 定义函数体
nums.forEach(v => {
 if (v % 5 === 0)
 fives.push(v);
});

this 怎么用呢?

var object = {
 name: "Name",
 arrowGetName: () => this.name,
 regularGetName: function() { return this.name },
 arrowGetThis: () => this,
 regularGetThis: function() { return this }
}
console.log(this.name)
console.log(object.arrowGetName());
console.log(object.arrowGetThis());
console.log(this)
console.log(object.regularGetName());
console.log(object.regularGetThis());

类(Classes)

在其他真正实现类的语言中,我们都知道这个概念。这里不过是原型继承之上的语法糖而已。

no-eval
class SkinnedMesh extends THREE.Mesh {
 constructor(geometry, materials) {
 super(geometry, materials);
 this.idMatrix = SkinnedMesh.defaultMatrix();
 this.bones = [];
 this.boneMatrices = [];
 //...
 }
 update(camera) {
 //...
 super.update();
 }
 get boneCount() {
 return this.bones.length;
 }
 set matrixType(matrixType) {
 this.idMatrix = SkinnedMesh[matrixType]();
 }
 static defaultMatrix() {
 return new THREE.Matrix4();
 }
}

Lebab.io

增强的对象字面量(Enhanced Object Literals)

var theProtoObj = {
 toString: function() {
 return "The ProtoOBject To string"
 }
}
var handler = () => "handler"
var obj = {
 // __proto__
 __proto__: theProtoObj,
 // 'handler: handler' 的简写
 handler,
 // 方法
 toString() {
 // 上层调用
 return "d " + super.toString();
 },
 // 动态计算属性名
 [ "prop_" + (() => 42)() ]: 42
};
console.log(obj.handler)
console.log(obj.handler())
console.log(obj.toString())
console.log(obj.prop_42)

字符串插值(String interpolation)

很好的字符串插值语法。

var name = "Bob", time = "today";
var multiLine = `This
Line
Spans Multiple
Lines`
console.log(`Hello ${name},how are you ${time}?`)
console.log(multiLine)

解构赋值(Destructuring)

// 列表 "匹配"
var [a, , b] = [1,2,3];
console.log(a)
console.log(b)

对象也能被解构赋值。

nodes = () => { return {op: "a", lhs: "b", rhs: "c"}}
var { op: a, lhs: b , rhs: c } = nodes()
console.log(a)
console.log(b)
console.log(c)

使用简写法。

nodes = () => { return {lhs: "a", op: "b", rhs: "c"}}
// 绑定 `op`, `lhs` and `rhs` 到作用域
var {op, lhs, rhs} = nodes()
console.log(op)
console.log(lhs)
console.log(rhs)

还可以用在函数参数上。

function g({name: x}) {
 return x
}
function m({name}) {
 return name
}
console.log(g({name: 5}))
console.log(m({name: 5}))

失效弱化的解构赋值。

var [a] = []
var [b = 1] = []
var c = [];
console.log(a)
console.log(b);
console.log(c);

默认的函数参数值(Default)

function f(x, y=12) {
 return x + y;
}
console.log(f(3))

展开(Spread)

在函数中:

function f(x, y, z) {
 return x + y + z;
}
// 将数组每个元素作为参数传入
console.log(f(...[1,2,3]))

在数组中:

var parts = ["shoulders", "knees"];
var lyrics = ["head", ...parts, "and", "toes"]; 
console.log(lyrics)

展开 + 对象字面量

可以用展开(Spread)在创建对象时做些很酷的事。

no-eval
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
console.log(x); // 1
console.log(y); // 2
console.log(z); // { a: 3, b: 4 }
// 展开属性
let n = { x, y, ...z };
console.log(n); // { x: 1, y: 2, a: 3, b: 4 }
console.log(obj)

不幸的是这还没被原生支持:

npm install --save-dev babel-plugin-transform-object-rest-spread

Rest

可以用 rest 操作符给函数传入无数个参数。

function demo(part1, ...part2) {
 return {part1, part2}
}
console.log(demo(1,2,3,4,5,6))

Let

Let 是新的 var。它有"正常"的绑定。

{
 var globalVar = "from demo1"
}
{
 let globalLet = "from demo2";
}
console.log(globalVar)
console.log(globalLet)

无论如何,它不会给 window 添加任何东西:

let me = "go"; // 全局作用域
var i = "able"; // 全局作用域
console.log(window.me);
console.log(window.i);

通过 let 可以重复声明一个变量:

let me = "foo";
let me = "bar";
console.log(me);
var me = "foo";
var me = "bar";
console.log(me)

常量(Const)

Const 声明的是只读变量。

const a = "b"
a = "a"

const 定义的对象,其属性依然是可修改的。

const a = { a: "a" }
a.a = "b"
console.log(a)

For..of

新型迭代器,与 for..in 是等价的。其中返回值而不是返回 keys

let list = [4, 5, 6];
console.log(list)
for (let i in list) {
 console.log(i);
}
let list = [4, 5, 6];
console.log(list)
for (let i of list) {
 console.log(i);
}

迭代器(Iterators)

这个迭代器比数组更加灵活。

let infinite = {
 [Symbol.iterator]() {
 let c = 0;
 return {
 next() {
 c++;
 return { done: false, value: c }
 }
 }
 }
}
console.log("start");
for (var n of infinite) {
 // 截取序列到 1000
 if (n > 10)
 break;
 console.log(n);
}

通过 Typescript 接口我们可以看到:

no-eval
interface IteratorResult {
 done: boolean;
 value: any;
}
interface Iterator {
 next(): IteratorResult;
}
interface Iterable {
 [Symbol.iterator](): Iterator
}

生成器(Generators)

生成器用来创建迭代器,比迭代器更为灵活。它们不必以相同的方式跟踪状态,且没有 done 的概念。

var infinity = {
 [Symbol.iterator]: function*() {
 var c = 1;
 for (;;) {
 yield c++;
 }
 }
}
console.log("start")
for (var n of infinity) {
 // 截取序列到 1000
 if (n > 10)
 break;
 console.log(n);
}

再通过 Typescript 看它的接口。

no-eval
interface Generator extends Iterator {
 next(value?: any): IteratorResult;
 throw(exception: any);
}

function* Iterators and generator

一个 yield* 的例子:

function* anotherGenerator(i) {
 yield i + 1;
 yield i + 2;
 yield i + 3;
}
function* generator(i) {
 yield i;
 yield* anotherGenerator(i);
 yield i + 10;
}
var gen = generator(10);
console.log(gen.next().value);
console.log(gen.next().value);
console.log(gen.next().value);
console.log(gen.next().value);
console.log(gen.next().value);

Unicode

ES6 为 Unicode 提供了更好的支持。

var regex = new RegExp('\u{61}', 'u');
console.log(regex.unicode)
console.log("\uD842\uDFD7")
console.log("\uD842\uDFD7".codePointAt())

模块 & 模块加载器

原生支持模块。

no-eval
import defaultMember from "module-name";
import * as name from "module-name";
import { member } from "module-name";
import { member as alias } from "module-name";
import { member1 , member2 } from "module-name";
import { member1 , member2 as alias2 , [...] } from "module-name";
import defaultMember, { member [ , [...] ] } from "module-name";
import defaultMember, * as name from "module-name";
import "module-name";
no-eval
export { name1, name2, ..., nameN };
export { variable1 as name1, variable2 as name2, ..., nameN };
export let name1, name2, ..., nameN; // 也可以用 var
export let name1 = ..., name2 = ..., ..., nameN; // 也可以用 var, const
export expression;
export default expression;
export default function (...) { ... } // 也可以是 class, function*
export default function name1(...) { ... } // 也可以是 class, function*
export { name1 as default, ... };
export * from ...;
export { name1, name2, ..., nameN } from ...;
export { import1 as name1, import2 as name2, ..., nameN } from ...;

Import Export

集合(Set)

集合对应数学上的概念,即所有元素都是唯一的。对于了解 SQL 的读者,这就相当于 distinct 关键字。

var set = new Set();
set.add("Potato").add("Tomato").add("Tomato");
console.log(set.size)
console.log(set.has("Tomato"))
for(var item of set) {
 console.log(item)
}

Set

弱集合(WeakSet)

WeakSet 对象可以让你在一个收集器中存储弱引用的对象。当对象没有被引用时将被垃圾回收处理。

var item = { a:"Potato"}
var set = new WeakSet();
set.add({ a:"Potato"}).add(item).add({ a:"Tomato"}).add({ a:"Tomato"});
console.log(set.size)
console.log(set.has({a:"Tomato"}))
console.log(set.has(item))
for(let item of set) {
 console.log(item)
}

WeakSet

Map

Maps,也称为字典。

var map = new Map();
map.set("Potato", 12);
map.set("Tomato", 34);
console.log(map.get("Potato"))
for(let item of map) {
 console.log(item)
}
for(let item in map) {
 console.log(item)
}

除了字符串意外的其他类型也可以使用。

var map = new Map();
var key = {a: "a"}
map.set(key, 12);
console.log(map.get(key))
console.log(map.get({a: "a"}))

Map

WeakMap

用对象作为键,且只保存有弱引用的键。

var wm = new WeakMap();
var o1 = {}
var o2 = {}
var o3 = {}
wm.set(o1, 1);
wm.set(o2, 2);
wm.set(o3, {a: "a"});
wm.set({}, 4);
console.log(wm.get(o2));
console.log(wm.has({}))
delete o2;
console.log(wm.get(o3));
for(let item in wm) {
 console.log(item)
}
for(let item of wm) {
 console.log(item)
}

WeakMap

代理(Proxies)

代理可以用来改变对象的行为。它允许我们定义陷阱。

var obj = function ProfanityGenerator() {
 return {
 words: "Horrible words"
 }
}()
var handler = function CensoringHandler() {
 return {
 get: function (target, key) {
 return target[key].replace("Horrible", "Nice");
 },
 }
}()
var proxy = new Proxy(obj, handler);
console.log(proxy.words);

下面的陷阱都是可用的:

no-eval
var handler =
{
 get:...,
 set:...,
 has:...,
 deleteProperty:...,
 apply:...,
 construct:...,
 getOwnPropertyDescriptor:...,
 defineProperty:...,
 getPrototypeOf:...,
 setPrototypeOf:...,
 enumerate:...,
 ownKeys:...,
 preventExtensions:...,
 isExtensible:...
}

Proxies

符号(Symbols)

符号是一种新类型。可以用来创建匿名属性。

var typeSymbol = Symbol("type");
class Pet {
 constructor(type) {
 this[typeSymbol] = type;
 }
 getType() {
 return this[typeSymbol];
 }
}
var a = new Pet("dog");
console.log(a.getType());
console.log(Object.getOwnPropertyNames(a))
console.log(Symbol("a") === Symbol("a"))

More info

可继承的内建对象(Inheritable Built-ins)

现在我们可以继承自原生类了。

class CustomArray extends Array {
}
var a = new CustomArray();
a[0] = 2
console.log(a[0])

如果不用数组的代理,就不可能覆盖 getter 函数。

新的库(New Library)

各种新的方法和常量。

console.log(Number.EPSILON)
console.log(Number.isInteger(Infinity))
console.log(Number.isNaN("NaN"))
console.log(Math.acosh(3))
console.log(Math.hypot(3, 4))
console.log(Math.imul(Math.pow(2, 32) - 1, Math.pow(2, 32) - 2))
console.log("abcde".includes("cd") )
console.log("abc".repeat(3) )
console.log(Array.of(1, 2, 3) )
console.log([0, 0, 0].fill(7, 1) )
console.log([1, 2, 3].find(x => x == 3) )
console.log([1, 2, 3].findIndex(x => x == 2)) 
console.log([1, 2, 3, 4, 5].copyWithin(3, 0)) 
console.log(["a", "b", "c"].entries() )
console.log(["a", "b", "c"].keys() )
console.log(["a", "b", "c"].values() )
console.log(Object.assign({}, { origin: new Point(0,0) }))

文档: Number, Math, Array.from, Array.of, Array.prototype.copyWithin, Object.assign

二进制和八进制

二进制和八进制编码的字面量。

console.log(0b11111)
console.log(0o2342)
console.log(0xff); // es5 同样支持

Promises

异步编程的好东西。

var p1 = new Promise((resolve, reject) => {
 setTimeout(() => resolve("1"), 101)
})
var p2 = new Promise((resolve, reject) => {
 setTimeout(() => resolve("2"), 100)
})
Promise.race([p1, p2]).then((res) => {
 console.log(res)
})
Promise.all([p1, p2]).then((res) => {
 console.log(res)
})

快速 Promise(Quick Promise)

想快速 resolved promise 吗?

var p1 = Promise.resolve("1")
var p2 = Promise.reject("2")
Promise.race([p1, p2]).then((res) => {
 console.log(res)
})

快速失败(Fail fast)

如果一个 promise 失败,allrace 同样都会 reject。

var p1 = new Promise((resolve, reject) => {
 setTimeout(() => resolve("1"), 1001)
})
var p2 = new Promise((resolve, reject) => {
 setTimeout(() => reject("2"), 1)
})
Promise.race([p1, p2]).then((res) => {
 console.log("success" + res)
}, res => {
 console.log("error " + res)
})
Promise.all([p1, p2]).then((res) => {
 console.log("success" + res)
}, res => {
 console.log("error " + res)
})

More Info

反射(Reflect)

新型元编程,新的 API,现有的方法和一些新的方法。

var z = {w: "Super Hello"}
var y = {x: "hello", __proto__: z};
console.log(Reflect.getOwnPropertyDescriptor(y, "x"));
console.log(Reflect.has(y, "w"));
console.log(Reflect.ownKeys(y, "w"));
console.log(Reflect.has(y, "x"));
console.log(Reflect.deleteProperty(y,"x"))
console.log(Reflect.has(y, "x"));

More Info

尾调用优化(Tail Call Optimization)

ES6 应该了修复尾调用,不会造成堆栈溢出。(并不是所有的实现工作)

function factorial(n, acc = 1) {
 if (n <= 1) return acc;
 return factorial(n - 1, n * acc);
}
console.log(factorial(10))
console.log(factorial(100))
console.log(factorial(1000))
console.log(factorial(10000))
console.log(factorial(100000))
console.log(factorial(1000000))
w3ctech微信

扫码关注w3ctech微信公众号

共收到0条回复

AltStyle によって変換されたページ (->オリジナル) /