2017-02-16 8 views
5

У меня есть связанный список в JavaScript, который мне нужно сделать итерабельным с помощью цикла for of. Я почти сделал это, но, похоже, нет способа получить первое значение, включенное в результат. Вот упрощенная версия:Создание связанного списка итерации в ES6

var obj = {value: 1, next: {value: 2, next: {value: 3, next: {value: 4, next: {value: 5, next: {value: 6, next: {value:7, next: null}}}}}}}; 

obj[Symbol.iterator] = function() { 
    var current = this; 
    return { 
    next() { 
     if (current.next !== null) { 
     current = current.next; 
     return {value: current.value, done: false}; 
     } 
     return {done: true} 
    } 
    } 
} 

for (const x of obj) { 
    console.log(x) 
} 

// this is how you get the values printed with no loop 
// console.log(obj.value + '->' + obj.next.value + '->' + obj.next.next.value) 

ответ

4

Проблема в том, вы двигаетесь current к следующему узлу перед извлечением в value.

var obj = {value: 1, next: {value: 2, next: {value: 3, next: {value: 4, next: {value: 5, next: {value: 6, next: {value:7, next: null}}}}}}}; 
 

 
obj[Symbol.iterator] = function() { 
 
    var current = this; 
 
    return { 
 
    next() { 
 
     if (current) { 
 
     var value = current.value; 
 
     current = current.next; 
 
     return {value: value, done: false}; 
 
     } 
 
     return {done: true}; 
 
    } 
 
    }; 
 
}; 
 

 
for (const x of obj) { 
 
    console.log(x); 
 
}

Это гораздо легче реализовать итератор с generator function.

var obj = {value: 1, next: {value: 2, next: {value: 3, next: {value: 4, next: {value: 5, next: {value: 6, next: {value:7, next: null}}}}}}}; 
 

 
obj[Symbol.iterator] = function*() { 
 
    var current = this; 
 
    while (current) { 
 
    yield current.value; 
 
    current = current.next; 
 
    } 
 
}; 
 

 
for (const x of obj) { 
 
    console.log(x); 
 
}

1

Вы должны испытывать для current, не current.next:

obj[Symbol.iterator] = function() { 
    var current = this; 
    return { 
    next() { 
     if (current !== null) { 
     var res = {value: current.value, done: false}; 
     current = current.next; 
     return res; 
     } else { 
     return {done: true}; 
     } 
    } 
    }; 
} 

Но можно писать гораздо проще, так как метод генератора:

obj[Symbol.iterator] = function*() { 
    for (var current = this; current !== null; current = current.next) { 
    yield current.value; 
    } 
} 

Btw, Я w ould рекомендует не помещать этот итератор на каждый узел списка (или даже на первый). Положите в на отдельном объекте, который указывает на начало списка, или сделать его статическую вспомогательную функцию:

let list = { 
    head: obj, // could be null either 
    *[Symbol.iterator]() { 
    for (var current = this.head; current !== null; current = current.next) { 
     yield current.value; 
    } 
    } 
} 

function* linkedList(head) 
    for (; head !== null; head = head.next) { 
    yield head.value; 
    } 
} 
Смежные вопросы