ES6經常使用七大特性

  ES6可謂是對JS語言的一個顛覆性改變,增長了Module改善JS一直被詬病的模塊化、Promise解決異步函數的回調地獄、Class的面相對象編程...vue

  在學習ES6的過程當中,你們或多或少都有看過阮一峯老師的《ECMAScript 6 入門》。這本書把ES6的全部知識點都講解的很詳細,若是有時間,仍是要去仔仔細細的研究一番。這篇博文只是摘錄五個經常使用的特性來說解,話很少說,下面開講:es6

1、let和const命令

一、let:

(1)基本用法vuex

ES6 新增了let命令,用來聲明變量。相似於var,可是所聲明的變量,只在let命令所在的代碼塊內有效。編程

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

 

(2)let在for循環中使用數組

var a = [];
for (var i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[2](); // 10
a[6](); // 10

 

這個例子中,i 由 var 聲明,在全局範圍有效,a 的全部組員裏面的 i 都是指向同一個 i,致使全部組員運行輸出的都是最後一輪的 i 的值。瀏覽器

var a = [];
for (let i = 0; i < 10; i++) {
    a[i] = function () {
        console.log(i);
    }
}
a[2](); // 2
a[6](); // 6

這個例子中, i 由 let 聲明,當前的 i 只在本輪循環有效,全部每次循環的 i 其實都是一個新的變量。
Tips: 每輪循環的 i 都是從新聲明的,JavaScript 引擎內部會記住上一輪循環的值,初始化本輪的 i 時,就在上一輪循環的基礎上進行計算
數據結構

 

(3)for循環的特別之處app

在 for 循環中,設置循環變量的那部分是一個父做用域,而循環內部是一個單獨的子做用域異步

for (let i = 0; i < 3; i++) {
    let i = 'abc';  // 和上一行for循環計數器的i不在同一做用域,因此能夠聲明成功。類比下面要講的function(arg){let arg;}會報錯,就是做用域問題
    console.log(i);
}
// abc
// abc
// abc

 

(4)不能重複聲明async

let 不容許在相同做用域內,重複聲明同一個變量。

function func() {
  var a = 10;
  let a = 1;
}
func(); //Identifier 'a' has already been declared

function func() {
  let a = 10;
  let a = 1;
}
func(); //Identifier 'a' has already been declared
 
function func(arg) {
  let arg; 
}
func(); //Identifier 'arg' has already been declared
 
function func(arg) {
  {
    let arg; 
  }
}
func(); //不報錯

 

(5)不存在變量提高

var 命令會發生「變量提高」現象,即變量能夠在聲明以前使用,值爲 undefined。 let 命令改變了語法行爲,它所聲明的變量必定要在聲明後使用,不然會報錯。

console.log(foo); //undefined
var foo = 2;
console.log(bar); // ReferenceError: bar is not defined
let bar =  2;

 

(6)暫時性死區

ES6規定,若是區塊中存在 let 和 const 命令,這個區塊對這些命令聲明的變量,從一開始就造成了封閉做用域。凡是在聲明以前使用這些變量,就會報錯。這在語法上稱爲 「暫時性死區」。

var tmp = 123;
if(true){
    tmp = 'abc'; // ReferenceError: tmp is not defined
    let tmp;
}

Tips:「暫時性死區」的本質就是:只要一進入當前做用域,所要使用的變量就已經存在了,但不可獲取(不然報錯),只有等到聲明的那一行代碼出現,才能夠獲取和使用。

 
二、const:

const命令的用法和let類似,最大不一樣點就是:const聲明一個只讀的常量。一旦聲明,常量的值就不能改變。

Tips:這個不可改變的是指針,因此對於const聲明的對象和數組仍是能夠改變的。若是真的想將對象凍結,應該使用Object.freeze方法。

 

三、let和const部分補充:

ES5 只有兩種聲明變量的方法:var命令和function命令。

ES6 除了添加let和const命令,另外兩種聲明變量的方法:import命令和class命令。因此,ES6 一共有 6 種聲明變量的方法。

 

頂層對象:在瀏覽器環境指的是window對象,在 Node 指的是global對象。ES5 之中,頂層對象的屬性與全局變量是等價的。

ES6爲了保持兼容性,規定:a. var 命令和 function 命令聲明的全局變量,依舊是頂層對象的屬性。b. let,const,class 命令聲明的全局變量,不屬於頂層對象的屬性。

var a = 1;
window.a; // 1
let b = 2;
window.b; // undefined

2、變量的解構賦值

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

 

一、數組的解構賦值

(1)基本用法

// 以前,爲變量賦值,能夠直接指定值
let a = 1;
let b = 2;
let c = 3;

// ES6中容許這樣
let [a, b, c] = [1, 2, 3];  // 能夠從數組中提取值,按照對應位置,對變量賦值。

 

本質上,這種寫法屬於「模式匹配」,只要等號兩邊的模式相同,左邊的變量就會被賦予對應的值。下面是一些使用嵌套數組進行解構的例子。

let [foo, [[bar], baz]] = [1, [[2], 3]];
foo // 1
bar // 2
baz // 3
 
let [ , , third] = ["foo", "bar", "baz"];
third // "baz"
 
let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]
 
let [x, y, ...z] = ['a'];
x // "a"
y // undefined  - 若是解構不成功,變量的值就等於 undefined
z // []

 若是解構不成功,變量的值就等於undefined

 

上面一種狀況是解構不成功的;另外一種狀況是不徹底解構,即等號左邊的模式,只匹配一部分的等號右邊的數組。這種狀況下,解構依然能夠成功。

let [a, [b], d] = [1, [2, 3], 4];
a // 1
b // 2
d // 4

上面兩個例子,都屬於不徹底解構,可是能夠成功。

 

若是等號的右邊不是數組,那麼將會報錯。

let [foo] = 1;
let [foo] = false;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {};

 

(2)默認值

解構賦值容許指定默認值。例如:

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

 

Tips:ES6 內部使用嚴格相等運算符(===)去判斷一個位置是否有值因此,只有當一個數組成員嚴格等於 undefined ,默認值纔會生效。例如:

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

let [x = 1] = [null];
x // null - 默認值就不會生效,由於null不嚴格等於undefined

 

默認值能夠引用解構賦值的其餘變量,但該變量必須已經聲明。

let [x = 1, y = x] = [1, 2];
x;//1
y;//2
 
let [x = y, y = 1] = [];// ReferenceError: y is not defined -- let的暫時性死區
let [x = y, y = 1] = [1, 2];

 

二、對象的解構賦值

(1)基本用法

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

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

 

對象的解構與數組的解構,一個重要的不一樣點在於: 數組元素是按次序排列的,變量的取值由它的位置決定;而對象的屬性沒有次序,變量名與屬性同名,才能取到正確的值。

若是沒有與變量名對應的屬性名,致使取不到值,最後等於undefined。

 

若是變量名和屬性名不同,必須寫才下面這樣:

let { 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 { foo: foo, bar: bar } = { foo: "aaa", bar: "bbb" };

 也就是說,對象的解構賦值的內部機制,是先找到同名屬性,而後再賦給對應的變量。真正被賦值的是後者,而不是前者。

 

let { foo: baz } = { foo: "aaa", bar: "bbb" };
baz // "aaa"
foo // error: foo is not defined

 上面代碼中,foo是匹配的模式,baz纔是變量。真正被賦值的是變量baz,而不是模式foo

 

(2)默認值

對象的解構也能夠指定默認值。默認值生效的條件是對象的屬性值嚴格等於 undefined。

let {x, y = 5} = {x: 1};
x;// 1
y;// 5

let { message: msg = 'Something went wrong' } = {};
msg;//"Something went wrong"

 

Tips:若是要將一個已經聲明的變量用於解構賦值,須要注意:

let x;
{x} = {x:1};
//上面的代碼會報錯,由於JavaScript引擎會將 {x} 理解爲一個代碼塊,從而發生語法錯誤。只有不將大括號寫在行首,避免JavaScript將其解釋爲代碼塊,才能解決這個問題。
 
//正確的寫法,將須要解構的部分用括號()包起來
let x;
({x} = {x:1});

 

三、字符串的解構賦值

字符串也能夠解構賦值。這是由於此時,字符串被轉換成了一個相似數組的對象。

const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"

 

相似數組的對象都有一個 length 屬性,所以還能夠對這個屬性解構賦值。

let {length: len} = 'hello';
len;// 5

 

四、數值和布爾值的解構賦值

解構賦值時,若是等號右邊是數值和布爾值,則會先轉化爲對象:

let {toString: s} = 123;
s === Number.prototype.toString // true

let {toString: s} = true;
s === Boolean.prototype.toString // true

上面代碼中,數值和布爾值的包裝對象都有 toString 屬性,所以變量 s 均可以取到值。

 

解構賦值的規則是:只要等號右邊的值不是對象或數組,就先將其轉化爲對象。 因爲 undefined 和 null 沒法轉化爲對象,因此對他們進行解構賦值都會報錯。

 

五、函數參數的解構賦值
function add([x, y]){
   return x + y;
}
 
add([1, 2]); // 3
 
[[1, 2], [3, 4]].map(([a, b]) => a + b);
// [ 3, 7 ]

 上面代碼中,函數 add 的參數看似是一個數組,但在傳入參數時,數組參數就解構爲變量 x 和 y。對於函數內部代碼來講,參數就是 x 和 y。

 

函數參數的解構也可使用默認參數:

function move({x=0, y=0}={}) {
  return [x, y];
}
move({x:3,y:8});// [3, 8]
move({x:3});// [3, 0]
move({});// [0, 0]
move();// [0, 0]

上例中,函數 move 的參數是一個對象,經過對這個對象進行解構,獲得變量 x 和 y 的值。若是解構失敗,x 和 y 等於默認值。

 

再看下面這種寫法:

function move({x, y} = { x: 0, y: 0 }) {
  return [x, y];
}
 
move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, undefined]
move({}); // [undefined, undefined]
move(); // [0, 0]

上面的代碼是爲函數 move 的參數指定默認值,而不是爲變量 x 和 y 指定默認值。

 

六、解構的用途

(1)交換變量的值

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

 

(2)從函數返回多個值
函數只能返回一個值,若是要返回多個值,只能將它們放在數組或對象裏面返回。有了解構賦值,取出這些值就很是方便。

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

 

(3)函數參數的定義
解構賦值能夠方便的將一組參數與變量名對應起來。

//參數是一組有序值
function f([x, y, z]) {}
f([1, 2, 3]);
 
//參數是一組無序值
function f({x, y, z}) {}
f({x: 1, y: 2, z: 3});

 

(4)提取JSON數據

let data = {
    id: 1,
    status: 'ok',
    data: [867, 5612]
};
let {id, status, data:number} = data;
console.log(id, status, number);// 1 "ok"  [867, 5612]

 

 (5)遍歷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) {}

3、函數的默認參數

一、基本用法

ES6 以前,不能直接爲函數的參數指定默認值,只能採用變通的方法。

function log(x, y) {
  y = y || 'World';
  console.log(x, y);
}

log('Hello') // Hello World
log('Hello', 'China') // Hello China
log('Hello', '') // Hello World

上面代碼檢查函數log的參數y有沒有賦值,若是沒有,則指定默認值爲World。這種寫法的缺點在於,若是參數y賦值了,可是對應的布爾值爲false,則該賦值不起做用。就像上面代碼的最後一行,參數y等於空字符,結果被改成默認值。


爲了不這個問題,一般須要先判斷一下參數y是否被賦值,若是沒有,再等於默認值。

if (typeof y === 'undefined') {
  y = 'World';
}

 

ES6 容許爲函數的參數設置默認值,即直接寫在參數定義的後面。

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

log('Hello') // Hello World
log('Hello', 'China') // Hello China
log('Hello', '') // Hello -- 上面說過,ES6 內部使用嚴格相等運算符(===),判斷一個位置是否有值。因此,只有當一個數組成員嚴格等於 undefined ,默認值纔會生效。

 

二、與解構賦值默認值結合使用
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

上面代碼只使用了對象的解構賦值默認值,沒有使用函數參數的默認值。只有當函數foo的參數是一個對象時,變量x和y纔會經過解構賦值生成。

若是函數foo調用時沒提供參數,變量x和y就不會生成,從而報錯。

 

經過提供函數參數的默認值,就能夠避免這種狀況。

function foo({x, y = 5} = {}) {
  console.log(x, y);
}

foo() // undefined 5

 

下面是另外一個解構賦值默認值的例子:

function fetch(url, { body = '', method = 'GET', headers = {} }) {
  console.log(method);
}

fetch('http://example.com', {})
// "GET"

fetch('http://example.com')
// 報錯

上面代碼中,若是函數fetch的第二個參數是一個對象,就能夠爲它的三個屬性設置默認值。


這種寫法不能省略第二個參數,若是結合函數參數的默認值,就能夠省略第二個參數。這時,就出現了雙重默認值。

function fetch(url, { body = '', method = 'GET', headers = {} } = {}) {
  console.log(method);
}

fetch('http://example.com')
// "GET"

上面代碼中,函數fetch沒有第二個參數時,函數參數的默認值就會生效,而後纔是解構賦值的默認值生效,變量method纔會取到默認值GET。

 

所以,與解構賦值默認值結合使用時,切記,函數要定義默認參數,防止函數不傳參時報錯。

4、模板字符串

模板字符串是加強版的字符串,用反引號 (`) 標識。它能夠當普通字符串使用,也能夠用來定義多行字符串,或者在字符串中嵌入變量。

 

一、基本用法
let greeting = `\`Yo\` World!`;  // `Yo` World -- 使用反斜槓轉義反引號

// 多行字符串
$('#result').append(`
  There are <b>${basket.count}</b> items
   in your basket, <em>${basket.onSale}</em>
  are on sale!
`);

Tips:
a. 若是在模板字符串中須要使用反引號,則前面須要使用反斜槓轉義。
b. 若是使用模板字符串表示多行字符串,全部的空格和縮進都會被保留在輸出之中。

 

二、在模板字符串使用變量

(1) 在模板字符串中嵌入變量,須要將變量名寫在 ${} 之中。
(2) 大括號內部能夠放入任意的JavaScript表達式,能夠進行運算,以及引用對象屬性。
(3) 模板字符串之中還能調用函數。
(4) 若是大括號中的值不是字符串,將按照通常的規則轉爲字符串。如: 若是大括號中是一個對象,將默認調用對象的 toString 方法。
(5) 若是模板字符串中的變量沒有聲明將會報錯。
(6) 若是大括號內部是一個字符串,將原樣輸出。

//普通字符串
`In JavaScript '\n' is a line-feed.`;
 `Hello ${'World'}`; // "Hello World"

//字符串中嵌入變量
let name = "Bob", time = "today";
console.log(`Hello ${name}, how are you ${time}?`); //  Hello Bob, how are you today?

//字符串中嵌入 JavaScript 表達式
`${x} + ${y} = ${x + y}`;// "1 + 2 = 3"
`${x} + ${y * 2} = ${x + y * 2}`;// "1 + 4 = 5"

let obj = {x: 1, y: 2};
`${obj.x + obj.y}`;// "3"

// 字符串中嵌入函數
function fn(){
    return "hello world"
}
`foo ${fn()} bar`;// "foo hello world bar"

// 字符串中嵌入對象
`${obj}`;// "[object Object]"

// 字符串中嵌入未聲明的變量
 `Hello, ${place}`;// ReferenceError: place is not defined 

5、箭頭函數

 ES6 容許使用 「箭頭」 (=>)定義函數。

一、基本用法
var f = v => v;
//等同於
var f = function (v) {
    return v;
}

=> 前面的部分是函數的參數,=> 後面的部分是函數的代碼塊。

 

(1)若是箭頭函數不須要參數或須要多個參數,就使用一個圓括號表明參數部分。

var f = () => 5;
//等同於
var f = function (v) {
    return 5
};

var sum = (num1, num2) =>  num1 + num2;
//等同於
var sum = function(num1, num2){
    return num1 + num2;
}

 

(2)若是箭頭函數的代碼塊部分多於一條語句,就要使用大括號將它們括起來,而且使用 return 語句返回。

var sum = (num1,num2) => { return num1 + num2; }

 

(3)因爲大括號會被解釋爲代碼塊,因此若是箭頭函數直接返回一個對象,就必須在對象外面加上括號,不然會報錯。

// 報錯
let getTempItem = id => { id: id, name: "Temp" };

// 不報錯
let getTempItem = id => ({ id: id, name: "Temp" });
getTempItem(1);//{id: 1, name: "Temp"}

let getTempItem = id => {
    return { id: id, name: "Temp" };
}
getTempItem(1);// {id: 1, name: "Temp"}

 

(4)箭頭函數內部,能夠嵌套箭頭函數

function insert (value) {
    return {into: function (array){
            return {after: function (afterValue) {
                        array.splice(array.indexOf(ahterValue)+1, 0, value);
                        return array;
                    }
               }
        }    
    }
}
insert(2).into([1, 3]).after(1); //[1, 2, 3]

//使用箭頭函數改寫
let insert = (value) => ({into: (array) => ({after: (afterValue) => {
            array.splice(array.indexOf(afterValue)+1, 0, value);
            return array;
        }
    })
});

 

二、箭頭函數與變量解構結合使用
const full = ({ first, last }) => first + ' ' + last;
full({first: 1, last: 2});// "1 2"
// 等同於 function full(person) { return person.first + ' ' + person.last; } full({first: 1, last: 2});// "1 2"

 

三、rest 參數與箭頭函數結合
const numbers = (...nums) => nums;
numbers(1,2,3,4);//  [1, 2, 3, 4]

const headAndTail = (head, ...tail) => [head, tail];
headAndTail(1,2,3,4);// [1,[2,3,4]]

 

四、箭頭函數的優勢

(1)簡化代碼

const isEven = n => n%2 == 0;
isEven(3);// false
isEven(4);// true

 

(2)簡化回調函數

[1, 2, 3].map( x => x*x ); //[1, 4, 9]
[3,2,5].sort((a, b) => a - b); // [2, 3, 5]

 

五、箭頭函數的注意點——this

ES5中 this 的指向是可變的,可是箭頭函數中 this 指向固定化。

var  handler = {
    id: '123',
    init: function () {
        document.addEventListener('click', 
            event => this.doSomethisng(event.type), false);
    },
    doSomethisng: function (type) {
        console.log('Handling ' + type + ' for ' + this.id);
    }
};
handler.init();  //Handling click for 123  -- this指向handle -- this是屬於函數的一個對象,誰調用指向誰(es5中)

 

 this 指向的固定化,並非由於箭頭函數內部有綁定 this 的機制,實際緣由是箭頭函數內部根本沒有本身的this,致使內部的this 就是外層代碼塊的 this 。

 

 箭頭函數的this是比較難理解的,但只要能想象到他是如何從ES5轉化來的,就能夠徹底理解它的做用對象。 箭頭函數轉成 ES5 的代碼以下:

// ES6
function foo() {
  setTimeout(() => {
    console.log('id:', this.id);
  }, 100);
}

// ES5
function foo() {
  var _this = this;

  setTimeout(function () {
    console.log('id:', _this.id);
  }, 100);
}

 

Tips:

(1) 函數體內的 this 對象,就是定義時所在的對象,而不是使用時所在的對象。
(2) 不能夠當構造函數,即不可使用 new 命令,由於它沒有 this,不然會拋出一個錯誤。
(3) 箭頭函數沒有本身的 this,因此不能使用 call()、apply()、bind() 這些方法去改變 this 指向。
(4) 不可使用arguments 對象,該對象在函數體內不存在。若是要用,可使用rest參數代替。

6、數組的擴展(擴展運算符) 

 一、擴展運算符

(1)基本用法

  擴展運算符(spread)是三個點(...)。它比如 rest 參數的逆運算,將一個數組轉爲用逗號分隔的參數序列。

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>]

 

  該運算符主要用於函數調用。擴展運算符與正常的函數參數能夠結合使用,很是靈活。

function push(array, ...items) {
  array.push(...items);
}

function add(x, y) {
  return x + y;
}

const numbers = [4, 38];
add(...numbers) // 42

function f(v, w, x, y, z) { }
const args = [0, 1];
f(-1, ...args, 2, ...[3]);

 

若是擴展運算符後面是一個空數組,則不產生任何效果。 [...[], 1] // [1] 

 

注意,擴展運算符若是放在括號中,JavaScript 引擎就會認爲這是函數調用,不然就會報錯。

(...[1,2])
// Uncaught SyntaxError: Unexpected number

console.log((...[1,2]))
// Uncaught SyntaxError: Unexpected number

console.log(...[1,2])  // 不會報錯 

 

二、替代函數的apply方法

因爲擴展運算符能夠展開數組,因此再也不須要apply方法,將數組轉爲函數的參數了。

// ES5 的寫法
function f(x, y, z) {
  // ...
}
var args = [0, 1, 2];
f.apply(null, args);

// ES6的寫法
function f(x, y, z) {
  // ...
}
let args = [0, 1, 2];
f(...args);

 

三、擴展運算符引用

(1)複製數組

數組是複合的數據類型,直接複製的話,只是複製了指向底層數據結構的指針(淺拷貝),而不是克隆一個全新的數組。

如何實現深拷貝呢?下面看看ES5和ES6的實現:

// ES5
const a1 = [1, 2];
const a2 = a1.concat();

// ES6
const a1 = [1, 2];
// 寫法一
const a2 = [...a1];
// 寫法二
const [...a2] = a1;

a2[0] = 2;
a1 // [1, 2]

 

(2)合併數組

const arr1 = ['a', 'b'];
const arr2 = ['c'];
const arr3 = ['d', 'e'];

// ES5 的合併數組
arr1.concat(arr2, arr3);
// [ 'a', 'b', 'c', 'd', 'e' ]

// ES6 的合併數組
[...arr1, ...arr2, ...arr3]
// [ 'a', 'b', 'c', 'd', 'e' ]

 

不過,這兩種方法都是淺拷貝,使用的時候須要注意。若是修改了原數組的成員,會同步反映到新數組。

const a1 = [{ foo: 1 }];
const a2 = [{ bar: 2 }];

const a3 = a1.concat(a2);
const a4 = [...a1, ...a2];

a3[0] === a1[0] // true
a4[0] === a1[0] // true

 

(3)與解構賦值結合

const [first, ...rest] = [1, 2, 3, 4, 5];
first // 1
rest  // [2, 3, 4, 5]

const [first, ...rest] = [];
first // undefined
rest  // []

const [first, ...rest] = ["foo"];
first  // "foo"
rest   // []

 

注意:若是將擴展運算符用於數組賦值,只能放在參數的最後一位,不然會報錯。

const [...butLast, last] = [1, 2, 3, 4, 5]; // 報錯

const [first, ...middle, last] = [1, 2, 3, 4, 5]; // 報錯

 

(4)字符串

擴展運算符能夠將字符串和函數參數arguments轉成真正的數組

[...'hello']  // [ "h", "e", "l", "l", "o" ]

function (){
   let arr = [...arguments];
}

7、對象的擴展

一、屬性的簡潔表示法

ES6 容許直接寫入變量和函數,做爲對象的屬性和方法。這樣的書寫更加簡潔。

const foo = 'bar';
const baz = {foo};
baz // {foo: "bar"}

// 等同於
const baz = {foo: foo};

 

上面代碼代表,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}

 

方法簡寫:

const o = {
  method() {
    return "Hello!";
  }
};

// 等同於
const o = {
  method: function() {
    return "Hello!";
  }
};

 

 CommonJS 模塊輸出一組變量,就很是合適使用簡潔寫法。

let ms = {};

function getItem (key) {
  return key in ms ? ms[key] : null;
}

function setItem (key, value) {
  ms[key] = value;
}

function clear () {
  ms = {};
}

module.exports = { getItem, setItem, clear };
// 等同於
module.exports = {
  getItem: getItem,
  setItem: setItem,
  clear: clear
};

 

二、屬性名錶達式

JavaScript 定義對象的屬性,有兩種方法。 

// 方法一
obj.foo = true;

// 方法二
obj['a' + 'bc'] = 123;

上面代碼的方法一是直接用標識符做爲屬性名,方法二是用表達式做爲屬性名,這時要將表達式放在方括號以內。

可是,若是使用字面量方式定義對象(使用大括號),在 ES5 中只能使用方法一(標識符)定義屬性。

var obj = {
  foo: true,
  abc: 123
};

 

ES6 容許字面量定義對象時,用方法二(表達式)做爲對象的屬性名,即把表達式放在方括號內。

let propKey = 'foo';

let obj = {
  [propKey]: true,
  ['a' + 'bc']: 123
};

 

表達式還能夠用於定義方法名。好比咱們熟悉的Vuex定義Mutation就是推薦這種方式:

// mutation-types.js
export const SOME_MUTATION = 'SOME_MUTATION'

// store.js
import Vuex from 'vuex'
import { SOME_MUTATION } from './mutation-types'

const store = new Vuex.Store({
  state: { ... },
  mutations: {
    // 咱們可使用 ES2015 風格的計算屬性命名功能來使用一個常量做爲函數名
    [SOME_MUTATION] (state) {
      // mutate state
    }
  }
})

 

var test = {            
  'attr0' : 'attr1',            
  'attr1' : 'attr2',            
  'attr2' : 'attr3',            
  'attr3' : 'I'm here',          
}                  

// 輸出: I'm here  , 方括號能夠接受任何JS語句,最後都被轉化爲字符串。利用這個字符串在key-value集合中尋址。
console.log(test[test[test[test['attr0']]]]);

 

至此,先是粗略的講解了一下ES6的七個經常使用的知識點。

另外,ES6的Promise對象、async函數、Set和Map數據結構、Class、Module也都是比較具備顛覆性的改進,每個都能滿滿的寫一篇,待續...

相關文章
相關標籤/搜索