摘要:迭代器在原有的數據結構類型上新增了兩種類型,我們在使用的時候還可以通過自由組合的形式使用這些結構類型達到自己想要的數據結構,這就需要一種統一的接口機制供我們調用處理不同的數據結構。
引言
萬丈高樓平地起,欲練此功,必先打好基本功: )
在了解 ES6 新增的變量類型前,我們必須先知道 JavaScript 在ES6之前,有如下六種基本數據類型:Null、Undefined、Number、String、Boolean和Object。而 ES6 中,新增了第七種數據類型:Symbol。
上述七種數據類型作如下類型劃分:
基本類型: Undefined、Null、Boolean、String、Number,這五種類型的變量都是直接把實際值存儲在棧內存當中,操作或訪問的時候都是直接對實際值進行的.
引用類型: Object。Object 類型的變量是把指向堆內存的地址值存儲在棧內存當中的一類數據。(關于堆棧的知識將會在后面的文章中作介紹。)
有關基本類型和引用類型的說明,網上已經有很多文章有說明介紹,為免篇幅過長,這里就不再重復敘述了。
Symbol類型:這里我們著重說一下 Symbol 類型:
Symbol 是一個函數,調用該函數,返回的唯一值就是 Symbol 類型值;
let symbol = Symbol(); symbol; //Symbol() typeof symbol; //symbol let symbol1 = new Symbol(); //Uncaught TypeError: Symbol is not a constructorSymbol 函數調用時,可接受一個參數,該參數會通過 toString 方法變為字符串,作為 symbol 值的說明,傳入的參數不可以為 symbol 類型的值
let testStr = "this is a string", testObj = {obj: "this is a object"}, testArr = ["this","is","a","array"], testFn = () => { console.log("this is a function"); }, testSym = Symbol("this is a symbol"), symbolStr = Symbol(testStr), //Symbol(this is a string) symbolObj = Symbol(testObj), //Symbol([object Object]) symnolArr = Symbol(testArr), //Symbol([object Object]) symbolFn = Symbol(testFn), //Symbol(() => {console.log("this is a function");}) symbolSym = Symbol(testSym); //Uncaught TypeError: Cannot convert a Symbol value to a stringSymbol 函數調用后生成的值是唯一的
let symbol1 = Symbol("test"), symbol2 = Symbol("test"); symbol1 == symbol2; //false symbol1 === symbol2; //falseSymbol 值不能與其他類型值進行運算、隱式轉換,否則會報錯;但能通過 toString 方法顯式轉為字符串。
let symbol = Symbol("this is symbol"), str = "this is string", num = 2, symStr = symbol.toString(); let newStr = symbol + str; //Uncaught TypeError: Cannot convert a Symbol value to a string let newNum = Symbol + num; //Uncaught TypeError: Cannot convert a Symbol value to a number symStr; // Symbol(this is symbol)Symbol 值的唯一性,用于 Object 的屬性中,可以確保不會出現同名屬性
let symbol = Symbol("this is symbol"), symbol1 = Symbol("this is symbol"); let obj = { [symbol]: "this is a", [symbol1]: "this is b" }; obj; //{Symbol(this is symbol): "this is a", Symbol(this is symbol): "this is b"} let str = "test", str1 = "test", obj = {}; obj[str] = "測試非symbol類型命名的屬性"; obj; //{test: "測試非symbol類型命名的屬性"} obj[str1] = "再次測試非symbol類型命名的屬性"; obj; //{test: "再次測試非symbol類型命名的屬性"}Symbol 命名的屬性可通過 Object.getOwnPropertySymbols 獲取
let symbol = Symbol("this is symbol"), symbol1 = Symbol("this is symbol"); let symbolObj = { [symbol]: "this is a", [symbol1]: "this is b", } Object.getOwnPropertySymbols(symbolObj); //[Symbol(this is symbol), Symbol("this is symbol")]Symbol 值命名的屬性不會出現在 Object.keys、for...in...中,通過Object.getOwnPropertyNames()、JSON.stringify() 也無法得到返回值。但該屬性是公開屬性,不是私有屬性。
let symbol = Symbol("this is symbol"), symbol1 = Symbol("this is symbol"); let obj = { [symbol]: "this is a", [symbol1]: "this is b", d: "test" }; for(key in obj){ console.log(key); // d } Object.keys(obj); // ["d"] Object.getOwnPropertyNames(obj); // ["d"] JSON.stringify(obj); //{d:"test"} //仍可訪問到Symbol值定義的屬性鍵和屬性值 let symKeys = Object.getOwnPropertySymbols(obj); symKeys; //[Symbol(this is symbol), Symbol(this is symbol)] symKeys[0]; //Symbol(this is symbol) obj[symKeys[0]]; //this is a可通過 Symbol.for("xxx") 獲得以"xxx"作為入參而生成的 Symbol 值,若不存在以"xxx"作為入參生成的 Symbol 值,則會自動創建一個以"xxx"為入參的 Symbol 值。
let symbol = Symbol("this is symbol"), symbol1 = Symbol.for("this is symbol"), symbol2 = Symbol.for("this is symbol"); symbol === symbol1 //false symbol === symbol2 //false symbol1 === symbol2 //true12. 通過 Symbol.keyFor 方法可返回一個已“登記”的 Symbol 類型值的修飾詞。
通過 Symbol 創建的值有如下兩種情況:
被登記的與未被登記的。
什么是被登記的?在
let s1 = Symbol.for("foo"); console.log(Symbol.keyFor(s1)); // "foo" var s2 = Symbol("foo"); console.log(Symbol.keyFor(s2) ); // undefined
這里還有一些 MDN 關于 Symbol 的屬性介紹,因為感覺在日常開發中使用的概率比較低,因此也不贅述一些自己的理解了,有興趣的朋友可以去看看https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Symbol
關于 Symbol 的總結: 對于 Symbol 的使用,實用性最高的我覺得是 symbol 值用于屬性命名的情況,在一些開發情況下,對一個 Object 對象進行遍歷的時候,希望某一些屬性不被 for in 或 Object.keys 遍歷出來,避免做 if 或 switch 情況處理,這時候使用 Symbol 定義屬性名是個不錯的選擇。
在原有 ES5 的屬性命名和賦值過程中,多人協作開發可能會導致一些屬性名重命名而導致值覆蓋,對“半私有屬性”屬性使用 Symbol 命名屬性名會是個很好的選擇。
ES6 在原有的數據結構類型( Array、Object )上新增了兩種類型( Map、Set ),我們在使用的時候還可以通過自由組合的形式使用這些結構類型達到自己想要的數據結構,這就需要一種統一的接口機制供我們調用處理不同的數據結構 —— Iterator。
ES6中,只要被遍歷“對象”存在 可迭代協議 , 即System.iterator 屬性,該對象都是被認為是“可遍歷的”。
在 ES6 中,有三類數據結構原生具備 Iterator 接口:__數組、某些類似數組的對象(如 字符串、類似數組形式的對象)、Set 和 Map 結構數據__。
迭代器協議 定義了一種標準的方式來產生一個有限或無限序列的值,每次遍歷都會首先調用被遍歷數據集合對象中的 [Symbol.iterator]() 方法,該方法返回一個 Symbol對象的iterator屬性 ,該屬性擁有執行迭代對象的 next 方法,并返回一個對象,如下是一段模擬 next 方法的代碼
function Iterator(arr){ let nextIndex = 0; return { next: function(){ return nextIndex < arr.length ? {value: arr[nextIndex++], done: false} : {value: undefined, done: true}; }, [Symbol.iterator]: function() { return this } } } let example = Iterator(["a", "b"]); example.next() // {value: "a", done: false} example.next() // {value: "b", done: false} example.next() // {value: undefined, done: true} //遍歷結束
返回的對象中必須包含如下兩個屬性
{ done, //迭代是否已經執行完畢 迭代完畢時返回true,否則返回false,返回false時會繼續執行迭代 value //當前成員的值 迭代完畢時返回undefined,否則返回當前成員的值 }在某些情景下,JS會默認調用 Symbol.iterator (Iterator接口)
擴展運算符
擴展運算符(…)會默認調用 iterator 接口。
解構賦值
對數組和Set結構進行解構賦值時,會默認調用 Symbol.iterator 方法。
yield*
yield*后面跟的是一個可遍歷的結構,它會調用該結構的 iterator 接口。
for...of
執行 for...of循環時,會調用 iterator 接口對數據進行處理。
Array.from()
在 Array.form() 時,會遍歷數據,調用 iterator 接口返回相應數據
其它情況還有
Map() , Set() , WeakMap() , WeakSet() (比如new Map([["a",1],["b",2]])) , Promise.all() , Promise.race() 。
順帶一提:
在ES6中,具有 System.iterator 屬性的對象均可通過 for...of 進行遍歷
let arr = ["1","2","3"]; arr.pro = "test"; for (let i in arr) { console.log(arr[i]); //1 2 3 test } for(let i of arr) { console.log(arr[i]); //1 2 3 }
for...of 的相比于 forEach 、 for...in ,其好處在于: forEach 循環無法通過 break 、 continue 、 return 跳出循環,而 for...of 可以; for...in 循環設計的目的是用于遍歷包含鍵值對的對象,對數組并不是那么友好,而 for...of 遍歷輸出的值會在輸出數據后默認遍歷結束。
關于 Iterator 的總結: Iterator作為一種統一的接口機制供我們調用處理不同的數據結構,讓可以用相同的方式來遍歷集合,而不用去考慮集合的內部實現,若數據的形式發生改變,只要數據內部還存在 System.iterator 屬性,那遍歷的代碼就可以不用做修改直接使用。 同時,其服務于 for...of 循環, for...of 又有效地避免了以往對數據集僅能通過 forEach 、 for..in 遍歷時遇到的一部分問題。
以上。
文章觀點內容如有錯誤歡迎指出交流,相互進步
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/104180.html
摘要:變量聲明結論存在變量提升,可重復多次聲明同名變量。和的出現,很好地把中定義變量的給埋了,解決了定義同名變量導致變量間相互污染的問題,保證了同一塊級作用域下,變量名的唯一性。中規定,函數本身的作用域在其所在的塊級作用域當中。 引言 萬丈高樓平地起,欲練此功,必先打好基本功: )。 ES6已經融入到了我們的日常開發當中,甚至一些ES7的特性也已經在普遍使用,但由于瀏覽器的支持問題,ES6的...
摘要:擴展運算符簡介擴展運算符是三個點,可以將一個數組轉為用逗號分隔的參數序列。在實際項目中靈活應用擴展運算符運算符,能寫出更精簡易讀性高的代碼。 1、擴展運算符簡介 擴展運算符( spread )是三個點(...),可以將一個數組轉為用逗號分隔的參數序列。 說的通俗易懂點,有點像化骨綿掌,把一個大元素給打散成一個個單獨的小元素。 showImg(https://segmentfault.c...
摘要:執行函數會返回一個遍歷器對象,每一次函數里面的都相當一次遍歷器對象的方法,并且可以通過方法傳入自定義的來改變函數的行為。函數可以通過配合函數更輕松更優雅的實現異步編程和控制流管理。它和構造函數的不同點類的內部定義的所有方法,都是不可枚舉的。 let const的命令 在ES6之前,聲明變量只能用var,var方式聲明變量其實是很不合理的,準確的說,是因為ES5里面沒有塊級作用域是很不合...
摘要:目前的標準化工作正在進行中,預計會在年月份放出正式敲定的版本。反的方法可以接收一個參數并且返回值取決與它的構造函數。之后就可以用這個返回值做為對象的鍵了。 本文基于lukehoban/es6features ,同時參考了大量博客資料,具體見文末引用。 ES6(ECMAScript 6)是即將到來的新版本JavaScript語言的標準,代號harmony(和諧之意,顯然沒有跟上我國的步伐...
摘要:掛機科了次使用這個結構,匿名函數就有了自己的執行環境或閉包,然后我們立即執行。注意,匿名函數的圓括號是必需的,因為以關鍵字開頭的語句通常被認為是函數聲明請記住,中不能使用未命名的函數聲明。 這是專門探索 JavaScript 及其所構建的組件的系列文章的第 20 篇。 想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等著你! 如果你錯過了前面的章節,可以在這里找到它們: ...
閱讀 1990·2021-09-22 16:05
閱讀 9252·2021-09-22 15:03
閱讀 2880·2019-08-30 15:53
閱讀 1697·2019-08-29 11:15
閱讀 902·2019-08-26 13:52
閱讀 2348·2019-08-26 11:32
閱讀 1797·2019-08-26 10:38
閱讀 2562·2019-08-23 17:19