Рубрики
Без рубрики

ES6 итераторы и генераторы

Автор оригинала: Scott Robinson.

Итераторы и генераторы обычно являются вторичной мыслью при написании кода, но если вы можете занять несколько минут, чтобы подумать о том, как использовать их для упрощения вашего кода, они сэкономит вам много отладки и сложности. С новыми итераторами ES6 и генераторами JavaScript используют аналогичные функции Java, что позволяет нам настроить нашу итерацию на объекты.

Например, если у вас был объект графа, вы можете легко использовать генератор для прогулки по узлам или краям. Это делает для гораздо более чистого кода, поместив логику прохождения в объект графа, где он принадлежит. Это разделение логики – это хорошая практика, а итераторы/генераторы облегчают следовать этими лучшими практиками.

ES6 итераторы и генераторы

Итераторы

Использование итераторов вы можете создать способ итерации, используя для ... из построить для вашего пользовательского объекта. Вместо использования Для ... в , который просто итерации через все свойства объекта, используя для ... из Давайте сделаем гораздо более настраиваемый и структурированный итератор, в котором мы выбираем, какие значения возвращаются на каждую итерацию.

Под капотом для ... из на самом деле использует Symbol.itereator Отказ Напомним Символы Новая функция в JavaScript ES6. Symbol.itereator Символ специального назначения, созданный специально для доступа к внутреннему итератору объекта. Итак, вы можете использовать его для получения функции, которая итерации на объект массива, как так:

var nums = [6, 7, 8];
var iterator = nums[Symbol.iterator]();
iterator.next();				// Returns { value: 6, done: false }
iterator.next();				// Returns { value: 7, done: false }
iterator.next();				// Returns { value: 8, done: false }
iterator.next();				// Returns { value: undefined, done: true }

Когда вы используете для ... из Построить, это на самом деле то, что используется внизу. Обратите внимание, как возвращается каждое последующее значение, наряду с индикатором, сообщающим, что если вы находитесь в подавляющем большинстве случаев, когда вам не нужно использовать Далее () Вручную вроде это, но вариант в том случае, если у вас есть применение, требующее более сложного цикла.

Вы можете использовать Symbol.itereator определить специализированную итерацию для объекта. Итак, давайте скажем, у вас есть свой объект, который является оберткой для предложений, Предложение Отказ

function Sentence(str) {
    this._str = str;
}

Чтобы определить, как мы переиграем на внутренние органы объекта предложения, мы поставляем функцию прототипа итератора:

Sentence.prototype[Symbol.iterator] = function() {
    var re = /\S+/g;
    var str = this._str;

    return {
        next: function() {
            var match = re.exec(str);
            if (match) {
                return {value: match[0], done: false};
            }
            return {value: undefined, done: true};
        }
    }
};

Теперь, используя итератор, который мы только что создали выше (содержащие строку REGEX, которая соответствует только словам), мы можем легко повторить слова любого предложения, которое мы поставляем:

var s = new Sentence('Good day, kind sir.');

for (var w of s) {
    console.log(w);
}

// Prints:
// Good
// day,
// kind
// sir.
Генераторы

Генераторы ES6 создают на вершине токовых итераторов, используя специальный синтаксис для легкого создания функции итерации. Генераторы определяются с использованием Функция * ключевое слово. В пределах Функция * , вы можете многократно возвращать значения, используя доходность Отказ доходность Ключевое слово используется в функциях генератора, чтобы приостановить выполнение и вернуть значение. Это можно подумать о генераторной версии Возвращение ключевое слово. В следующей итерации исполнение возобновится в последнее время, что доходность был использован.

function* myGenerator() {
    yield 'foo';
    yield 'bar';
    yield 'baz';
}

myGenerator.next();		// Returns {value: 'foo', done: false}
myGenerator.next();		// Returns {value: 'bar', done: false}
myGenerator.next();		// Returns {value: 'baz', done: false}
myGenerator.next();		// Returns {value: undefined, done: true}

Или, вы могли бы использовать для ... из Конструкция:

for (var n of myGenerator()) {
    console.log(n);
}

// Prints
// foo
// bar
// baz

В этом случае мы можем видеть, что генератор позаботится о возврате {Значение: val, сделано: bool} Объект для вас, который все обрабатывается под капотом в для ... из Отказ

Так как мы можем использовать генераторы в наше преимущество? Возвращаясь к нашему предыдущему примеру, мы можем упростить Предложение Итератор к следующему коду:

Sentence.prototype[Symbol.iterator] = function*() {
    var re = /\S+/g;
    var str = this._str;
    var match;
    while (match = re.exec(str)) {
        yield match[0];
    }
};

Обратите внимание, как функция итератора (сейчас генератор) намного меньше, чем предыдущая версия. Нам больше не нужно возвращать объект с Следующий функция, и нам больше не нужно иметь дело с возвращением {Значение: val, сделано: bool} объект. Хотя эти сбережения могут показаться минимальными в этом примере, его полезность будет легко реализована, поскольку ваши генераторы растут в сложности.

Преимущества

Как Джейк Арчибальд Указывает, некоторые преимущества этих генераторов:

  • Лень : Значения не рассчитываются заранее, поэтому, если вы не повторяете, до конца вы не потеряли время, рассчитав неиспользуемые значения.

  • Бесконечный : Поскольку значения не рассчитаны заранее, вы можете получить бесконечный набор значений. Просто убедитесь, что вы вырываетесь из цикла в какой-то момент.

  • Струнная итерация : Благодаря Symbol.itereator Строка теперь имеет свой собственный итератор, чтобы сделать петли над персонажами намного проще. Итализация по символам символов строки может быть настоящей болью. Это особенно полезно теперь, когда JavaScript ES5 поддерживает Unicode.

    для (var символ строки) { console.log (символ); }

Заключение

В то время как итераторы и генераторы не являются огромными дополнительными функциями, они помогают довольно быстро убирать код и сохранить его организованным. Сохранение итерационной логики с объектом, к которой она принадлежит, это хорошая практика, которая, кажется, большая часть фокусировки функций ES6. Стандарт, по-видимому, движется к структуре – способность и дизайн-дружелюбие Java, в то же время сохраняя скорость развития динамических языков.

Что вы думаете о новых функциях ES6? Что за интересные случаи использования у вас есть для итераторы и генераторы? Дайте нам знать об этом в комментариях!

Благодаря Джейк Арчибальд Для отличной статьи, подробную информацию о том, как итераторы и генераторы работают в ES6.