ES6和ECMAScript2015的關係
標準委員會最終決定,標準在每年的 6 月份正式發佈一次,作爲當年的正式版本。接下來的時間,就在這個版本的基礎上做改動,直到下一年的 6 月份,草案就自然變成了新一年的版本。這樣一來,就不需要以前的版本號了,只要用年份標記就可以了。
ES6 的第一個版本,就這樣在 2015 年 6 月發佈了,正式名稱就是《ECMAScript 2015 標準》(簡稱 ES2015)。2016 年 6 月,小幅修訂的《ECMAScript 2016 標準》(簡稱 ES2016)如期發佈,這個版本可以看作是 ES6.1 版,因爲兩者的差異非常小(只新增了數組實例的includes
方法和指數運算符),基本上是同一個標準。根據計劃,2017 年 6 月發佈 ES2017 標準。
Babel轉碼器
Babel是一個廣泛使用的ES6轉碼器,可以將ES6代碼轉爲ES5代碼,從而在現有的環境執行
// 轉碼前
input.map(item => item + 1);
// 轉碼後
input.map(function (item) {
return item + 1;
});
Babel的配置文件是.babelrc,存放在根目錄下,該文件來設置轉碼規則和插件
{
"presets": [],
"plugins": []
}
命令行轉碼babel-cli
安裝命令如下
$ npm install --global babel-cli
改寫package.json
{
// ...
"devDependencies": {
"babel-cli": "^6.0.0"
},
"scripts": {
"build": "babel src -d lib"
},
}
babel-node命令,提供一個支持ES6的REPL環境,支持Node的REPL環境的所有功能,而且可以直接執行ES6 。
babel-register模塊改寫require命令,加上一個鉤子。每當使用require加載.js .jsx .es .es6後綴名的文件就會先用Babel轉碼。
babel-core模塊,對需要調用Babel的API進行轉碼。
babel-polyfill爲當前環境提供一個墊片,比如Iterator
、Generator
、Set
、Map
、Proxy
、Reflect
、Symbol
、Promise
等全局對象,以及一些定義在全局對象上的方法(比如Object.assign
)進行轉碼。
let和const命令
ES6新增了let命令用來聲明變量,用法類似與var,但所生命的變量在let命令所在的代碼塊內有效。
for循環的計數器模式和使用let命令。
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 10
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 6
不存在變量提升
// var 的情況
console.log(foo); // 輸出undefined
var foo = 2;
// let 的情況
console.log(bar); // 報錯ReferenceError
let bar = 2;
暫時性死區
在代碼塊內,使用lei命令聲明變量之前,該變量都是不可用的
if (true) {
// TDZ開始
tmp = 'abc'; // ReferenceError
console.log(tmp); // ReferenceError
let tmp; // TDZ結束
console.log(tmp); // undefined
tmp = 123;
console.log(tmp); // 123
}
let不允許在相同作用域內,重複聲明同一個變量 。
function func(arg) {
let arg; // 報錯
}
function func(arg) {
{
let arg; // 不報錯
}
}
塊級作用域
ES5只有全局作用域和函數作用域,沒有塊級作用域會導致內層變量可能覆蓋外層變量,用來計數的循環變量泄露爲全局變量。
塊級作用域的出現使得廣泛應用的立即執行函數表達式不必要了IIFE。
// IIFE 寫法
(function () {
var tmp = ...;
...
}());
// 塊級作用域寫法
{
let tmp = ...;
...
}
考慮到環境導致的行爲差異太大,應該避免在塊級作用域內聲明函數。如果確實需要,也應該寫成函數表達式,而不是函數聲明語句。
// 函數聲明語句
{
let a = 'secret';
function f() {
return a;
}
}
// 函數表達式
{
let a = 'secret';
let f = function () {
return a;
};
}
const命令
const聲明一個只讀的常量,一旦聲明,常量的值就不能改變
const的作用域與let命令相同:只在聲明所在的塊級作用域內有效。
const
實際上保證的,並不是變量的值不得改動,而是變量指向的那個內存地址所保存的數據不得改動
const a = [];
a.push('Hello'); // 可執行
a.length = 0; // 可執行
a = ['Dave']; // 報錯
可以使用Object。freeze方法將對象凍結
const foo = Object.freeze({});
// 常規模式時,下面一行不起作用;
// 嚴格模式時,該行會報錯
foo.prop = 123;
變量的解構賦值用途
1.交換變量的值
let x = 1;
let y = 2;
[x, y] = [y, x];
2.從函數返回多個值
// 返回一個數組
function example() {
return [1, 2, 3];
}
let [a, b, c] = example();
// 返回一個對象
function example() {
return {
foo: 1,
bar: 2
};
}
let { foo, bar } = example();
3.函數參數的定義
解構賦值可以方便地將一組參數與變量名對應起來
// 參數是一組有次序的值
function f([x, y, z]) { ... }
f([1, 2, 3]);
// 參數是一組無次序的值
function f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1});
4.提取JSON數據
let jsonData = {
id: 42,
status: "OK",
data: [867, 5309]
};
let { id, status, data: number } = jsonData;
console.log(id, status, number);
// 42, "OK", [867, 5309]
5.函數參數默認值
jQuery.ajax = function (url, {
async = true,
beforeSend = function () {},
cache = true,
complete = function () {},
crossDomain = false,
global = true,
// ... more config
} = {}) {
// ... do stuff
};
6.遍歷Map結構
const map = new Map();
map.set('first', 'hello');
map.set('second', 'world');
for (let [key, value] of map) {
console.log(key + " is " + value);
}
// first is hello
// second is world
// 獲取鍵名
for (let [key] of map) {
// ...
}
// 獲取鍵值
for (let [,value] of map) {
// ...
}
7.輸入模塊的指定方法
const { SourceMapConsumer, SourceNode } = require("source-map");
字符串的擴展