1.什么是es6
ECMAScript 6.0(以下簡稱ES6)是JavaScript語言的下一代標准,已經在2015年6月正式發布了。它的目標,是使得JavaScript語言可以用來編寫復雜的大型應用程序,成為企業級開發語言。
ECMAScript和JavaScript的關系是,前者是后者的規格,后者是前者的一種實現。
es6入門文檔:http://caibaojian.com/es6/
2.node中使用es6
Babel是一個廣泛使用的ES6轉碼器,可以將ES6代碼轉為ES5代碼,從而在現有環境執行。
2.1配置文件 .babelrc
Babel的配置文件是.babelrc
,存放在項目的根目錄下。使用Babel的第一步,就是配置這個文件。該文件用來設置轉碼規則和插件,基本格式如下:
{
"presets": [],
"plugins": []
}
2.2安裝es6轉換模塊
presets
字段設定轉碼規則,官方提供以下的規則集,你可以根據需要安裝。
// ES2015轉碼規則
$ npm install --save-dev babel-preset-es2015
// react轉碼規則
$ npm install --save-dev babel-preset-react
// ES7不同階段語法提案的轉碼規則(共有4個階段),選裝一個
$ npm install --save-dev babel-preset-stage-0
$ npm install --save-dev babel-preset-stage-1
$ npm install --save-dev babel-preset-stage-2
$ npm install --save-dev babel-preset-stage-3
然后,將這些規則加入.babelrc
。
{
"presets": [
"es2015",
"react",
"stage-2"
],
"plugins": []
}
注意,Babel工具和模塊的使用,都必須先寫好.babelrc
。
2.3全局安裝命令行工具
Babel提供babel-cli
工具,用於命令行轉碼。
cnpm install babel‐cli ‐g
2.4使用
babel-node js文件名
3.語法新特性
3.1 變量聲明let
在es6之前,var關鍵字聲明變量。無論聲明在何處,都會被視為聲明在函數的最頂部,這是函數變量的提升。如下:
function aa() {
if(bool) {
//聲明變量
var test = 'hello man'
} else {
console.log(test)
}
}
上面代碼實際是:
function aa() {
var test // 變量提升
if(bool) {
test = 'hello man'
} else {
//此處訪問test 值為undefined
console.log(test)
}
//此處訪問test 值為undefined
}
es6后,通常用let和const來聲明,let表示變量、const表示常量。let和const都是塊級作用域(在一個函數內部 ,在一個代碼塊內部)。如下:
//變量聲明let
function test(b){
if(b){
//var 全局變量; let 局部變量
let a = 'abc';
}
//a 在此處訪問不到
console.log(a);
}
test(true);
終端運行:node demo1
,會報錯:ReferenceError: a is not defined
3.2 常量聲明
const用於常量聲明:
//常量聲明,常量不能進行改變
const name = 'abc';
// name = "xyz"; //再次賦值會報錯
console.log(name);
3.3 模板字符串
反引號(``),是es6模板字符串
1.字符串格式化
將表達式嵌入字符串中進行拼接。用${}
來界定。
//1.字符串拼接
//ES5
var name = 'abc';
console.log("你好,"+name+"歡迎來到十次方世界");
//ES6 模板字符串
let name2 = 'xyz';
//反引號`是esc鍵下面的英文符 ${}界定
console.log(`你好,${name2}歡迎來到十次方世界`);
2.換行
//2.換行
//ES5
var info = "Hi \
man!"
//ES6
var info = `<div>
<span>hello world</span>
</div>`
3.4 函數默認參數
es6為函數參數提供了默認值。在定義函數時便初始化函數參數,以便在參數沒有被傳遞前去使用。
//函數默認參數
function test(num = 200){
console.log(num);
}
test();
test(500);
3.5 箭頭函數
就是函數的快捷寫法。最直觀的三個特點:
1.不需要function關鍵字來創建函數
2.省略return關鍵字
3.繼承當前上下文的 this 關鍵字
//ES5
var add = function(a,b){
return a+b;
}
//ES6
var add2 = (a,b) => {
return a+b;
}
//當函數體中只有return語句時,可簡寫成下面
var add3 = (a,b) => a+b;
console.log(add(100,200));
console.log(add2(100,200));
console.log(add3(100,200));
3.6 對象初始化簡寫
ES6允許在對象之中,直接寫變量。這時,屬性名為變量名, 屬性值為變量的值。
function f(x, y) {
return {x, y};
}
// 等同於
function f(x, y) {
return {x: x, y: y};
}
f(1, 2) // Object {x: 1, y: 2}
//JSON.stringify()把jsonObject轉化為jsonString
console.log(JSON.stringify(people("abc",12)));
除了屬性簡寫,方法也可以簡寫。
var birth = '2000/01/01';
var Person = {
name: '張三',
//等同於birth: birth
birth,
// 等同於hello: function ()...
hello() { console.log('我的名字是', this.name); }
};
3.7 變量的解構賦值
ES6允許按照一定模式,從數組和對象中提取值,對變量進行賦值,這被稱為解構(Destructuring)。本質上,這種寫法屬於“模式匹配”,只要等號兩邊的模式相同,左邊的變量就會被賦予對應的值。
1.數組的解構賦值
let [foo, [[bar], baz]] = [1, [[2], 3]];
foo // 1
bar // 2
baz // 3
let [ , , third] = ["foo", "bar", "baz"];
third // "baz"
let [x, , y] = [1, 2, 3];
x // 1
y // 3
let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]
//解構不成功,變量的值都會等於`undefined`
let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []
//不完全解構,即等號左邊的模式,只匹配一部分的等號右邊的數組
let [a, [b], d] = [1, [2, 3], 4];
a // 1
b // 2
d // 4
//默認值
var [foo = true] = [];
foo // true
[x, y = 'b'] = ['a']; // x='a', y='b'
[x, y = 'b'] = ['a', undefined]; // x='a', y='b'
2.對象的解構賦值
對象的解構與數組有一個重要的不同。數組的元素是按次序排列的,變量的取值由它的位置決定;而對象的屬性沒有次序,變量必須與屬性同名,才能取到正確的值。
//1.屬性名與變量名一致
var { bar, foo } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"
var { baz } = { foo: "aaa", bar: "bbb" };
baz // undefined
//2.屬性名與變量名不一致
var { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"
let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj;
f // 'hello'
l // 'world'
對象的解構賦值的內部機制,是先找到同名屬性,然后再賦給對應的變量。真正被賦值的是后者,而不是前者。
var { foo: baz } = { foo: "aaa", bar: "bbb" };
baz // "aaa"
foo // error: foo is not defined
foo
是匹配的模式,baz
才是變量。真正被賦值的是變量baz
,而不是模式foo
。注意,采用這種寫法時,變量的聲明和賦值是一體的。對於let
和const
來說,變量不能重新聲明,所以一旦賦值的變量以前聲明過,就會報錯。
let foo;
({foo} = {foo: 1}); // 成功
let baz;
({bar: baz} = {bar: 1}); // 成功
let
命令下面一行的圓括號是必須的,否則會報錯。因為解析器會將起首的大括號,理解成一個代碼塊,而不是賦值語句。
解構也可以用於嵌套結構的對象:
var obj = {
p: [
'Hello',
{ y: 'World' }
]
};
var { p: [x, { y }] } = obj;
x // "Hello"
y // "World"
注意,這時p
是模式,不是變量,因此不會被賦值。
3.8 Spread Operator
擴展運算符(...
)組裝對象或數組。
//組裝數組
const color = ['red','green']
const colorful = [...color,'pink']
console.log(colorful) //[ 'red', 'green', 'pink' ]
//組裝對象
const people = {name: 'xyz', address: 'aaaaa'}
const peopleful = {...people, age: 18}
console.log( JSON.stringify(peopleful))//{"name":"xyz","address":"aaaaa","age":18}
3.9 import和export
import導入模塊、export導出模塊。
創建lib.js
let fn0 = function(){
console.log('fno...')
}
export {fn0}
創建demo9.js
import {fn0} from './lib'
fn0()
注意:node(v8.x)本身並不支持import關鍵字,所以我們需要使用babel的命令行工具來執行
babel-node demo9
3.10 Promise對象
所謂Promise
,簡單說就是一個容器,里面保存着某個未來才會結束的事件(通常是一個異步操作)的結果。從語法上說,Promise是一個對象,從它可以獲取異步操作的消息。Promise提供統一的API,各種異步操作都可以用同樣的方法進行處理。
Promise
對象有以下兩個特點:
1.對象的狀態不受外界影響。Promise
對象代表一個異步操作,有三種狀態:Pending
(進行中)、Resolved
(已完成,又稱Fulfilled)和Rejected
(已失敗)。
2.一旦狀態改變,就不會再變,任何時候都可以得到這個結果。Promise
對象的狀態改變,只有兩種可能:從Pending
變為Resolved
和從Pending
變為Rejected
。
基本用法:
ES6規定,Promise對象是一個構造函數,用來生成Promise實例。
var promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 異步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
Promise構造函數接受一個函數作為參數,該函數的兩個參數分別是resolve
和reject
。它們是兩個函數,由JavaScript引擎提供,不用自己部署。
Promise實例生成以后,可以用then
方法分別指定Resolved
狀態和Reject
狀態的回調函數。
promise.then(function(value) {
// success
}, function(error) {
// failure
});
Promise新建后就會立即執行。
let promise = new Promise(function(resolve, reject) {
console.log('Promise');
resolve();
});
promise.then(function() {
console.log('Resolved.');
});
console.log('Hi!');
// Promise
// Hi!
// Resolved
Promise新建后立即執行,所以首先輸出的是“Promise”。然后,then
方法指定的回調函數,將在當前腳本所有同步任務執行完才會執行,所以“Resolved”最后輸出。
下面是一個用Promise對象實現的Ajax操作的例子:
var getJSON = function(url) {
var promise = new Promise(function(resolve, reject){
var client = new XMLHttpRequest();
client.open("GET", url);
client.onreadystatechange = handler;
client.responseType = "json";
client.setRequestHeader("Accept", "application/json");
client.send();
function handler() {
if (this.readyState !== 4) {
return;
}
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error(this.statusText));
}
};
});
return promise;
};
getJSON("/posts.json").then(function(json) {
console.log('Contents: ' + json);
}, function(error) {
console.error('出錯了', error);
});
getJSON
是對XMLHttpRequest對象的封裝,用於發出一個針對JSON數據的HTTP請求,並且返回一個Promise對象。需要注意的是,在getJSON
內部,resolve
函數和reject
函數調用時,都帶有參數。
如果調用resolve
函數和reject
函數時帶有參數,那么它們的參數會被傳遞給回調函數。reject
函數的參數通常是Error對象的實例,表示拋出的錯誤;resolve
函數的參數除了正常的值以外,還可能是另一個Promise實例,表示異步操作的結果有可能是一個值,也有可能是另一個異步操作。