【问题标题】:Is there any way I can apply filter method to a custom iterator? [duplicate]有什么方法可以将过滤器方法应用于自定义迭代器? [复制]
【发布时间】:2018-09-17 06:17:54
【问题描述】:

我正在研究如何在 JavaScript 中使用生成器。

由于生成器返回迭代器,我想我可以像iterable.filter() 一样使用它,就像array.prototype.filter 一样。

但是,可迭代对象没有filter、map、forEach、reduce方法。

所以,我制作了 filter、map、reduce、forEach 方法的生成器版本,如下所示。

我当前的代码

'use strict';

function* range(n) {
    for (let i = 1; i <= n; i++) {
        yield i;
    }
}

function* filter(context, predicate) {

    for (let i of context) {
        if (predicate(i) === true) {
            yield i;
        }
    }

}

function isEven(value) {
    return value % 2 === 0;
}

console.log(
    ...filter(range(10), isEven)
);

此代码确实有效,但我想像 range(10).filter(isEven) 一样使用它而不是 filter(range(10), isEven)

有什么方法可以实现我想要的吗?

我正在研究 ES6 代理,Reflect,但是嗯...我不确定这些 ES6 的东西是否对我有帮助。

我想怎么用

range(10)
    .filter(isEven) //generator version of filter
    .map(multiplyBy5) //generator version of map
    .forEach(console.log); //generator version of forEach

再试一次 - 不...哈哈哈...

这段代码也可以,但这就像一个笑话......

'use strict';

function* filter(predicate) {
    for (let i of this) {
        if(predicate(i) === true) {
            yield i;
        }
    }   
}


function* map(project) {
    for (let i of this) {
        yield project(i);
    }   
}

function* range(end) {
    for (let i = 0; i <= end; i++) {
        yield i;        
    }
}

const isEven = (v) => v % 2 === 0;
const multiplyBy = (v) => (by) => v * by;

var range10_filterByEven = filter.bind(range(10), isEven);
var range10_filterByEven_multiplyBy10 = map.bind(range10_filterByEven(), multiplyBy(10));

console.log(
    ...range10_filterByEven_multiplyBy10() //0 20 40 60 80 100
);

看起来更好,虽然这不是我想要的样子。

'use strict';

function filter(predicate) {
    return function* f() {
        for (let i of this) {
                if(predicate(i) === true) {
                    yield i;
                }
            }
    }   
}


function map(project) {
    return function* m() {
        for (let i of this) {
            yield project(i);
        }  
    }
}

function range(end) {
    return function* r() {
        for (let i = 0; i <= end; i++) {
            yield i;        
        }
    }
}

const isEven = (v) => v % 2 === 0;
const multiplyBy = (v) => (by) => v * by;


function pipe() {
    return [...arguments].reduce(function(chain, current) {
        return current.bind(chain()); 
    })}

console.log(
    ...pipe(
        range(10),
        filter(isEven),
        map(multiplyBy(10))
    )()
);

【问题讨论】:

  • 您想要使用它的方式与使用生成器函数的方式根本不同。您可以编写 range 使其不是生成器(但在内部使用)并返回带有 filter 的对象,但是如果我们不这样做,您也可以做很多其他事情t 以 range 作为生成器开始,所以...
  • @T.J.Crowder 感谢您的反馈!让我试试别的……

标签: javascript


【解决方案1】:

您可能只是扩展生成器原型,虽然这看起来很老套,我不确定我是否会推荐这种方法。

另一方面,我相信这是您所期望的最简单的方法。

function* range(n) {
    for (let i = 1; i <= n; i++) {
        yield i;
    }
}

// "Generator" is not resolvable at the top level
var Generator = Object.getPrototypeOf(function* () {});

Generator.prototype.filter = function*(predicate) {
    for (let i of this) {
        if (predicate(i) === true) {
            yield i;
        }
    }        
}

for ( var elem of range(10).filter( x => x<5) ) {
    console.log(elem);
}

for ( var elem of range(10).filter( x => x<5 ).filter( x => x<3 ) ) {
    console.log(elem);
}

可能会以类似的方式添加其他运算符。

【讨论】:

  • 这看起来不错!!它也给了我很多提示!谢谢!
  • 谢谢,如果您认为这适合您,请接受此作为答案。
猜你喜欢
  • 2013-01-05
  • 1970-01-01
  • 2020-04-21
  • 1970-01-01
  • 1970-01-01
  • 2014-10-27
  • 2019-10-22
  • 2010-09-30
  • 2020-07-28
相关资源
最近更新 更多