- Symbol型別
Symbol
的原因Symbol
,表示獨一無二的值。它是 JavaScript 語言的第七種資料型別,前六種是:undefined
、null
、布林值(Boolean)、字串(String)、數值(Number)、物件(Object)Symbol
函式生成。這就是說,物件的屬性名現在可以有兩種型別,一種是原來就有的字串,另一種就是新增的 Symbol 型別。凡是屬性名屬於 Symbol 型別,就都是獨一無二的,可以保證不會與其他屬性名產生衝突typeof s
// “symbol”
s
就是一個獨一無二的值。typeof
運算子的結果,表明變數s
是 Symbol 資料型別,而不是字串之類的其他型別Symbol
函式前不能使用new
命令,否則會報錯。這是因為生成的 Symbol 是一個原始型別的值,不是物件。也就是說,由於 Symbol 值不是物件,所以不能新增屬性。基本上,它是一種類似於字串的資料型別。Symbol
函式可以接受一個字串作為引數,表示對 Symbol 例項的描述,主要是為了在控制檯顯示,或者轉為字串時,比較容易區分。s1 // Symbol(foo)
s2 // Symbol(bar)
s1.toString() // “Symbol(foo)”
s2.toString() // “Symbol(bar)”
s1
和s2
是兩個 Symbol 值。如果不加引數,它們在控制檯的輸出都是Symbol()
,不利於區分。有了引數以後,就等於為它們加上了描述,輸出的時候就能夠分清,到底是哪一個值。Symbol
函式的引數只是表示對當前 Symbol 值的描述,因此相同引數的Symbol
函式的返回值是不相等的。// 有引數的情況
s1
和s2
都是Symbol
函式的返回值,而且引數相同,但是它們是不相等的。if (sym) {
// …
}
Number(sym) // TypeError
sym + 2 // TypeError
let a = {};
a[mySymbol] = `Hello!`;
// 第二種寫法
let a = {
a[mySymbol] // “Hello!”
const a = {};
a.mySymbol = `Hello!`;
a[mySymbol] // undefined
a[`mySymbol`] // “Hello!”
mySymbol
作為標識名所指代的那個值,導致a
的屬性名實際上是一個字串,而不是一個 Symbol 值。let obj = {
[s]: function (arg) { … }};
obj[s](123);
s
不放在方括號中,該屬性的鍵名就是字串s
,而不是s
所代表的那個 Symbol 值。- Set和Map結構
[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));
for (let i of s) {
console.log(i);}
// 2 3 5 4
add
方法向 Set 結構加入成員,結果表明 Set 結構不會新增重複的值。const set = new Set([1, 2, 3, 4, 4]);
// [1, 2, 3, 4]
// 例二
const items = new Set([1, 2, 3, 4, 5, 5, 5, 5]);
items.size // 5
// 例三
[…new Set(array)]
5
和"5"
是兩個不同的值。Set 內部判斷兩個值是否不同,使用的演算法叫做“Same-value-zero equality”,它類似於精確相等運算子(===
),主要的區別是NaN
等於自身,而精確相等運算子認為NaN
不等於自身。constructor
:建構函式,預設就是Set
函式。size
:返回Set
例項的成員總數。
// 注意2被加入了兩次
s.size // 2
s.has(1) // true
s.has(2) // true
s.has(3) // false
s.delete(2);
s.has(2) // false
Array.from
方法可以將 Set 結構轉為陣列。for (let x of set) {
console.log(x);}
// red
// green
// blue
forEach
方法,用於對每個成員執行某種操作,沒有返回值。// 4 : 4
// 9 : 9
forEach
方法的引數就是一個處理函式。該函式的引數與陣列的forEach
一致,依次為鍵值、鍵名、集合本身(上例省略了該引數)。這裡需要注意,Set 結構的鍵名就是鍵值(兩者是同一個值),因此第一個引數與第二個引數的值永遠都是一樣的。Map 結構的例項有以下屬性和操作方法。
(1)size 屬性
size
屬性返回 Map 結構的成員總數。map.set(`foo`, true);
map.set(`bar`, false);
map.size // 2
(2)set(key, value)
set
方法設定鍵名key
對應的鍵值為value
,然後返回整個 Map 結構。如果key
已經有值,則鍵值會被更新,否則就新生成該鍵。m.set(`edition`, 6) // 鍵是字串
m.set(262, `standard`) // 鍵是數值
m.set(undefined, `nah`) // 鍵是 undefined
set
方法返回的是當前的Map
物件,因此可以採用鏈式寫法。.set(1, `a`)
.set(2, `b`)
.set(3, `c`);
get
方法讀取key
對應的鍵值,如果找不到key
,返回undefined
。const hello = function() {console.log(`hello`);};
m.set(hello, `Hello ES6!`) // 鍵是函式
m.get(hello) // Hello ES6!
has
方法返回一個布林值,表示某個鍵是否在當前 Map 物件之中。m.set(`edition`, 6);
m.set(262, `standard`);
m.set(undefined, `nah`);
m.has(`edition`) // true
m.has(`years`) // false
m.has(262) // true
m.has(undefined) // true
delete
方法刪除某個鍵,返回true
。如果刪除失敗,返回false
。m.set(undefined, `nah`);
m.has(undefined) // true
m.delete(undefined)
m.has(undefined) // false
clear
方法清除所有成員,沒有返回值。Map 結構原生提供三個遍歷器生成函式和一個遍歷方法。
keys()
:返回鍵名的遍歷器。values()
:返回鍵值的遍歷器。entries()
:返回所有成員的遍歷器。forEach()
:遍歷 Map 的所有成員。
[`F`, `no`],
[`T`, `yes`],]);
for (let key of map.keys()) {
console.log(key);}
// “F”
// “T”
for (let value of map.values()) {
console.log(value);}
// “no”
// “yes”
for (let item of map.entries()) {
console.log(item[0], item[1]);}
// “F” “no”
// “T” “yes”
// 或者
for (let [key, value] of map.entries()) {
console.log(key, value);}
// “F” “no”
// “T” “yes”
// 等同於使用map.entries()
for (let [key, value] of map) {
console.log(key, value);}
// “F” “no”
// “T” “yes”
...
)。[1, `one`],
[2, `two`],
[3, `three`],]);
[…map.keys()]
// [1, 2, 3]
[…map.values()]
// [`one`, `two`, `three`]
[…map.entries()]
// [[1,`one`], [2, `two`], [3, `three`]]
[…map]
// [[1,`one`], [2, `two`], [3, `three`]]
- Generators生成器函式
function
關鍵字與函式名之間有一個星號;二是,函式體內部使用yield
表示式,定義不同的內部狀態(yield
在英語裡的意思就是“產出”)yield `hello`;
yield `world`;
return `ending`;}
var hw = helloWorldGenerator();
helloWorldGenerator
,它內部有兩個yield
表示式(hello
和world
),即該函式有三個狀態:hello,world 和 return 語句(結束執行)。next
方法才會遍歷下一個內部狀態,所以其實提供了一種可以暫停執行的函式。yield
表示式就是暫停標誌。(1)遇到yield
表示式,就暫停執行後面的操作,並將緊跟在yield
後面的那個表示式的值,作為返回的物件的value
屬性值。
(2)下一次呼叫next
方法時,再繼續往下執行,直到遇到下一個yield
表示式。
(3)如果沒有再遇到新的yield
表示式,就一直執行到函式結束,直到return
語句為止,並將return
語句後面的表示式的值,作為返回的物件的value
屬性值。
return
語句,則返回的物件的value
屬性值為undefined
next
方法,使得指標移向下一個狀態。也就是說,每次呼叫next
方法,內部指標就從函式頭部或上一次停下來的地方開始執行,直到遇到下一個yield
表示式(或return
語句)為止。換言之,Generator 函式是分段執行的,yield
表示式是暫停執行的標記,而next
方法可以恢復執行。// { value: `hello`, done: false }
hw.next()
// { value: `world`, done: false }
hw.next()
// { value: `ending`, done: true }
hw.next()
// { value: undefined, done: true }
上面程式碼一共呼叫了四次next
方法。
第一次呼叫,Generator 函式開始執行,直到遇到第一個yield
表示式為止。next
方法返回一個物件,它的value
屬性就是當前yield
表示式的值hello
,done
屬性的值false
,表示遍歷還沒有結束。
第二次呼叫,Generator 函式從上次yield
表示式停下的地方,一直執行到下一個yield
表示式。next
方法返回的物件的value
屬性就是當前yield
表示式的值world
,done
屬性的值false
,表示遍歷還沒有結束。
第三次呼叫,Generator 函式從上次yield
表示式停下的地方,一直執行到return
語句(如果沒有return
語句,就執行到函式結束)。next
方法返回的物件的value
屬性,就是緊跟在return
語句後面的表示式的值(如果沒有return
語句,則value
屬性的值為undefined
),done
屬性的值true
,表示遍歷已經結束。
next
方法返回物件的value
屬性為undefined
,done
屬性為true
。以後再呼叫next
方法,返回的都是這個值。next
方法,就會返回一個有著value
和done
兩個屬性的物件。value
屬性表示當前的內部狀態的值,是yield
表示式後面那個表示式的值;done
屬性是一個布林值,表示是否遍歷結束。