我可以从内部函数中屈服吗?

时间:2015-03-28 04:14:16

标签: javascript for-loop generator yield ecmascript-6

使用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循环是令人厌恶的。

2 个答案:

答案 0 :(得分:20)

不,你不能在内部函数中使用yield。但在你的情况下,你不需要它。您始终可以使用for-of循环代替forEach方法。它看起来会更漂亮,您可以在其中使用continuebreakyield

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

如果您对其中的项目进行了一些操作,则可以使用for-of。否则,您绝对不需要创建此生成器,因为array本身有iterator interface

答案 1 :(得分:4)

不,你不能从回调中屈服(从技术上讲,它不是“内部函数”,这意味着其他的东西)。显然无法使用等效的forEach来调用*,或者,如果回调本身是生成器,则告诉forEach使用yield *调用回调。

另一种方法是编写函数forEachGen,如下所示:

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

基本上将for循环移动到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); }
});

然后做

yield *array.forEachGen(yieldSelf)

您可能对http://fitzgen.github.io/wu.js/感兴趣,它在包装器上使用forEach等方法定义了生成器的包装器。

async / await

使用await,您应该可以执行以下操作。

定义一个简单的回调,只返回自己的承诺。

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

forEachAsync将输入数组映射到promises数组中,并使用await *创建并返回所有单个promise已准备就绪的承诺。

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