有没有一种方法可以使if条件是静态/常量?

3
假设我有以下代码片段:
let arr = [{...},{...} ...]// huge array of objects;

arr.forEach(i => {
  if(someOtherProperty == "one") {
    ...
  } else if(someOtherProperty == "two") {
    ...
  }...

})

基本上,我在循环体内有一个if-else-if阶梯。

条件不依赖于数组项。

我想知道是否有可能在循环执行之前评估if条件,因为该条件在整个循环运行期间是静态/恒定的

我能想到的几种方法是:

  1. keep the loop inside each of the if/else blocks. This way the if condition will be executed only once but I have more codes.
  2. Use an object like

    let condition = {
      one: someOtherProperty == "one",
      two: someOtherProperty == "two",
      ...
    }
    

    And use it in the condition like if(condition.one) and so on.

    Please suggest a better way to deal with situations like this to improve the efficiency.


你能解释一下你想要达到什么目的吗? - Phiter
@Phiter,感觉代码效率不高。由于数组的大小很大,并且有相当多的else-if块。对于每次迭代,都要评估条件,我认为可以在循环运行之前完成,但不知道最好的方法。 - Satish Kumar
这里可以用switch语句吗?我不太确定我理解问题的意思。 - jhpratt
1
分支预测可能会影响if语句的速度,如果需要一致的结果,则可能不需要进行预优化。最大的减速因素是使用forEach()而不是for语句,因为存在上下文切换开销。 - Patrick Roberts
@PatrickRoberts。在这种情况下,由于所有迭代的条件都相同,我猜想这样做不会改善性能。 - Satish Kumar
显示剩余2条评论
4个回答

2

我认为在这种情况下,条件语句内的代码有很大的区别,您可以使用以下方法使您的代码更加优美:

let arr = [1, 2, 3, 4, 5];
let str = "one";
const conditions = {
  "one": function(item, index) {
    console.log("one", item);
  },
  "two": function(item, index) {
    console.log("two", item);
  }
}

arr.forEach(conditions[str]);

或者,如果您想坚持基础知识,也可以这样做:

let arr = [1, 2, 3, 4, 5];
let str = "one";
var one = function(item, index) {
  console.log("one", item);
};
var two = function(item, index) {
  console.log("two", item);
};
switch (str) {
  case "one":
    arr.forEach(one);
    break;
  case "two":
    arr.forEach(two);
    break;
}


0
为了避免代码重复,您可以进行一次条件检查,然后迭代循环,在函数中放置其余的代码。
您还可以将循环迭代代码放在一个函数中并调用它,具体取决于您在循环中要做什么。
let arr = [{...},{...} ...]// huge array of objects;

if(someOtherProperty == "one") {
    arr.forEach(i => { ...functionOnArray(); });
    functionOne();
} else if(someOtherProperty == "two") {
    arr.forEach(i => { ...functionOnArray(); });
    functionTwo();
}...

function functionOnArray(){ ... }
function functionOne(){ ... }
function functionTwo(){ ... }

0
脑海中最好的解决方案是使用函数式方法。
let arr = [1,2,3,4,5,6,7,8,9]; // Huge array

let condFactory = (condition) => {
    if (condition === 'one') {
        console.log('This will only be called once, if condition==="one"',
                    'it will not be called for each element')
        return (item, index) => console.log('one (called for each element)', item, index);
    } else if (condition === 'two') {
        console.log('This will only be called once, if condition==="two"',
                    'it will not be called for each element')
        return (item, index) => console.log('two (called for each element)', item, index);
    }

    console.log('This will only be called once, if no condition matches',
                'it will not be called for each element')
    return (item, index) => console.log('No condition matched (called for each element)', item, index);
}

arr.forEach(condFactory(someOtherProperty));

对于 ES5:

var arr = [1,2,3,4,5,6,7,8,9]; // Huge array

var condFactory = function(condition) {
    if (condition === 'one') {
        console.log('This will only be called once, if condition==="one"',
                    'it will not be called for each element')
        return function(item, index) { console.log('one (called for each element)', item, index); };
    } else if (condition === 'two') {
        console.log('This will only be called once, if condition==="two"',
                    'it will not be called for each element')
        return function(item, index) { console.log('two (called for each element)', item, index); };
    }

    console.log('This will only be called once, if no condition matches',
                'it will not be called for each element')
    return function(item, index) { console.log('No condition matched', item, index); };
}

arr.forEach(condFactory(someOtherProperty));

这样,在循环开始之前就确定了每个条件要使用的函数,并在循环内部使用每个元素。

您可以扩展此单行代码

arr.forEach(condFactory(someOtherProperty));

将代码分成两行,以查看为什么 if...else 只被评估一次:
let functionBasedOnIfElse = condFactory(someOtherProperty); // Get the function based on your "someOtherProperty"
arr.forEach(functionBaseOnIfElse); // Pass reference to the function

正如您所看到的,if...else语句只会被评估一次。在该if...else中返回的函数将被传递给arr.forEach,并对数组中的每个元素进行调用。

编辑:添加默认返回值。

编辑2:更正了es5代码片段。

编辑3:扩展了案例以显示每个函数应用于数组中的每个项目。

编辑4:增加了有关为什么if...else只被评估一次的更多信息。

编辑5:添加了一些console.log以显示哪个部分将在哪个时间点被调用。


你的代码片段/方法与问题中提供的有何不同? - Satish Kumar
condFactory(someOtherProperty) 根据条件返回一个函数。扩展示例:let determinedFunction = condFactory(someOtherProperty); // 基于条件的函数 arr.forEach(determinedFunction) // 传递函数引用这样,if...else 只会被确定一次 -> 基于此返回一个函数 -> 此函数将为数组中的每个元素调用。 我会更新答案以包含这个信息。 - pascalpuetz
@SatishKumar,我更新了我的答案,展示了它与问题中的方法有何不同。 - pascalpuetz
我认为你对于“这样,if...else语句只会被确定一次”的部分是错误的。你刚刚传递了函数,它将被调用以处理数组中的每个元素。因此,条件将被_每次_评估。此外,问题中的代码片段和你的代码片段是等效的。你所做的就是将循环体放在一个函数中。 - Satish Kumar
这不是真的。condFactory()函数只被调用一次。然后根据条件仅仅一次返回函数。该函数确实会为每个元素调用一次,但它只包含您想要针对该条件运行的代码,而不是条件本身。我将再次更新答案以使其更清晰。 - pascalpuetz
啊,你说得对,我道歉。我没有注意到你在回调中返回了一个函数。我想你的方法几乎与这个相同。 - Satish Kumar

-2

你可以做的一件事是创建一个分支非匿名函数,然后将其映射到数组上。例如:

f =  {(x => if (prop1 == "one") 
     { ...} 
     else if (prop2 == "two") 
     {...} )}

然后执行 arr.forEach(i=> f(i))。 这正是Javascript的函数式特性的用途。
这大致与你尝试做的一样有效。如果你尝试聪明地使用 部分应用并将条件作为参数传递给该函数,它会更快。

那个语法甚至都不合法。 - Patrick Roberts
这是与问题中的代码片段相当的内容。 - Satish Kumar
x => if (...) 不等同于 x => { if (...) }。前者是语法错误。非表达式语句不能存在于没有括号的箭头函数中。 - Patrick Roberts

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接