ES6迭代器(interator)和for...of...循环

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 = '';
            return $(str).appendTo($('body'));
        } catch (e) {
            return false;
        }
    },
    getFormUploadObj () {
        let str = '';   // 表单上传
        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]

你可能感兴趣的:(迭代器模式,迭代器,es6)