Могу ли я получить из внутренней функции?

С генераторами ES6 я вижу такой код:

var trivialGenerator = function *(array) {
    var i,item;
    for(var i=0; i < array.length; i++){
        item = array[i];
        yield item;
    };
};

Можно ли написать что-то более похожее на код ниже?

var trivialGenerator = function *(array) {
    array.forEach(function *(item){
        yield item;
    });
};

Я спрашиваю, потому что классический цикл for - мерзость.

Ответ 1

Нет, вы не можете использовать yield внутри внутренней функции. Но в вашем случае вам это не нужно. Вы всегда можете использовать for-of вместо forEach метод. Это будет выглядеть намного красивее, и вы можете использовать continue, break, yield внутри него:

var trivialGenerator = function *(array) {
    for (var item of array) {
        // some item manipulation
        yield item;
    }
}

Вы можете использовать for-of, если у вас есть некоторые манипуляции с элементом внутри него. В противном случае вам абсолютно не нужно создавать этот генератор, поскольку array имеет iterator interface изначально.

Ответ 2

Нет, вы не можете уступить от обратного вызова (технически это не "внутренняя функция", что означает что-то еще). Очевидно, нет способа вызвать forEach с эквивалентом * или, если сам обратный вызов является генератором, сообщить forEach для вызова обратного вызова с помощью yield *.

Один из вариантов - написать функцию forEachGen следующим образом:

function *forEachGen(array, fn) { for (var i of array) yield *fn(i); }

по существу перемещая for-loop в forEachGen. Определение небольшого генератора выборок как

function *yieldSelf(item) { yield item; }

forEachGen будет использоваться как

yield *forEachGen(array, yieldSelf);

Это предполагает, что обратный вызов является самим генератором, поскольку вы, кажется, подразумеваете, что хотите в своем примере. Если обратный вызов был ROF (обычная старая функция), например

function returnSelf(item) { return item; }

Тогда это будет

function *forEachGen(array, fn) { for (var i of array) yield fn(i); }

используется как

yield *forEachGen(array, returnSelf);

Если вы не возражаете добавить это в прототип массива, то

Object.defineProperty(Array.prototype, 'forEachGen', { value :
    function *(fn) { for (i of this) yield fn(i); }
});

то do

yield *array.forEachGen(yieldSelf)

Вам может быть интересен http://fitzgen.github.io/wu.js/, который определяет оболочку для генераторов с такими методами, как forEach на обертке.

async/await

С помощью await вы сможете сделать следующее.

Определите тривиальный обратный вызов, который просто возвращает обещание для себя.

async function returnSelf(item) { return await item; }

forEachAsync отображает входной массив в массив promises и использует await * для создания и возврата обещания для всех индивидуальных promises, которые будут готовы.

async function forEachAsync(values, fn) {
  return await *values.map(returnSelf);
}

Мы можем рассматривать результат как обычное обещание и распечатывать его в then:

forEachAsync([1,2,3], returnSelf) .
  then(result => console.log(result);

или используйте небольшую оболочку асинхронного типа IIFE, чтобы дождаться результата, а затем распечатайте его:

(async function() { 
    console.log(await forEachAsync([1,2,3], returnSelf));
})();

Протестировано с помощью

babel-node --experimental test.js