ES6迭代器(interator)和for...of...循环
或许在写ES6的代码的时候,你可能没有感觉有用过迭代器这个东西,可是ES6中的for...of...循环我们都不陌生,而for...of...循环的必要条件就是必须满足被循环的对象实现了迭代器接口才行。例子如下:
Example
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为方法属性才行。而数组对象是默认实现了该方法的,所以并未报错。现在我们就来具体实现一下这个迭代器接口。
Example
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,前者是迭代器的输出值,后者是判断迭代终止条件。下面附上一个通用上传迭代器的运用例子:
Example
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]
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。