ECMAScript 6新特性簡介

簡介

ECMAScript 6.0(如下簡稱 ES6)是 JavaScript 語言的下一代標準,正式發佈與2015年6月。它的目標,是使得JavaScript語言能夠用來編寫複雜的大型應用程序,成爲企業級開發語言。json

今天咱們將會講解一下ES6中引入的語法新特性。數組

ECMAScript和JavaScript的關係

1996年11月,JavaScript 的創造者 Netscape 公司,決定將 JavaScript 提交給國際標準化組織ECMA.瀏覽器

1997年, ECMA 發佈262號標準文件 ECMAScript 1.0。數據結構

ECMAScript 和 JavaScript 的關係是,前者是後者的規格,後者是前者的一種實現。ecmascript

咱們看一下ECMAScript的發行歷史:函數

從2015年ES2015,也就是ES6發佈以來,ECMAScript以每一年一個版本的發行速度發行到了ES2020。this

後面的文章咱們會講解一下這些新版本的ECMAScript的新特性。spa

let和const

ES6中引入了let和const,是爲了解決以前的var變量的種種問題。code

在ES6以前,JS中變量的做用域有兩種:全局做用域和函數做用域。對象

全局做用域很好理解,咱們在瀏覽器控制檯或者 Node.js 交互終端中開始編寫 JavaScript 時,即進入了所謂的全局做用域。

全局做用域的變量能夠在任何其餘做用域中訪問。

函數做用域就是定義在函數內部的變量,在函數內部均可以訪問到該變量。

這兩種做用域會有一些問題:

  1. 變量提高

var命令會發生」變量提高」現象,即變量能夠在聲明以前使用,值爲undefined.

// var 的狀況 
console.log(foo);  // 輸出undefined 
var foo = 2;
  1. 變量覆蓋

當咱們在函數做用域使用全局變量的時候,若是函數做用域中定義了一樣名字的變量,不論是在哪裏定義的,都會覆蓋掉全局的變量。以下所示:

var tmp = new Date(); 
function f() { 
console.log(tmp); 
if (false) { var tmp = "hello world"; 
} } 
f(); // undefined
  1. 變量泄露

變量泄露的意思是,咱們原本只但願在小範圍做用域使用的變量,結果泄露到了範圍外面,以下所示:

var s = 'hello'; 
for (var i = 0; i < s.length; i++) { 
console.log(s[i]); 
} 
console.log(i); // 5
~~

爲了解決上面兩個問題,ES6引入了let和const。

這兩個都是塊級做用域。不一樣的是const定義的變量初始化以後就不能變化了。

什麼是塊級做用域呢?相似於 if、switch 條件選擇或者 for、while 這樣的循環體便是所謂的塊級做用域,或者更簡單一點使用大括號括起來的就叫作塊級做用域。

塊級做用域的最大好處就是不會產生做用域提高,以下所示:

{
let a = 10;
var b = 1;
}
a // ReferenceError: a is not defined.
b // 1

# 解構賦值

什麼是解構賦值呢?

ES6 容許按照必定模式,從數組和對象中提取值,對變量進行賦值,這被稱爲解構。

以下所示:

let [a, b, c] = [1, 2, 3];
let [ , , third] = ["foo", "bar", "baz"];
let [x, , y] = [1, 2, 3];
let [head, ...tail] = [1, 2, 3, 4];

let [x, y] = [1, 2, 3];

解構賦值還能夠設定默認值,咱們來看下面的幾個例子:

let [foo = true] = [];
foo // true

let [x, y = 'b'] = ['a'];
// x='a', y='b'

let [x, y = 'b'] = ['a', undefined];
// x='a', y='b’

let [x = 1] = [undefined];
x // 1
let [x = 1] = [null];
x // null

若是解構的默認值是一個函數,那麼能夠觸發惰性賦值:

function f() {
console.log('aaa');
}

let [x = f()] = [1];

上面的例子中,f函數將不會被執行。

除告終構變量以外,還能夠結構對象:

let { bar, foo } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"

let { baz } = { foo: "aaa", bar: "bbb" };
baz // undefined

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'

解構還支持嵌套的結構:

let obj = { p: [ 'Hello', { y: 'World' } ] };

let { p: [x, { y }] } = obj;

x // "Hello"
y // "World"

解構賦值有兩個很是重要的做用。

第一就是交換變量:

let x = 1;
let y = 2;
[x, y] = [y, x];

咱們就能夠再也不使用中間變量,直接進行兩個變量值的交互。

第二個做用就是從函數中返回多個值:

// 返回一個數組
function example() { return [1, 2, 3]; }
let [a, b, c] = example();

// 返回一個對象
function example() { return { foo: 1, bar: 2 }; }
let { foo, bar } = example();

//提取JSON數據
let jsonData = { id: 42, status: "OK", data: [867, 5309] };
let { id, status, data: number } = jsonData;

# 數組的擴展

ES6中的Array.from方法用於將下面兩類對象轉爲真正的數組:

* 相似數組的對象(array-like object)
* 可遍歷(iterable)的對象(包括ES6新增的數據結構Set和Map)。

什麼是相似數組對象呢?

所謂相似數組的對象,本質特徵只有一點,即必須有length屬性。所以,任何有length屬性的對象,均可以經過Array.from方法轉爲數組。

下面的變量就是類數組變量:

let arrayLike = { '0': 'a', '1': 'b', '2': 'c', length: 3 };

這個類數組對象怎麼轉換成爲數組呢?

// ES5的寫法
var arr1 = [].slice.call(arrayLike);
// ['a', 'b', 'c']

// ES6的寫法 let arr2 = Array.from(arrayLike);
// ['a', 'b', 'c']

咱們看下一般的使用場景:

// NodeList對象
let ps = document.querySelectorAll('p');
Array.from(ps).forEach(function (p) { console.log(p); });

// arguments對象
function foo() { var args = Array.from(arguments);
// ...
}

什麼是可遍歷對象呢?

只要是部署了Iterator接口的數據結構,都叫作可遍歷對象。

咱們看下下面的例子:

Array.from('hello') // ['h', 'e', 'l', 'l', 'o']
let namesSet = new Set(['a', 'b'])
Array.from(namesSet) // ['a', 'b']

同時還引入了擴展運算符(...),經過擴展運算符,也能夠很方便的轉換爲數組對象:

function foo() { var args = [...arguments]; } // arguments對象
[...document.querySelectorAll('div')] // NodeList對象

Array.from方法還能夠接收第二個參數,用來對數組中的元素進行操做:

Array.from(arrayLike, x => x * x);
// 等同於
Array.from(arrayLike).map(x => x * x);

Array.from([1, 2, 3], (x) => x * x)
// [1, 4, 9]

Array.of方法能夠很方便的建立新的數組:

Array.of(3, 11, 8) // [3,11,8]
Array.of(3) // [3]
Array.of(3).length // 1

Array() // []
Array(3) // [, , ,]
Array(3, 11, 8) // [3, 11, 8]

# 函數的擴展

ES6,能夠支持函數的默認值了:

function log(x, y = 'World') { console.log(x, y); }
function Point(x = 0, y = 0) { this.x = x; this.y = y; }

函數的默認值能夠和解構賦值默認值組合起來使用:

function foo({x, y = 5}) { console.log(x, y); }
foo({}) // undefined, 5
foo({x: 1}) // 1, 5
foo({x: 1, y: 2}) // 1, 2
foo() // TypeError: Cannot read property 'x' of undefined

接下來,咱們看一個複雜的例子:

// 寫法一
function m1({x = 0, y = 0} = {})
{ return [x, y]; }

// 寫法二
function m2({x, y} = { x: 0, y: 0 })
{ return [x, y]; }

咱們來看一下,上面的兩種寫法有什麼不一樣呢?

當函數沒有參數的狀況:

m1() // [0, 0]
m2() // [0, 0]

當x和y都有值的狀況:

m1({x: 3, y: 8}) // [3, 8]
m2({x: 3, y: 8}) // [3, 8]

當x有值,y無值的狀況 :

m1({x: 3}) // [3, 0]
m2({x: 3}) // [3, undefined]

當x和y都無值的狀況:

m1({}) // [0, 0];
m2({}) // [undefined, undefined]
m1({z: 3}) // [0, 0]
m2({z: 3}) // [undefined, undefined]

看出區別了嗎? m1的解構賦值,對於x,y來講是有默認值0的。而m2的解構賦值對於x,y來講是沒有默認值的。

> 本文做者:flydean程序那些事
> 
> 本文連接:[http://www.flydean.com/ecmascript-6-startup/](http://www.flydean.com/ecmascript-6-startup/)
> 
> 本文來源:flydean的博客
> 
> 歡迎關注個人公衆號:「程序那些事」最通俗的解讀,最深入的乾貨,最簡潔的教程,衆多你不知道的小技巧等你來發現!
相關文章
相關標籤/搜索