2016-01-14 136 views
4

我想了解Ecmascript 6迭代器,并试图创建一个行为非常像本地数组的数据结构。了解实现自定义迭代器

for (let i of [1,2,3]) console.log(i); //Iterate over data set itself 

将输出1,2,3

for (let i of [1,2,3].keys()) console.log(i); //Iterate over a custom iterator from a method 

将输出0,1,2,和

var a = [1,2,3]; 
var keys = [...a.keys()]; 

将包含[0,1,2]如预期。

因此,

console.log([1,2,3].keys().next()); 

将输出Object {value: 0, done: false}

现在,我创建了一个新的数据类型,并试图使其行为方式相同。

var myDogs = function(dogs) { 
this.dogs = dogs; 
this[Symbol.iterator] =() => { 
    let i = -1; 
    return { 
    next() { 
    i++; 
    var dog = Object.keys(dogs)[i]; 
    if (!dog) return {done:true}; 
    return {value:{ dog, hungry:dogs[dog] }, done:false}; 
    } 
    }; 
}; 
this.dogsNames =() => { 
    return { 
    [Symbol.iterator]() { 
    let i = -1; 
    return { 
     next() { 
     i++; 
     var dog = Object.keys(dogs)[i]; 
     if (!dog) return {done:true}; 
     return {value: dog, done:false}; 
     } 
    }; 
    } 
    } 
} 
}; 

var dogs = new myDogs({ buddy: true, hasso: false }); 

可正常工作(自定义迭代器 - thank you):

var dogHungryMap = [...dogs]; 
dogHungryMap == [{ dog: 'buddy', hungry: true }, { dog: 'hasso': hungry: false }] 

dogsNames()工作几乎如预期的迭代器。这是OK:

var names = [...dogs.dogsNames()]; 
names == ["buddy", "hasso"] 

但这并不:

dogs.dogsNames().next() 
VM19728:2 Uncaught TypeError: dogs.dogsNames(...).next is not a function(…) 

为什么,我怎么能重现本地阵列的行为?

+0

仅供参考,本地阵列工作方式相同。没有'Array.prototype.next()'方法,它只能通过'arrayVar [Symbol.iterator]()获得。next()'too – CodingIntrigue

+1

'dogNames'必须返回一个也是可迭代的迭代器(并返回它自己)。每个内置的迭代器都会这样做:http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%iteratorprototype%-object。快速测试:v'ar it = [] .keys();它[Symbol.iterator]()===它的结果是'true'。所以基本上:'return {next(){...},[Symbol.iterator](){return this; }};'。 –

+0

@FelixKling这确实回答了我的问题。谢谢。 –

回答

4

dogNames必须返回一个迭代(一些实现next方法),这也是一个可迭代(一些implemen方法)(并返回它自己)。 Every built-in iterator does that

快速测试验证:

var it = [].keys(); 
it[Symbol.iterator]() === it // true 

所以,你可以更改您的代码

this.dogsNames =() => { 
    let i = -1; 
    return { 

    [Symbol.iterator]() { 
     return this; 
    }, 

    next() { 
     i++; 
     var dog = Object.keys(dogs)[i]; // should probably also be put in the outer function 
     if (!dog) return {done:true}; 
     return {value: dog, done:false}; 
    }, 

    }; 
}; 
+0

现在有光了。 –

5

因为dogsNames()返回一个具有迭代器作为关键字的对象。所以,你可以使用for...of在dogsNames,但访问next()直接您需要访问声明的对象上,像这样的迭代器功能:

dogsNames()[Symbol.iterator]().next() 

Babel REPL Example

以及物品是否完整,未来共享的完整代码( )函数:

var myDogs = function(dogs) { 
this.dogs = dogs; 
let i = -1; 
var iter = { 
    next() { 
    i++; 
    var dog = Object.keys(dogs)[i]; 
    if (!dog) return {done:true}; 
    return {value:{ dog, hungry:dogs[dog] }, done:false}; 
    } 
} 
this[Symbol.iterator] =() => iter; 
this.next = iter.next; 
}; 
var dogList = new myDogs({ 
    dog1: "no", 
    dog2: "yes" 
}); 
for(const x of dogList) console.log(x); 
console.log(dogList.next()); 
console.log(dogList.next()); 
+0

好吧,我该如何重现本地数组的行为? –

+0

关于迭代器?这已经是你已经做了或多或少的事情了。 [Babel REPL for arrays](https://babeljs.io/repl/#?experimental=true&evaluate=true&loose=false&spec=false&code=var%20arr%20%3D%20%5B1%2C2%2C3%5D%3B%0Aconsole .log(arr%5BSymbol.iterator%5D()。next())) – CodingIntrigue

+0

换句话说:我该如何让spread运算符工作并使'dogsNames()。next()'工作好? –