ECMAScript6 新特性范例大全
ecmascript6(ecmascript 2015 ,es5,es2016)技术已经在前端圈子很流行了,他给前端开发人员带来了很多惊喜,提供的语法糖使复杂的操作变得简单。
本文没有详细描述这些新特性,因为网上都已经有很多相关的介绍了。主要针对es6 新特性收集了相关范例代码,他可以让你快速了解这个新的javascript规范。
箭头函数
function()
函数的简写表示法,但它不绑定 this
。
var odds = evens.map(v => v + 1); // no parentes and no brackets var nums = evens.map((v, i) => v + i); var pairs = evens.map(v => ({even: v, odd: v + 1})); // statement bodies 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());
结果:
this.name -> object.arrowgetname() -> object.arrowgetthis() -> [object window] this -> [object window] object.regulargetname() -> name object.regulargetthis() -> {"name":"name"}
classes(类)
我们知道“真正”语言中的类(classes)。在 es6 中类(classes)其实是原型继承的语法糖。
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(); } }
增强的对象字面量
var theprotoobj = { tostring: function() { return "the protoobject to string" } } var handler = () => "handler" var obj = { // __proto__ __proto__: theprotoobj, // shorthand for ‘handler: handler' handler, // methods tostring() { // super calls return "d " + super.tostring(); }, // computed (dynamic) property names [ "prop_" + (() => 42)() ]: 42 }; console.log(obj.handler) console.log(obj.handler()) console.log(obj.tostring()) console.log(obj.prop_42)
结果:
obj.handler -> () => "handler" obj.handler() -> handler obj.tostring() -> d the protoobject to string obj.prop_42 -> 42
字符串插值
字符串插值的好语法
字符串插值
var name = "bob", time = "today"; var multiline = `this line spans multiple lines` console.log(`hello ${name},how are you ${time}?`) console.log(multiline)
结果:
`hello ${name},how are you ${time}?` -> hello bob,how are you today? multiline -> this line spans multiple lines
解构 destructuring
愚人码头注:列表匹配
// list "matching" var [a, , b] = [1,2,3]; console.log(a) console.log(b)
结果:
a -> 1 b -> 3
对象也能很好的解构
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)
结果:
a -> a b -> b c -> c
使用速记表示法。
nodes = () => { return {lhs: "a", op: "b", rhs: "c"}} // binds `op`, `lhs` and `rhs` in scope var {op, lhs, rhs} = nodes() console.log(op) console.log(lhs) console.log(rhs)
结果:
op -> b lhs -> a rhs -> c
可在参数位置使用
function g({name: x}) { return x } function m({name}) { return name } console.log(g({name: 5})) console.log(m({name: 5}))
结果:
g({name: 5}) -> 5 m({name: 5}) -> 5
故障弱化解构
var [a] = [] var [b = 1] = [] var c = []; console.log(a) console.log(b); console.log(c);
结果:
a -> undefined b -> 1 c -> []
参数默认值(default)
function f(x, y=12) { return x + y; } console.log(f(3)) console.log(f(3,2))
结果:
f(3) -> 15 f(3,2) -> 5
扩展(spread)
在函数中:
function f(x, y, z) { return x + y + z; } // 传递数组的每个元素作为参数 console.log(f(...[1,2,3]))
结果:
f(...[1,2,3]) -> 6
在数组中:
var parts = ["shoulders", "knees"]; var lyrics = ["head", ...parts, "and", "toes"]; console.log(lyrics)
结果:
lyrics -> ["head","shoulders","knees","and","toes"]
扩展 + 对象字面量
我们可以使用这个创造很酷的对象。
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 } // spread properties 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))
结果:
demo(1,2,3,4,5,6) -> {"part1":1,"part2":[2,3,4,5,6]}
let
let
是新的var
。 因为它有块级作用域。
{ var globalvar = "from demo1" } { let globallet = "from demo2"; } console.log(globalvar) console.log(globallet)
结果:
globalvar -> from demo1 globallet -> referenceerror: globallet is not defined
但是,它不会向window
分配任何内容:
let me = "go"; // 全局作用域 var i = "able"; // 全局作用域 console.log(window.me); console.log(window.i);
结果:
window.me -> undefined window.i -> able
不能使用let
重新声明一个变量:
let me = "foo"; let me = "bar"; console.log(me);
结果:
syntaxerror: identifier 'me' has already been declared
var me = "foo"; var me = "bar"; console.log(me)
结果:
me -> bar
const
const
是只读变量。
const a = "b" a = "a"
结果:
typeerror: assignment to constant variable.
应该注意,const 对象仍然可以被改变的。
const a = { a: "a" } a.a = "b" console.log(a)
结果:
a -> {"a":"b"}
for..of
迭代器的新类型,可以替代for..in
。 它返回的是值而不是keys
。
let list = [4, 5, 6]; console.log(list) for (let i in list) { console.log(i); }
结果:
list -> [4,5,6] i -> 0 i -> 1 i -> 2
let list = [4, 5, 6]; console.log(list) for (let i of list) { console.log(i); }
结果:
list -> [4,5,6] i -> 4 i -> 5 i -> 6
迭代器(iterators)
迭代器是一个比数组更动态的类型。
let infinite = { [symbol.iterator]() { let c = 0; return { next() { c++; return { done: false, value: c } } } } } console.log("start"); for (var n of infinite) { // truncate the sequence at 1000 if (n > 10) break; console.log(n); }
结果:
"start" -> start n -> 1 n -> 2 n -> 3 n -> 4 n -> 5 n -> 6 n -> 7 n -> 8 n -> 9 n -> 10
使用typescript,我们可以看到它接口的样子:
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) { // truncate the sequence at 1000 if (n > 10) break; console.log(n); }
结果:
"start" -> start n -> 1 n -> 2 n -> 3 n -> 4 n -> 5 n -> 6 n -> 7 n -> 8 n -> 9 n -> 10
使用typescript 再次显示接口:
interface generator extends iterator { next(value?: any): iteratorresult; throw(exception: any); }
function* iterators and generator
一个产量的例子*
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);
结果:
gen.next().value -> 10 gen.next().value -> 11 gen.next().value -> 12 gen.next().value -> 13 gen.next().value -> 20
unicode
es6 为unicode 提供了更好的支持。
var regex = new regexp('\u{61}', 'u'); console.log(regex.unicode) console.log("\ud842\udfd7") console.log("\ud842\udfd7".codepointat())
结果:
regex.unicode -> true "" -> "".codepointat() -> 134103
模块和模块加载器
原生支持模块。
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";
export { name1, name2, …, namen }; export { variable1 as name1, variable2 as name2, …, namen }; export let name1, name2, …, namen; // also var export let name1 = …, name2 = …, …, namen; // also var, const export expression; export default expression; export default function (…) { … } // also class, function* export default function name1(…) { … } // also class, function* export { name1 as default, … }; export * from …; export { name1, name2, …, namen } from …; export { import1 as name1, import2 as name2, …, namen } from …;
set
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.size -> 2 set.has("tomato") -> true item -> potato item -> tomato
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) }
结果:
set.size -> undefined set.has({a:"tomato"}) -> false set.has(item) -> true typeerror: set[symbol.iterator] is not a function
map
map 也称为词典。
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) }
结果:
map.get("potato") -> 12 item -> ["potato",12] item -> ["tomato",34]
可以使用除字符串之外的其他类型。
var map = new map(); var key = {a: "a"} map.set(key, 12); console.log(map.get(key)) console.log(map.get({a: "a"}))
结果:
map.get(key) -> 12 map.get({a: "a"}) -> undefined
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) }
结果:
wm.get(o2) -> 2 wm.has({}) -> false wm.get(o3) -> {"a":"a"} typeerror: wm[symbol.iterator] is not a function
代理(proxy)
代理可以用来改变对象的行为。 它们允许我们定义 trap 。
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);
结果:
proxy.words -> nice words
提供以下 trap :
var handler = { get:..., set:..., has:..., deleteproperty:..., apply:..., construct:..., getownpropertydescriptor:..., defineproperty:..., getprototypeof:..., setprototypeof:..., enumerate:..., ownkeys:..., preventextensions:..., isextensible:... }
symbols
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"))
结果:
a.gettype() -> dog object.getownpropertynames(a) -> [] symbol("a") === symbol("a") -> false
可继承内置函数
我们现在可以继承原生类。
class customarray extends array { } var a = new customarray(); a[0] = 2 console.log(a[0])
结果:
a[0] -> 2
不能使用数组的代理(proxy)来覆盖getter函数。
新类库
各种新的方法和常量。
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.epsilon -> 2.220446049250313e-16 number.isinteger(infinity) -> false number.isnan("nan") -> false math.acosh(3) -> 1.7627471740390859 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.of(1, 2, 3) -> [1,2,3] [0, 0, 0].fill(7, 1) -> [0,7,7] [1, 2, 3].find(x => x == 3) -> 3 [1, 2, 3].findindex(x => x == 2) -> 1 [1, 2, 3, 4, 5].copywithin(3, 0) -> [1,2,3,1,2] ["a", "b", "c"].entries() -> {} ["a", "b", "c"].keys() -> {} ["a", "b", "c"].values() -> typeerror: ["a","b","c"].values is not a function object.assign({}, { origin: new point(0,0) }) -> referenceerror: point is not defined
文档: number, math, array.from, array.of, array.prototype.copywithin, object.assign
二进制和八进制
二进制和八进制数字的字面量。
console.log(0b11111) console.log(0o2342) console.log(0xff); // also in es5
结果:
0b11111 -> 31 0o2342 -> 1250 0xff -> 255
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) })
结果:
res -> 2 res -> ["1","2"]
快速的 promise
var p1 = promise.resolve("1") var p2 = promise.reject("2") promise.race([p1, p2]).then((res) => { console.log(res) })
结果:
res -> 1
快速失败
如果一个 promise 失败,all
和race
也将 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) })
结果:
"error " + res -> error 2 "error " + res -> error 2
反射(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"));
结果:
reflect.getownpropertydescriptor(y, "x") -> {"value":"hello","writable":true,"enumerable":true,"configurable":true} reflect.has(y, "w") -> true reflect.ownkeys(y, "w") -> ["x"] reflect.has(y, "x") -> true reflect.deleteproperty(y,"x") -> true reflect.has(y, "x") -> false
尾调用(tail call)优化
尾调用的概念非常简单,一句话就能说清楚,就是指某个函数的最后一步是调用另一个函数。
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))
结果:
factorial(10) -> 3628800 factorial(100) -> 9.332621544394418e+157 factorial(1000) -> infinity factorial(10000) -> infinity factorial(100000) -> rangeerror: maximum call stack size exceeded factorial(1000000) -> rangeerror: maximum call stack size exceeded
原文:es6 features
推荐阅读