Interator(遍歷器)git
在 JavaScript 中 迭代器是一個對象,它提供了一個next() 方法,(除了next()方法還有return和throw方法),用來返回序列中的下一項。這個方法返回包含兩個屬性:done和 value。done屬性是個布爾值,表明遍歷是否結束,便是否還有必要再一次調用next方法。value屬性表明當前成員的值。es6
迭代器對象一旦被建立,就能夠反覆調用next()。github
function makeIterator(array){ var nextIndex = 0; return { next: function(){ return nextIndex < array.length ? {value: array[nextIndex++], done: false} : {done: true}; } }; } let a = makeIterator(['apple','pear','orange']) console.log(a.next()) // {value: "apple", done: false} console.log(a.next()) // {value: "pear", done: false} console.log(a.next()) // {value: "orange", done: false} console.log(a.next()) // {done: true}
ES6 規定,默認的 Iterator 接口部署在數據結構的Symbol.iterator屬性, Symbol.iterator屬性自己是一個函數,就是當前數據結構默認的遍歷器生成函數。執行這個函數,就會返回一個遍歷器。編程
學習一下新型的for-of循環。可在具備Iterator 接口的元素進行遍歷。數組
let arr = [1,2,3]; for(let v of arr){ v +=1; console.log(v) } // 2 3 4
[1,2,3,4,5].forEach((i,v) => { console.log(v) if(i > 3){ break; } }) // Uncaught SyntaxError: Illegal break statement
for(let v in ['a','b','c']){ console.log(v) } // 0 1 2
let arr = [1,2,3,4]; for(let v of arr){ console.log(v) } // 1 2 3 4
let a = ['a','b','c','d'] for(let v of a){ console.log(v) } // a b c d
for(let v of [1,2,3,4,5]){ console.log(v) if(v > 3){ break } } // 1 2 3 4 5
3 能夠遍歷其餘的全部集合(Nodelist,Set,Map),還有生成器數據結構
<div>1</div> <div>2</div> <div>3</div> <div>4</div> let doms = document.querySelectorAll('div') for(let v of doms){ console.log(v.innerHTML) } // 1 2 3 4
let set = new Set([1,2,3,4,5]) for(let v of set){ console.log(v) } // 1 2 3 4 5
let map = new Map().set('a',1).set('b',2) for(let v of map){ console.log(v) } // ["a", 1] // ["b", 2]
let obj = {name:'peter',age:25} for(let v of obj){ console.log(v) } // Uncaught TypeError: obj is not iterable
let obj = {name:'peter',age:25} for(let v of Object.keys(obj)){ console.log(v) } // name age
4 另外,for-of能夠適用於字符串app
let str = 'hello'; for(let v of str) { console.log(v) } // h e l l o
Interator不是很難懂,只要明白了哪些是數據集合,就說明具備Interator接口,天然就能夠看成遍歷器,從而使用for-of循環和使用next方法獲取想要的數據。dom
Generator(生成器)異步
經過對Interator的理解,生成器也是具備Interator接口的對象,它自己帶有遍歷特性,返回一個遍歷器對象。async
既然生成器是遍歷器,那麼可使用遍歷器的方法(自己函數不會實行,必須經過next()方法才能調用或者使用for-of返回)
function *fn(){ yield 'peter'; yield 1; yield {name:'peter'}; yield [1,2,3,4]; yield function *foo(){ yield 123; } } let a = fn() console.log(a.next()) console.log(a.next()) console.log(a.next()) console.log(a.next()) console.log(a.next()) console.log(a.next()) {value: "peter", done: false} {value: 1, done: false} {value: {…}, done: false} {value: Array(4), done: false} {value: ƒ, done: false} {value: undefined, done: true}
學習一下yield:
function *fn(){ yield 'a'; let b = yield 'b' + 'c'; yield 'd' } let foo = fn() for(let v of foo){ console.log(v) } // a bc d
function *fn(){ yield '1' console.log('start') yield '2' } let a = fn() console.log(a.next()) {value: "1", done: false}
function fn(){ yield 'a' } fn() // Uncaught SyntaxError: Unexpected string
function *fn(){ yield '1'; yield '2'; return '3'; yield '4' } let a = fn() console.log(a.next()); // {value: "1", done: false} console.log(a.next()); // {value: "2", done: false} console.log(a.next()); // {value: "3", done: true} console.log(a.next()); // {value: undefined, done: true} console.log(a.next()); // {value: undefined, done: true}
function *foo(){ yield 'f' } function *fn(){ yield 'a'; yield foo() yield 'b' } for( let v of fn()){ console.log(v) } // a foo {<suspended>} b
function *foo(){ yield 1; yield 2 } function *fn(){ yield 'a'; yield *foo() yield 'b' } for( let v of fn()){ console.log(v) // a 1 2 b }
上面已經說到生成器也是具備Interator接口的對象,不可置否的,生成器自己帶有Symbol.iterator,能夠說生成器是遍歷器的一種,因此可遍歷,可使用for-of來循環數據。
for...of循環能夠自動遍歷 Generator 函數時生成的Iterator對象,且此時再也不須要調用next方法。
function *fn(){ yield 'a'; yield 'b'; yield 'c'; yield 'd'; return 'end' } let a = fn() for(let v of a){ console.log(v) // a b c d }
function *fn(){ yield 'a'; yield 'b'; yield 'c'; yield 'd'; return 'end' } let a = fn() console.log(a.next()); // {value: "a", done: false} console.log(a.next()); // {value: "b", done: false} console.log(a.next()); // {value: "c", done: false} console.log(a.next()); // {value: "d", done: false} console.log(a.next()); // {value: "end", done: true} console.log(a.next()); // {value: undefined, done: true}
function *fn(){ yield 'a'; yield 'b'; yield 'c'; yield 'd'; return 'end' } let a = fn() console.log([...a]) // ["a", "b", "c", "d"]
概要總結;只要具備Symbol.iterator屬性的,就能夠遍歷yield表達式
function* f() { yield 2; yield 3; } new f() // TypeError: F is not a constructor
Generator 函數的方法:
next() 返回 Generator 函數對象中yield後面的表達式,上面已經用到了next方法。yield表達式自己沒有返回值,老是返回undefined
function *fn(x){ let a = yield x; let b = yield 2 + a; } let a = fn(2); console.log(a.next(5)); // {value: 2, done: false} console.log(a.next(10)); // {value: 12, done: false} console.log(a.next(20)); // {value: undefined, done: true}
function *fn(x){ let a = yield x; let b = yield 2 + a; } let a = fn(2); console.log(a.next()); // {value: 2, done: false} console.log(a.next()); // {value: NaN, done: false} console.log(a.next()); // {value: undefined, done: true}
throw() 在函數體外拋出錯誤,而後在 Generator 函數體內捕獲。
let a = function* () { try { yield ; } catch ( e ){ console.log(e); } }; var i = a(); console.log(i.throw()) // Uncaught undefined
let g = function* () { try { yield 1; } catch (e) { console.log(e); } yield 'a'; yield 'b' }; let i = g(); console.log(i.next()) // 1 i.throw(new Error('出錯了!')); // Error: 出錯了!(…) 附帶執行了一次yield ‘a’ console.log(i.next()) // b
throw()方法的做用就是捕獲異常,而且繼續執行下去,不由於異常而中斷。throw方法被捕獲之後,會附帶執行下一條yield表達式。也就是說,會附帶執行一次next方法。
throw()的意義:大大方便了對錯誤的處理。多個yield表達式,能夠只用一個try...catch代碼塊來捕獲錯誤。若是使用回調函數的寫法,想要捕獲多個錯誤,就不得不爲每一個函數內部寫一個錯誤處理語句,如今只在 Generator 函數內部寫一次catch語句就能夠了。
return() 返回給定的值,而且終結遍歷 Generator 函數。
function *fn(){ yield 1; yield 2; return 3; } let a = fn(); console.log(a.next()) // {value: 1, done: false} console.log(a.return()); // {value: undefined, done: true} console.log(a.next()) // {value: undefined, done: true}
function *fn(){ yield 1; yield 2; return 3; } let a = fn(); console.log(a.next()) // {value: 1, done: false} console.log(a.return(100)); // {value: 100, done: true} console.log(a.next()) // {value: undefined, done: true}
return()的意義:一般在生成器異步操做時須要在某個時段跳出來。
Generator生成器是異步編程提供了方便。
對於Interator和Generator,在平時使用時不多用到,只有那個for-of能夠替代for循環使用,主要用於異步編程async當中。學習這個感受沒學全,事後我會再仔細學一遍。知識點我放到github裏了,有須要能夠去下載一塊兒學習。
仍是那句話。有什麼問題或錯誤請私信或者下方評論,一塊兒討論進步。
參考資料:
阮一峯es6入門 http://es6.ruanyifeng.com/