ES6 是下一代 JavaScript 語法標(biāo)準(zhǔn),比起 ES5 有很大的變化。
React 大量使用 ES6 語法,本文介紹其中一些最重要的語法點(diǎn)。完整的 ES6 介紹請參考 http://es6.ruanyifeng.com/ 。
let 和 const
let和const命令用于聲明變量。
let聲明的變量是可變的,const聲明的變量是不可變的。
let foo = 1;
foo = 2;
const bar = 1;
bar = 2; // 報(bào)錯
上面代碼中,let聲明的變量foo是可以重新賦值,但是如果對bar聲明的變量重新賦值,就會報(bào)錯。
注意,如果const聲明的變量指向一個對象,那么該對象的屬性是可變的。
const foo = {
bar: 1
};
foo.bar = 2;
上面代碼中,變量foo本身是不可變的,即foo不能指向另一個對象。但是,對象內(nèi)部的屬性是可變的,這是因?yàn)檫@時foo保存的是一個指針,這個指針本身不可變,但它指向的對象本身是可變的。
解構(gòu)賦值
ES6 允許按照一定模式,從數(shù)組和對象中提取值,對變量進(jìn)行賦值,這被稱為解構(gòu)(Destructuring)。
let [a, b, c] = [1, 2, 3];
上面代碼表示,可以從數(shù)組中提取值,按照對應(yīng)位置,對變量賦值。
解構(gòu)賦值不僅可以用于數(shù)組,還可以用于對象。
let { foo, bar } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"
解構(gòu)賦值時,還可以設(shè)置默認(rèn)值。
let [x, y = 'b'] = ['a']; // x='a', y='b'
上面代碼中,變量y解構(gòu)賦值時沒有取到值,所以默認(rèn)值就生效了。
對象的簡潔表示法
ES6 允許直接寫入變量和函數(shù),作為對象的屬性和方法。這樣的書寫更加簡潔。
const foo = 'bar';
const baz = { foo };
baz // {foo: "bar"}
除了屬性簡寫,方法也可以簡寫。
const o = {
method() {
return "Hello!";
}
};
// 等同于
const o = {
method: function() {
return "Hello!";
}
};
箭頭函數(shù)
ES6 允許使用“箭頭”(=>)定義函數(shù)。
var f = v => v;
// 等同于
var f = function (v) {
return v;
};
如果箭頭函數(shù)不需要參數(shù)或需要多個參數(shù),就使用一個圓括號代表參數(shù)部分。
var f = () => 5;
// 等同于
var f = function () { return 5 };
var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
return num1 + num2;
};
如果箭頭函數(shù)的代碼塊部分多于一條語句,就要使用大括號將它們括起來,并且使用return語句返回。
var sum = (num1, num2) => { return num1 + num2; }
rest 參數(shù)
ES6 引入 rest 參數(shù)(形式為...變量名),用于獲取函數(shù)的多余參數(shù),這樣就不需要使用arguments對象了。rest 參數(shù)搭配的變量是一個數(shù)組,該變量將多余的參數(shù)放入數(shù)組中。
function add(...values) {
let sum = 0;
for (var val of values) {
sum += val;
}
return sum;
}
add(2, 5, 3) // 10
上面代碼的add函數(shù)是一個求和函數(shù),利用 rest 參數(shù),可以向該函數(shù)傳入任意數(shù)目的參數(shù)。
擴(kuò)展運(yùn)算符
擴(kuò)展運(yùn)算符(spread)是三個點(diǎn)(...)。它好比 rest 參數(shù)的逆運(yùn)算,將一個數(shù)組轉(zhuǎn)為用逗號分隔的參數(shù)序列。
console.log(...[1, 2, 3])
// 1 2 3
console.log(1, ...[2, 3, 4], 5)
// 1 2 3 4 5
[...document.querySelectorAll('div')]
// [<div>, <div>, <div>]
對象也可以使用擴(kuò)展運(yùn)算符。
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x // 1
y // 2
z // { a: 3, b: 4 }
class
ES6 允許新建“類”(class)。
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();
}
}
上面是一個類的定義。
- constructor():構(gòu)造函數(shù),新建實(shí)例的時候,自動調(diào)用這個方法。
- extends:第一行的extends關(guān)鍵字表示繼承某個父類。
- super:子類方法里面的super指代父類。
- get():get是取值器,讀取該方法定義的屬性時,會自動執(zhí)行指定的代碼。
- set():set是賦值器,賦值該方法定義的屬性時,會自動執(zhí)行指定的代碼。
- static:方法前面加上static關(guān)鍵字,表示該方法是靜態(tài)方法,定義在類上面,而不是定義在實(shí)例對象上面,以上面為例,就是SkinnedMesh.defaultMatrix()這樣調(diào)用。
定義了類以后,就可以新建實(shí)例了。
const instance = new SkinnedMesh();
Promise 對象
Promise 是 ES6 引入的封裝異步操作的統(tǒng)一接口。它返回一個對象,包含了異步操作的信息。
Promise 本身是一個構(gòu)造函數(shù),提供了resolve和reject兩個方法。一旦異步操作成功結(jié)束,就調(diào)用resolve方法,將 Promise 實(shí)例對象的狀態(tài)改為resolved,一旦異步操作失敗,就調(diào)用reject方法,將 Promise 實(shí)例的狀態(tài)改成rejected。
function timeout(duration = 0) {
return new Promise((resolve, reject) => {
setTimeout(resolve, duration);
})
}
上面代碼中,timeout函數(shù)返回一個 Promise 實(shí)例,在指定時間以后,將狀態(tài)改為resolved。
var p = timeout(1000).then(() => {
return timeout(2000);
}).then(() => {
throw new Error("hmm");
}).catch(err => {
return Promise.all([timeout(100), timeout(200)]);
})
一旦 Promise 實(shí)例的狀態(tài)改變以后,就可以使用then()方法指定下面將要執(zhí)行的函數(shù),catch()方法用來處理rejected狀態(tài)的情況。
module
ES6 意義最重大的語法變化,就是引入了模塊(module)。
一個模塊內(nèi)部,使用export命令輸出對外的接口。
// lib/math.js
export function sum(x, y) {
return x + y;
}
export var pi = 3.141593;
上面的模塊輸出了sum和pi兩個接口。
import命令用于引入該模塊。
// app.js
import * as math from "lib/math";
alert("2π = " + math.sum(math.pi, math.pi));
上面代碼中,*表示引入所有接口,也可以只引入指定的接口。
// otherApp.js
import {sum, pi} from "lib/math";
alert("2π = " + sum(pi, pi));