如何在无限循环中重用数组函数

时间:2017-05-20 23:26:09

标签: javascript ecmascript-6 infinite-loop

真正的代码更大,所以我不会发布它。它看起来非常像这样:

class A {
    process(source) {
        // I perform several operations with array helper functions here:
        const filtered = source.filter(item => item);
        const condition = filtered.some(item => item);

        if (condition) {
            const mapped = source.map(item => /* Mapping operations... */);
            const sorted = mapped.sort((a, b) => { /* Some sort conditions... */ });
            return sorted;
        } else {
            const mapped2 = filtered.map(item => /* A different mapping operation... */);
            return mapped2;
        }
    }
}

const a = new A();

while (true) {
    const source = getSourceFromSomewhere(); // Array (40 - 50 items aprox)
    const b = a.process(source);
    // ...
}
  

问题:基本上,性能; "不要在循环中制作功能"。

在每次迭代中都会创建一堆匿名函数。

我的解决方案:

class A {
    // Predefine it:
    sort() { /* Sort logic */ }
    map() { /* Map logic */ }
    map2() { /* Map logic */ }
    filter() { /* Filter logic */ }
    some() { /* Condition */ }

    process(source) {
        const filtered = source.filter(this.filter); // Note: Scope of 'this' is changed.
        const condition = filtered.some(this.some);

        if (condition) {
            const mapped = source.map(this.map);
            const sorted = mapped.sort(this.sort);
            return sorted;
        } else {
            const mapped2 = filtered.map(this.map2);
            return mapped2;
        }
    }
}
  

另一个问题:这些函数中的一些需要访问对象本身的属性,但this的范围已经改变。

调用.bind(this)而不是创建匿名函数值得吗?或几乎相同?

在我的案子中你会做什么?

提前致谢。

3 个答案:

答案 0 :(得分:1)

初始化您可以执行的类中的绑定函数

class Test {
    fn = (t) => this[t]
}

基本上和你想做的一样。

答案 1 :(得分:1)

  

问题:基本上,性能; “不要在循环中创建函数”。

你的前提不正确。

JavaScript引擎经过高度优化。每次通过循环或每次调用函数时,它们都不会费力地逐字符地读取源文本,更不用说每次调用回调时。他们扫描,解析和预编译。在最坏的情况下,每个函数调用只会创建一次item => item之类的函数。更有可能的是,它们将在初始扫描和解析过程中预先创建。

因此,在考虑是否自行预定义功能时,您无需担心性能问题。指导原则应该是程序的可读性和结构。

如果你想预先定义一个函数,只要它不使用this,考虑在类外定义它:

function filterFunc(item) { return item.val < MAX; }

class A {
  process() {
    const filtered = source.filter(filterFunc);

如果你确实需要'this`,那么在现代JS中,最好写

class A {
  filterFunc(item) { return item.val < this.MAX; }

  process() {
    const filtered = source.filter(item => this.filterFunc(item));

而不是担心绑定this.filterFunc让你写

class A {
  constructor () { this.filterFunc = this.filterFunc.bind(this); }

  process() {
    const filtered = source.filter(this.filterFunc);

答案 2 :(得分:1)

虽然在另一个答案中提到

class Test {
    // constructor etc.
    step = x => x + this.currentStep;
    process() {
        return this.arr.map(step);
    }
}

将是实现预期行为的简洁方法,因为this已绑定到实例,它需要仍处于第2阶段的公共类字段,因此在没有转换器的许多浏览器中尚不支持

最好记住,您始终可以this范围传递给mapfilter 等函数的第二个参数,因此您不必不必事先手动绑定您的函数。然后代码变为

class Test {
    // constructor etc.
    step(x) { return x + this.currentStep; }
    process() {
        return this.arr.map(step, this);
    }
}

在确保您的功能具有正确的范围时,这非常接近您所考虑的解决方案。

虽然我不太了解浏览器的内部工作原理,但我认为如果代码足够热(经常运行),优化的编译器可能不需要每次运行都重新创建这些匿名函数。