或許在寫ES6的代碼的時候,你可能沒有感受有用過迭代器這個東西,但是ES6中的for...of...循環咱們都不陌生,而for...of...循環的必要條件就是必須知足被循環的對象實現了迭代器接口才行。例子以下:數組
Exampleapp
var a = [1,2,3]; var b = { name:'arvin', age:30 } for(var i of a){ console.log(i); // 結果依次是:1,2,3 } for(var j of b){ console.log(j); // TypeError: b[Symbol.iterator] is not a function }
代碼解讀:對於上面代碼的結果咱們基本都知道,但是爲何是這個結果就不會很懂了。從代碼的結果能夠看出,for...of...循環可行的條件是須要被循環對象實現一個以Symbol.iterator爲方法屬性才行。而數組對象是默認實現了該方法的,因此並未報錯。如今咱們就來具體實現一下這個迭代器接口。函數
Exampleui
var b = { name:'arvin', age:30 } Object.defineProperty(b, Symbol.iterator, { enumerable: false, writable: false, configurable: true, value: function () { var me = this; var idx = 0; var keys = Object.keys(me); return { next: function () { return { value: me[keys[idx++]], done: (idx > keys.length) } } } } }); for(var j of b){ console.log(j); // 結果依次是:arvin,30 } // 下面的代碼相似上面的for...of...循環的內部實現 var c = b[Symbol.iterator](); while(true){ var newValue = c.next(); if(newValue.done){ break; } console.log(newValue.value) // 結果依次是:arvin,30 }
代碼解讀:從上面的這個demo能夠看出,ES6的迭代器是實現要求必需要實現一個Symbol.iterator接口,而且該接口要返回一個帶有next方法的對象,並且該next方法必須包含至少兩個值,value以及done,前者是迭代器的輸出值,後者是判斷迭代終止條件。下面附上一個通用上傳迭代器的運用例子:this
Examplecode
let getUploadObj = { getActiveUploadObj (){ try { return new ActiveXObject('TXFTNActiveX.FTNUpload'); // IE上傳控件 } catch (e) { return false; } }, getFalshUploadObj () { try { new ActiveXObject('ShockwaveFlash.ShockwaveFlash'); // Flash上傳控件 let str = '<object type="application/x-shockwave-flash"></object>'; return $(str).appendTo($('body')); } catch (e) { return false; } }, getFormUploadObj () { let str = '<input name="file" type="file" calss="ui-file"/>'; // 表單上傳 return $(str).appendTo($('body')); } } // 給對象getUploadObj定義iterator接口,上面演示過這段代碼 // 這裏能夠經過工廠模式,抽象成一個專門給對象安裝iterator接口的函數,這樣就能夠省卻不少重複代碼了。 Object.defineProperty(getUploadObj, Symbol.iterator, { enumerable: false, writable: false, configurable: true, value: function(){ var o = this; var idx = 0; var ks = Object.keys(o); return { next: function(){ return { value: o[ks[idx++]], done: (idx > ks.length) } } } } }); function iteratorUploadObj (uploadObj){ // 直接使用`for...of`遍歷uploadObj對象 for(let getUpload of uploadObj){ let uploadObj = getUpload(); if(uploadObj) return uploadObj; } } let uploadObj = iteratorUploadObj(getUploadObj); console.log(uploadObj); // [input, prevObject: Z.fn.init[1], context: undefined]