в javascript порядок вычисления аргументов и отложенная оценка

#javascript

#javascript

Вопрос:

  1. если function( arg1, arg2 ) я прав, полагая, что arg1 это гарантированно вычисляется раньше arg2 (в отличие, например, от классического C)?

  2. есть ли какой-либо способ создать функцию, в которой аргументы не вычисляются, а скорее оцениваются по требованию? например, if( cond1 || cond2 ) вычисляется cond2 тогда и только тогда, когда cond1 равно false. возможно ли написать нашу собственную if подобную функцию?

например, могу ли я написать функцию, подобную oracle nvl( arg1, arg2, ... ) , которая возвращает первый ненулевой аргумент, лениво оценивая их. при обычном вызове функции все аргументы вычисляются до выполнения тела функции.

Ответ №1:

Аргументы функции вычисляются до того, как они передаются функции, поэтому то, что вы запрашиваете, технически невозможно. Однако вы могли бы сделать это:

 function nvl() {
    for (var i = 0; i < arguments.length; i  ) {
        var res = arguments[i]();
        if (res)
            return res;
    }
}

nvl(function() { return false; }, 
    function() { return 7; }, 
    function() { return true; });
  

Вызов nvl возвращает 7 .

Создаются все оболочки функций, но внутри вычисляются только тела первых двух nvl .

Это не совсем красиво, но это позволило бы вам предотвратить дорогостоящую операцию в теле любой из функций после того, как первая вернет истинное значение.

Комментарии:

1. ты больной щенок, и я тебя хвалю. (хотя для вашего примера nvl() false будет возвращено, поскольку оно не равно null.) нужно ли вам также что-то изменить в области видимости, чтобы функции вызывались в одной и той же области?

2. Это совершенно бессмысленно (без обид). Код false || 7 || true обладает идентичной функциональностью, как я пытался указать. @cc young — нет, этого не будет. if(res) это не нулевая проверка, это ложная проверка.

3. Я знаю, что ваш код выполнил то, что вы сказали, и я думал, что выразил свою признательность — все, что я пытался сделать, это сказать, что оригинальный oracle nvl() работает не так — что совершенно не отражается на вашем коде

4. @cwolves — Если вы принимаете «идентичный» за «вроде как одинаковый», то да. Это делается в функции, которую ищет OP. Ваш пример очень хорош и релевантен, но это невозможно выполнить в функции, потому что аргументы все равно будут оценены первыми.

5. OP не знает, о чем он просит. Он запрашивает функциональность с другого языка, потому что это то, к чему он привык. Если вы хотели это в вызове функции, это просто fn(false || 7 || true) , но это не то, чего хотел OP, он хотел функцию типа NVL, которую вы написали, но эта функция бесполезна, потому что ее можно на 100% заменить на false || 7 || true . Использование оператора OR ЯВЛЯЕТСЯ правильным способом сделать это в JavaScript; копирование способа выполнения другого языка — нет.

Ответ №2:

в вашем первом примере, да, если вы вызываете функцию, они будут оцениваться по порядку.

Во 2-м примере JS не оценивает каждый параметр (точно так же, как C), например:

 if(true || x  ){
  

x никогда не будет запускаться.

Что именно вы пытаетесь сделать?

Комментарии:

1. хороший пример … прекрасно показывает, как условия лениво вычисляются в javascript.

2. правильно! хотелось бы написать функцию, подобную oracle <code>nvl()</code>, которая возвращает первый ненулевой аргумент. как и <code>if</code>, аргументы должны оцениваться лениво.

3. в этом нет смысла. || Оператор выполняет то же самое: cond1 || cond2() || cond3() и т.д. Он будет вычисляться только до тех пор, пока значение не будет равно false.

Ответ №3:

  1. ДА
  2. Да, с помощью if(cond1 || cond2) условие 2 будет вычислено, если условие 1 равно false.

Вот функция, которая возвращает первый истинный аргумент:

 function firstDefinedArgument(){
    for(var i in arguments){
        if(arguments[i]){
           return arguments[i];
        }
     }
 }
  

Так, например, firstDefinedArgument(0, null, undefined, "", "hello", "goodbye") возвращалось бы "hello" .

Если бы вы хотели вернуть первый ненулевой аргумент вместо первого истинного, вы бы заменили if(arguments[i]) на if(arguments[i] !== null) . Эта функция вернет 0 результат в приведенном выше примере.

Комментарии:

1. правильно, но хотелось бы написать функцию, которая ведет себя аналогично

2. @cc young Я создал подобную функцию. Это то, что вы хотели?

3. Нет. Аргументы все еще оцениваются до их передачи. То, чего хочет OP, в принципе, невозможно, хотя у меня есть идея.