ES6新增特性(二)

七、解構(gòu)

7.1 解構(gòu)的實(shí)用

在 ECMAScript 5 或更早的版本中,從對(duì)象或數(shù)組中獲取特定的數(shù)據(jù)并賦值給本地變量需要書(shū)寫(xiě)很多并且相似的代碼。例如:

let options = {
        repeat: true,
        save: false
   };

// 從對(duì)象中提取數(shù)據(jù)

let repeat = options.repeat,
    save = options.save;

這段代碼反復(fù)地提取在 options 上存儲(chǔ)地屬性值并將它們傳遞給同名的本地變量。雖然這些看起來(lái)不是那么復(fù)雜,不過(guò)想象一下如果你的一大批變量有著相同的需求,你就只能一個(gè)一個(gè)地賦值。而且,如果你需要從對(duì)象內(nèi)部嵌套的結(jié)構(gòu)來(lái)查找想要的數(shù)據(jù),你極有可能為了一小塊數(shù)據(jù)而訪問(wèn)了整個(gè)數(shù)據(jù)結(jié)構(gòu)。

這也是 ECMAScript 6 給對(duì)象和數(shù)組添加解構(gòu)的原因。當(dāng)你想要把數(shù)據(jù)結(jié)構(gòu)分解為更小的部分時(shí),從這些部分中提取數(shù)據(jù)會(huì)更容易些。很多語(yǔ)言都能使用精簡(jiǎn)的語(yǔ)法來(lái)實(shí)現(xiàn)解構(gòu)操作。ECMAScript 6 解構(gòu)的實(shí)際語(yǔ)法或許你已經(jīng)非常熟悉:對(duì)象和數(shù)組字面量。

7.2 對(duì)象解構(gòu)

7.2.1 對(duì)象解構(gòu)的基本形式

對(duì)象結(jié)構(gòu)的語(yǔ)法就是在賦值語(yǔ)句的左側(cè)使用類似對(duì)象字面量的結(jié)構(gòu)。

let node = {
        type: "Identifier",
        name: "foo"
    };
//這里就相當(dāng)于聲明了兩個(gè)變量: type = node.type;  name:node.name
let { type, name } = node;

console.log(type);      // "Identifier"
console.log(name);      // "foo"

在上面的結(jié)構(gòu)中必須要初始化。否則會(huì)出現(xiàn)語(yǔ)法錯(cuò)誤。

// 語(yǔ)法錯(cuò)誤!
var { type, name };

// 語(yǔ)法錯(cuò)誤!
let { type, name };

// 語(yǔ)法錯(cuò)誤!
const { type, name };

7.2.2 解構(gòu)賦值表達(dá)式

如果聲明的變量想改變他們的值,也可以使用解構(gòu)表達(dá)式。

<script type="text/javascript">
    let node = {
      type: "Identifier",
      name: "foo"
    },
    type = "Literal",
    name = 5;

  //注意:此處必須要在圓括號(hào)內(nèi)才能使用解構(gòu)表達(dá)式
  ({type, name} = node);

  console.log(type);      // "Identifier"
  console.log(name);      // "foo""
</script>

7.2.3 對(duì)象解構(gòu)時(shí)的默認(rèn)值

如果賦值號(hào)右邊的對(duì)象中沒(méi)有與左邊變量同名的屬性,則左邊的變量會(huì)是 undefined

let node = {
        type: "Identifier",
        name: "foo"
    };
//因?yàn)閚ode中沒(méi)有叫value的屬性,所以valued的值將會(huì)是undefined
let { type, name, value } = node;

console.log(type);      // "Identifier"
console.log(name);      // "foo"
console.log(value);     // undefined

不過(guò)我們也可以手動(dòng)指定他的默認(rèn)值。(這個(gè)和函數(shù)的參數(shù)默認(rèn)值很像)

<script type="text/javascript">
    let node = {
        type: "Identifier",
        name: "foo"
    };
    //手動(dòng)添加value的默認(rèn)值為3
    let { type, name, value = 3} = node;

    console.log(type);      // "Identifier"
    console.log(name);      // "foo"
    console.log(value);     // 3
</script>

7.2.4 賦值給不同的變量名

在前面的操作中,都是把對(duì)象的屬性值,賦值給同名變量。

其實(shí)也可以賦值給不同名的變量。

<script type="text/javascript">
    let node = {
        type: "Identifier",
        name: "foo"
    };
    // localType才是要定義的新的變量。  type是node的屬性
    let {type: localType, name: localName} = node;

    console.log(localType);     // "Identifier"
    console.log(localName);     // "foo"
</script>

注意:冒號(hào)后面才是要定義的新的變量,這個(gè)和我們的對(duì)象字面量不太一樣!

這個(gè)地方也可以使用默認(rèn)值。

let node = {
        type: "Identifier"
    };

let { type: localType, name: localName = "bar" } = node;

console.log(localType);     // "Identifier"
console.log(localName);     // "bar"

7.3 數(shù)組解構(gòu)

7.3.1 數(shù)組解構(gòu)基本語(yǔ)法

數(shù)據(jù)解構(gòu)的語(yǔ)法和對(duì)象解構(gòu)看起來(lái)類似,只是將對(duì)象字面量替換成了數(shù)組字面量,而且解構(gòu)操作的是數(shù)組內(nèi)部的位置(索引)而不是對(duì)象中的命名屬性,例如:

let colors = [ "red", "green", "blue" ];
let [ firstColor, secondColor ] = colors;

console.log(firstColor);        // "red"
console.log(secondColor);       // "green"

如果只想取數(shù)組中的某一項(xiàng),則可以不用命名。

let colors = [ "red", "green", "blue" ];
//只取數(shù)組中的第三項(xiàng)。
let [ , , thirdColor ] = colors;

console.log(thirdColor);        // "blue"

7.3.2 解構(gòu)表達(dá)式

你可以想要賦值的情況下使用數(shù)組的解構(gòu)賦值表達(dá)式,但是和對(duì)象解構(gòu)不同,沒(méi)必要將它們包含在圓括號(hào)中,例如:

let colors = [ "red", "green", "blue" ],
    firstColor = "black",
    secondColor = "purple";

[ firstColor, secondColor ] = colors;  //可以不用加括號(hào)。當(dāng)然添加也不犯法

console.log(firstColor);        // "red"
console.log(secondColor);       // "green"

數(shù)組解構(gòu)表達(dá)式有一個(gè)很常用的地方,就是交換兩個(gè)變量的值。在以前一般定義一個(gè)第三方變量進(jìn)行交換,例如下面的代碼:

<script type="text/javascript">
    let a = 3,
        b = 4,
        temp;
    temp = a;
    a = b;
    b = temp;
    console.log(a);
    console.log(b)
</script>

那么在ES6中完全可以拋棄第三方變量這種方式,使用我們的數(shù)組解構(gòu)表達(dá)式

<script type="text/javascript">
    let a = 3,
        b = 4;
    //左側(cè)和前面的案例是一樣的,右側(cè)是一個(gè)新創(chuàng)建的數(shù)組字面量。
    [a, b] = [b, a];
    console.log(a);
    console.log(b)
</script>

八、新的基本類型:Symbol

以前我們有5種基本數(shù)據(jù)類型:Number、String、Boolean、Null、Undefined

ES6新增了一種新的數(shù)據(jù)類型:Symbol

在ES5之前我們都沒(méi)辦法創(chuàng)建私有變量,只能想辦法去封裝。symbol 來(lái)創(chuàng)建私有成員,這也是 JavaScript 開(kāi)發(fā)者長(zhǎng)久以來(lái)期待的一項(xiàng)特性。

8.1 創(chuàng)建Symbol

Symbol在基本數(shù)據(jù)類型中是比較特別的。我們以前的都可以用字面量去創(chuàng)建基本數(shù)據(jù)類型的數(shù)據(jù),但是Symbol卻不可以使用字面量的是形式去創(chuàng)建。

我們可以使用symbol全局函數(shù)來(lái)創(chuàng)建Symbol。

<script type="text/javascript">
    let firstName = Symbol();   //創(chuàng)建一個(gè)Symbol
    let person = {};

    person[firstName] = "張三";
    console.log(person[firstName]);     // "張三"
</script>

說(shuō)明:上面的代碼中,firstName 作為 symbol 類型被創(chuàng)建并賦值給 person 對(duì)象以作其屬性。每次訪問(wèn)這個(gè)屬性時(shí)必須使用該 symbol 。

在創(chuàng)建Symbol的時(shí)候,也可以傳入字符串,這個(gè)字符串也僅僅是在調(diào)試輸出的時(shí)候方便,實(shí)際沒(méi)有啥用處。

<script type="text/javascript">
    var s1 = Symbol("abc");
    var s2 = Symbol("abc");
    console.log(s1 == s2); //false
</script>

注意:任意兩個(gè)Symbol都不會(huì)相等,即使創(chuàng)建他們的時(shí)候使用了相同的參數(shù)。

8.2 識(shí)別Symbol

既然 symbol 是基本類型,你可以使用 typeof 操作符來(lái)判斷變量是否為 symbol 。ECMAScript 6 拓展了 typeof 使其操作 symbol 時(shí)返回 "symbol"。例如:

let symbol = Symbol();
console.log(typeof symbol);         // "symbol"

8.3 Symbol作為屬性名

由于每一個(gè)Symbol值都是不相等的,這意味著Symbol值可以作為標(biāo)識(shí)符,用于對(duì)象的屬性名,就能保證不會(huì)出現(xiàn)同名的屬性。這對(duì)于一個(gè)對(duì)象由多個(gè)模塊構(gòu)成的情況非常有用,能防止某一個(gè)鍵被不小心改寫(xiě)或覆蓋。
var mySymbol = Symbol();

// 第一種寫(xiě)法

var a = {};

a[mySymbol] = 'Hello!';

// 第二種寫(xiě)法

var a = {

    [mySymbol]: 'Hello!'
}

以上兩種寫(xiě)法都是相同的結(jié)果

注意:

  1. symbol作為對(duì)象的屬性的時(shí)候,只能使用 [ ] 去訪問(wèn),不能使用點(diǎn)去訪問(wèn)。

  2. symbol作為對(duì)象的屬性名使用的時(shí)候,該屬性還是公開(kāi)屬性,不是私有屬性。但是這個(gè)時(shí)候使用for... in和for...of時(shí)無(wú)法遍歷到這個(gè)symbol屬性的。

8.4 Symbol屬性名的遍歷

Symbol 作為屬性名,該屬性不會(huì)出現(xiàn)在for...in循環(huán)中,也不會(huì)被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()返回。但是,它也不是私有屬性,有一個(gè)Object.getOwnPropertySymbols方法,可以獲取指定對(duì)象的所有 Symbol 屬性名。

看下面的代碼

<script type="text/javascript">
    var obj = {};
    var a = Symbol('a');
    var b = Symbol('b');

    obj[a] = 'Hello';
    obj[b] = 'World';
    // 返回obj對(duì)象所有Symbol類型的屬性名組成的數(shù)組。
    var objectSymbols = Object.getOwnPropertySymbols(obj);
    console.log(objectSymbols)  //[Symbol(a), Symbol(b)]
</script>

看下面的代碼

var obj = {};

var foo = Symbol("foo");
obj[foo] = "lisi";
for (var i in obj) {
  console.log(i); // 無(wú)輸出 。   因?yàn)楸闅v不到Symbol型的屬性 
}

Object.getOwnPropertyNames(obj);// []   只能拿到非Symbol類型的屬性

Object.getOwnPropertySymbols(obj) //[Symbol(foo)]

還有一個(gè)新API可以拿到所有類型的屬性,包括常規(guī)和Symbol型的。

Reflect.ownKeys

let obj = {
  [Symbol('my_key')]: 1,
  enum: 2,
  nonEnum: 3
};

Reflect.ownKeys(obj);//  ["enum", "nonEnum", Symbol(my_key)]

說(shuō)明:

  1. 由于以 Symbol 值作為名稱的屬性,不會(huì)被常規(guī)方法遍歷得到。我們可以利用這個(gè)特性,為對(duì)象定義一些非私有的、但又希望只用于內(nèi)部的方法。

8.5 Symbol.for(字符串)和Symbol.keyFor(symbol類型的值)

一、Symbol.for(字符串參數(shù)):在全局環(huán)境中搜索 以該字符串作為參數(shù)的Symbol值,如果搜到則返回這個(gè)sybol,如果搜不到則創(chuàng)建一個(gè)Symbol,并把它注冊(cè)在全局環(huán)境中。

    <script type="text/javascript">
        //第一次搜不到,則新創(chuàng)建一個(gè)返回,并在全局環(huán)境(window)中注冊(cè)
        var a = Symbol.for("foo");
        //第二次搜到上次創(chuàng)建的
        var b = Symbol.for("foo");
        console.log(a === b);  //因?yàn)閮纱嗡训降氖峭粋€(gè)Symbol,所以此處是true
    </script>

Symbol.for()和Symbol()都可以創(chuàng)建Symbol類型的數(shù)據(jù)。

二者區(qū)別:

  1. Symbol.for()對(duì)同樣的字符串,每次得到結(jié)果肯定是一樣的。因?yàn)槎际菑娜汁h(huán)境中搜索。
  2. Symbol()則不會(huì)有搜索的過(guò)程,每次都是一個(gè)全新的不同的symbol,而且也不會(huì)向全局環(huán)境中注冊(cè)。

看下面的代碼

<script type="text/javascript">
   var a = Symbol("foo");
   var b = Symbol.for("foo");
   console.log(a == b); //false
</script>

二、Symbol.keyFor(symbol):返回一個(gè)已經(jīng)全局注冊(cè)的symbol的"key"。

<script type="text/javascript">
    var a = Symbol("foo");
    var b = Symbol.for("foo");
    console.log(Symbol.keyFor(a)); // undefined.   因?yàn)閍沒(méi)有向全局環(huán)境中注冊(cè),所以是undefinded
    console.log(Symbol.keyFor(b)); // foo
</script>

九、Set數(shù)據(jù)結(jié)構(gòu)

JavaScript 在絕大部分歷史時(shí)期內(nèi)只有一種集合類型,那就是數(shù)組。數(shù)組在 JavaScript 中的使用方式和其它語(yǔ)言很相似,但是其它集合類型的缺乏導(dǎo)致數(shù)組也經(jīng)常被當(dāng)作隊(duì)列(queues)和棧(stacks)來(lái)使用。

因?yàn)閿?shù)組的索引只能是數(shù)字類型,當(dāng)開(kāi)發(fā)者覺(jué)得非數(shù)字類型的索引是必要的時(shí)候會(huì)使用非數(shù)組對(duì)象。這項(xiàng)用法促進(jìn)了以非類數(shù)組對(duì)象為基礎(chǔ)的 set 和 map 集合類型的實(shí)現(xiàn)。

Set是類似數(shù)組的一種結(jié)構(gòu),可以存儲(chǔ)數(shù)據(jù),與數(shù)組的區(qū)別主要是 Set中的元素不能重復(fù),而數(shù)組中的元素可以重復(fù)。

一句話總結(jié):Set類型是一個(gè)包含無(wú)重復(fù)元素的有序列表

9.1 創(chuàng)建Set和并添加元素

Set本身是一個(gè)構(gòu)造函數(shù)。

<script type="text/javascript">
    //創(chuàng)建Set數(shù)據(jù)結(jié)構(gòu)對(duì)象。
    var s = new Set();
    //調(diào)用set對(duì)象的add方法,向set中添加元素
    s.add("a");
    s.add("c");
    s.add("b");
    //set的size屬性可以獲取set中元素的個(gè)數(shù)
    console.log(s.size)
</script>

9.2 Set中不能添加重復(fù)元素

<script type="text/javascript">
    var s = new Set();
    s.add("a");
    s.add("c");
    s.add("b");
    s.add("a");  //重復(fù),所以添加失敗。注意這個(gè)地方并不會(huì)保存。
    console.log(s.size); // 長(zhǎng)度是3
</script>   

看下面的代碼:

<script type="text/javascript">
    var s = new Set();
    s.add(5);
    s.add("5");
    console.log(s.size); // 長(zhǎng)度是2
</script>
在上面的代碼中,數(shù)字5和字符串5都會(huì)添加成功。為什么呢?

Set是使用什么機(jī)制來(lái)判斷兩個(gè)元素是否相等的呢?

是通過(guò)我們前面說(shuō)過(guò)的 Object.is(a, b) 來(lái)判斷兩個(gè)元素是否相等。

<script type="text/javascript">
    var s = new Set();
    s.add(+0);
    s.add(-0);  //重復(fù)添加不進(jìn)去
    s.add(NaN);
    s.add(NaN); //重復(fù)添加不進(jìn)去
    s.add([]);
    s.add([]);  //兩個(gè)空數(shù)組不相等,所以可以添加進(jìn)去
    s.add({});
    s.add({});  // 兩個(gè)空對(duì)象也不重復(fù),所以也可以添加進(jìn)去
    console.log(s.size); // 長(zhǎng)度是6
</script>

9.3 使用數(shù)組初始化Set

<script type="text/javascript">
    //使用數(shù)組中的元素來(lái)初始化Set,當(dāng)然碰到重復(fù)的也不會(huì)添加進(jìn)去。
    var s = new Set([2, 3, 2, 2, 4]);
    console.log(s.size)
</script>

9.4 判斷一個(gè)值是否在Set中

使用Set的 has() 方法可以判斷一個(gè)值是否在這個(gè)set中。

<script type="text/javascript">
    let set = new Set();
    set.add(5);
    set.add("5");

    console.log(set.has(5));    // true
    console.log(set.has(6));    // false
</script>

9.5 移除Set中的元素

delete(要?jiǎng)h除的值) :刪除單個(gè)值

clear():清空所有的值

<script type="text/javascript">
    let set = new Set();
    set.add(5);
    set.add("5");

    console.log(set.has(5));    // true

    set.delete(5);

    console.log(set.has(5));    // false
    console.log(set.size);      // 1

    set.clear();

    console.log(set.has("5"));  // false
    console.log(set.size);      // 0
</script>

9.6 遍歷Set

數(shù)組有個(gè)方法forEach可以遍歷數(shù)組。

  1. Set也有forEach可以遍歷Set。

使用Set的forEach遍歷時(shí)的回調(diào)函數(shù)有三個(gè)參數(shù):

function (value, key, ownerSet){

}

參數(shù)1:遍歷到的元素的值

參數(shù)2:對(duì)set集合來(lái)說(shuō),參數(shù)2的值和參數(shù)1的值是完全一樣的。

參數(shù)3:這個(gè) ==set== 自己

<script type="text/javascript">
    let set = new Set(["a", "c", "b", 9]);
    set.forEach(function (v, k, s) {
        console.log(v + "   " + (v === k) + "  " + (s === set));   // 永遠(yuǎn)是true
    })

</script>
  1. for…of也可以遍歷set。
for(var v of set){
    console.log(v)
}

9.7 將Set轉(zhuǎn)換為數(shù)組

將數(shù)組轉(zhuǎn)換為Set相當(dāng)容易,你只需要在創(chuàng)建Set集合時(shí)把數(shù)組作為參數(shù)傳遞進(jìn)去即可。

把Set轉(zhuǎn)換為數(shù)組使用前面講到的擴(kuò)展運(yùn)算符也很容易

<script type="text/javascript">
    let set = new Set([1, 2, 3, 3, 3, 4, 5]),
        arr = [...set];  //使用擴(kuò)展運(yùn)算符。那么新的數(shù)組中已經(jīng)沒(méi)有了重復(fù)元素。注意,此處對(duì)set并沒(méi)有什么影響

    console.log(arr);             // [1,2,3,4,5]
</script>

這種情況在需要去數(shù)組中重復(fù)元素的時(shí)候非常好用。

<script type="text/javascript">
    function eliminateDuplicates(items) {
        return [...new Set(items)];
    }
    let numbers = [1, 2, 3, 3, 3, 4, 5, 5, 2, 1, 1],
        //返回的是新的沒(méi)有重復(fù)元素的數(shù)組。
        noDuplicates = eliminateDuplicates(numbers);
    console.log(noDuplicates);      // [1,2,3,4,5]
</script>

Set提供了處理一系列值的方式,不過(guò)如果想給這些值添加一些附加數(shù)據(jù)則顯得力不從心,所以又提供了一種新的數(shù)據(jù)結(jié)構(gòu):Map

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • ES6 的內(nèi)置對(duì)象擴(kuò)展 Array 的擴(kuò)展方法 一、Array 的擴(kuò)展方法 1. 擴(kuò)展運(yùn)算符(展開(kāi)語(yǔ)法) 擴(kuò)展運(yùn)算...
    李小白呀閱讀 342評(píng)論 0 1
  • ES6新增特性 【說(shuō)明】ES5和ES6是javascript語(yǔ)法發(fā)展過(guò)程中的新增版本,對(duì)一些語(yǔ)法及功能性方法作了增...
    time_剛剛好閱讀 2,478評(píng)論 0 5
  • 一、let 和 const 1、塊級(jí)作用域 先來(lái)舉個(gè)栗子 會(huì)輸出4個(gè)4,因?yàn)椋?var定義的變量是全局的, 所以全...
    大南瓜鴨閱讀 418評(píng)論 0 2
  • 1.let和const關(guān)鍵字let: 變量不能重復(fù)聲明。 塊級(jí)作用域。在if-else語(yǔ)句、while循環(huán)、for...
    coder勇閱讀 610評(píng)論 0 0
  • ECMAScript6,即ES6,是ECMAScript的第六次修訂,于2015年完成,也稱ES2015 ES6是...
    babyface_fe閱讀 1,118評(píng)論 0 0

友情鏈接更多精彩內(nèi)容