ECMAScript6(ECMAScript 2015 ,ES5,ES2016)技術已經在前端圈子很流行了,他給前端開發人員帶來了很多驚喜,提供的語法糖使複雜的操作變得簡單。
本文沒有詳細描述這些新特性,因爲網上都已經有很多相關的介紹了。主要針對ES6 新特性收集了相關範例代碼,他可以讓你快速瞭解這個新的javascript規範。
箭頭函數
function()
函數的簡寫表示法,但它不綁定 this
。
課程內容大綱 | 開篇:一線大公司對中高級前端工程師的要求
-
1 JavaScript 測試基礎
-
2 JavaScript 難點選講
-
3 異步流程控制
-
7 學會性能測試對比
-
8 基於緩存的前端性能優化
-
......
點擊報名
ES6 代碼:
- 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
是如何工作的?
ES6 代碼:
- 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());
結果:
ES6 代碼:
- this.name ->
- object.arrowGetName() ->
- object.arrowGetThis() -> [object Window]
- this -> [object Window]
- object.regularGetName() -> Name
- object.regularGetThis() -> {"name":"Name"}
Classes(類)
我們知道“真正”語言中的類(Classes)。在 ES6 中類(Classes)其實是原型繼承的語法糖。
ES6 代碼:
- 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
增強的對象字面量
ES6 代碼:
- 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)
結果:
ES6 代碼:
- obj.handler -> () => "handler"
- obj.handler() -> handler
- obj.toString() -> d The ProtoOBject To string
- obj.prop_42 -> 42
字符串插值
字符串插值的好語法
字符串插值
ES6 代碼:
- var name = "Bob", time = "today";
-
- var multiLine = `This
-
- Line
-
- Spans Multiple
-
- Lines`
-
-
- console.log(`Hello ${name},how are you ${time}?`)
- console.log(multiLine)
結果:
ES6 代碼:
- `Hello ${name},how are you ${time}?` -> Hello Bob,how are you today?
- multiLine -> This Line Spans Multiple Lines
解構 Destructuring
愚人碼頭注:列表匹配
ES6 代碼:
- // list "matching"
- var [a, , b] = [1,2,3];
- console.log(a)
- console.log(b)
結果:
ES6 代碼:
- a -> 1
- b -> 3
對象也能很好的解構
ES6 代碼:
- 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)
結果:
ES6 代碼:
- a -> a
- b -> b
- c -> c
使用速記表示法。
ES6 代碼:
- 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)
結果:
ES6 代碼:
- op -> b
- lhs -> a
- rhs -> c
可在參數位置使用
ES6 代碼:
- function g({name: x}) {
- return x
- }
-
- function m({name}) {
- return name
- }
-
- console.log(g({name: 5}))
- console.log(m({name: 5}))
結果:
ES6 代碼:
- g({name: 5}) -> 5
- m({name: 5}) -> 5
故障弱化解構
ES6 代碼:
- var [a] = []
- var [b = 1] = []
- var c = [];
- console.log(a)
- console.log(b);
- console.log(c);
結果:
ES6 代碼:
- a -> undefined
- b -> 1
- c -> []
參數默認值(Default)
ES6 代碼:
- function f(x, y=12) {
- return x + y;
- }
-
- console.log(f(3))
- console.log(f(3,2))
結果:
ES6 代碼:
- f(3) -> 15
- f(3,2) -> 5
擴展(Spread)
在函數中:
ES6 代碼:
- function f(x, y, z) {
- return x + y + z;
- }
- // 傳遞數組的每個元素作爲參數
- console.log(f(...[1,2,3]))
結果:
ES6 代碼:
- f(...[1,2,3]) -> 6
在數組中:
ES6 代碼:
- var parts = ["shoulders", "knees"];
- var lyrics = ["head", ...parts, "and", "toes"];
-
- console.log(lyrics)
結果:
ES6 代碼:
- lyrics -> ["head","shoulders","knees","and","toes"]
擴展 + 對象字面量
我們可以使用這個創造很酷的對象。
ES6 代碼:
- 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 操作符來允許無限參數。
ES6 代碼:
- function demo(part1, ...part2) {
- return {part1, part2}
- }
-
- console.log(demo(1,2,3,4,5,6))
結果:
ES6 代碼:
- demo(1,2,3,4,5,6) -> {"part1":1,"part2":[2,3,4,5,6]}
Let
let
是新的var
。
因爲它有塊級作用域。
ES6 代碼:
- {
- var globalVar = "from demo1"
- }
-
- {
- let globalLet = "from demo2";
- }
-
- console.log(globalVar)
- console.log(globalLet)
結果:
ES6 代碼:
- globalVar -> from demo1
- globalLet -> ReferenceError: globalLet is not defined
但是,它不會向window
分配任何內容:
ES6 代碼:
- let me = "go"; // 全局作用域
- var i = "able"; // 全局作用域
-
- console.log(window.me);
- console.log(window.i);
結果:
ES6 代碼:
- window.me -> undefined
- window.i -> able
不能使用let
重新聲明一個變量:
ES6 代碼:
- let me = "foo";
- let me = "bar";
- console.log(me);
結果:
ES6 代碼:
- SyntaxError: Identifier 'me' has already been declared
ES6 代碼:
- var me = "foo";
- var me = "bar";
- console.log(me)
結果:
ES6 代碼:
- me -> bar
Const
const
是隻讀變量。
ES6 代碼:
- const a = "b"
- a = "a"
結果:
ES6 代碼:
- TypeError: Assignment to constant variable.
應該注意,const 對象仍然可以被改變的。
ES6 代碼:
- const a = { a: "a" }
- a.a = "b"
- console.log(a)
結果:
ES6 代碼:
- a -> {"a":"b"}
For..of
迭代器的新類型,可以替代for..in
。
它返回的是值而不是keys
。
ES6 代碼:
- let list = [4, 5, 6];
-
- console.log(list)
-
- for (let i in list) {
- console.log(i);
- }
結果:
ES6 代碼:
- list -> [4,5,6]
- i -> 0
- i -> 1
- i -> 2
ES6 代碼:
- let list = [4, 5, 6];
-
- console.log(list)
-
-
- for (let i of list) {
- console.log(i);
- }
結果:
ES6 代碼:
- list -> [4,5,6]
- i -> 4
- i -> 5
- i -> 6
迭代器(Iterators)
迭代器是一個比數組更動態的類型。
ES6 代碼:
- 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);
- }
結果:
ES6 代碼:
- "start" -> start
- n -> 1
- n -> 2
- n -> 3
- n -> 4
- n -> 5
- n -> 6
- n -> 7
- n -> 8
- n -> 9
- n -> 10
使用Typescript,我們可以看到它接口的樣子:
Typescript 代碼:
- interface IteratorResult {
- done: boolean;
- value: any;
- }
- interface Iterator {
- next(): IteratorResult;
- }
- interface Iterable {
- [Symbol.iterator](): Iterator
- }
生成器(Generators)
生成器創建迭代器,並且比迭代器更具動態性。他們不必以相同的方式跟蹤狀態 並不支持 done
的概念。
ES6 代碼:
- 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);
- }
結果:
ES6 代碼:
- "start" -> start
- n -> 1
- n -> 2
- n -> 3
- n -> 4
- n -> 5
- n -> 6
- n -> 7
- n -> 8
- n -> 9
- n -> 10
使用Typescript 再次顯示接口:
Typescript 代碼:
- interface Generator extends Iterator {
- next(value?: any): IteratorResult;
- throw(exception: any);
- }
function* Iterators
and generator
一個產量的例子*
ES6 代碼:
- 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);
結果:
ES6 代碼:
- gen.next().value -> 10
- gen.next().value -> 11
- gen.next().value -> 12
- gen.next().value -> 13
- gen.next().value -> 20
Unicode
ES6 爲Unicode 提供了更好的支持。
ES6 代碼:
- var regex = new RegExp('\u{61}', 'u');
-
- console.log(regex.unicode)
- console.log("\uD842\uDFD7")
- console.log("\uD842\uDFD7".codePointAt())
結果:
ES6 代碼:
- regex.unicode -> true
- "" ->
- "".codePointAt() -> 134103
模塊和模塊加載器
原生支持模塊。
ES6 代碼:
- 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";
ES6 代碼:
- 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 …;
Import Export
Set
Set 爲數學對應,其中所有項目都是唯一的。對於知道SQL的人來說,這相當於distinct
。
ES6 代碼:
- 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)
- }
結果:
ES6 代碼:
- set.size -> 2
- set.has("Tomato") -> true
- item -> Potato
- item -> Tomato
Set
WeakSet
WeakSet對象允許您在集合中存儲弱持有的對象。沒有引用的對象將被垃圾回收。
ES6 代碼:
- 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)
- }
結果:
ES6 代碼:
- set.size -> undefined
- set.has({a:"Tomato"}) -> false
- set.has(item) -> true
- TypeError: set[Symbol.iterator] is not a function
WeakSet
Map
Map 也稱爲詞典。
ES6 代碼:
- 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)
- }
結果:
ES6 代碼:
- map.get("Potato") -> 12
- item -> ["Potato",12]
- item -> ["Tomato",34]
可以使用除字符串之外的其他類型。
ES6 代碼:
- var map = new Map();
- var key = {a: "a"}
- map.set(key, 12);
-
-
- console.log(map.get(key))
- console.log(map.get({a: "a"}))
結果:
ES6 代碼:
- map.get(key) -> 12
- map.get({a: "a"}) -> undefined
Map
WeakMap
使用鍵的對象,並且只保留對鍵的弱引用。
ES6 代碼:
- 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)
- }
結果:
ES6 代碼:
- wm.get(o2) -> 2
- wm.has({}) -> false
- wm.get(o3) -> {"a":"a"}
- TypeError: wm[Symbol.iterator] is not a function
WeakMap
代理(Proxy)
代理可以用來改變對象的行爲。 它們允許我們定義 trap 。
ES6 代碼:
- 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);
結果:
ES6 代碼:
- proxy.words -> Nice words
提供以下 trap :
ES6 代碼:
- var handler =
- {
- get:...,
- set:...,
- has:...,
- deleteProperty:...,
- apply:...,
- construct:...,
- getOwnPropertyDescriptor:...,
- defineProperty:...,
- getPrototypeOf:...,
- setPrototypeOf:...,
- enumerate:...,
- ownKeys:...,
- preventExtensions:...,
- isExtensible:...
- }
Proxy
Symbols
Symbols 是一個新類型。 可用於創建匿名屬性。
ES6 代碼:
- 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"))
結果:
ES6 代碼:
- a.getType() -> dog
- Object.getOwnPropertyNames(a) -> []
- Symbol("a") === Symbol("a") -> false
更多信息
可繼承內置函數
我們現在可以繼承原生類。
ES6 代碼:
- class CustomArray extends Array {
-
- }
-
- var a = new CustomArray();
-
- a[0] = 2
- console.log(a[0])
結果:
ES6 代碼:
- a[0] -> 2
不能使用數組的代理(Proxy)來覆蓋getter函數。
新類庫
各種新的方法和常量。
ES6 代碼:
- 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) }))
結果:
ES6 代碼:
- 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
二進制和八進制
二進制和八進制數字的字面量。
ES6 代碼:
- console.log(0b11111)
- console.log(0o2342)
-
- console.log(0xff); // also in es5
結果:
ES6 代碼:
- 0b11111 -> 31
- 0o2342 -> 1250
- 0xff -> 255
Promises
異步編程。
ES6 代碼:
- 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)
- })
結果:
ES6 代碼:
- res -> 2
- res -> ["1","2"]
快速的 Promise
ES6 代碼:
- var p1 = Promise.resolve("1")
- var p2 = Promise.reject("2")
-
- Promise.race([p1, p2]).then((res) => {
- console.log(res)
- })
結果:
ES6 代碼:
- res -> 1
快速失敗
如果一個 promise 失敗,all
和race
也將
reject(拒絕)。
ES6 代碼:
- 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)
- })
結果:
ES6 代碼:
- "error " + res -> error 2
- "error " + res -> error 2
更多信息
反射(Reflect)
新類型的元編程與新的API現有的還有一些新的方法。
ES6 代碼:
- 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"));
結果:
ES6 代碼:
- 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可以確保尾調用不會造成堆棧溢出。 (不是所有的實現工作)。
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))
結果:
ES6 代碼:
- 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