【问题标题】:JavaScript OR (||) variable assignment explanationJavaScript OR (||) 变量赋值说明
【发布时间】:2011-01-07 05:31:14
【问题描述】:

鉴于这个 JavaScript 的 sn-p...

var a;
var b = null;
var c = undefined;
var d = 4;
var e = 'five';

var f = a || b || c || d || e;

alert(f); // 4

有人可以向我解释一下这种技术叫什么(我最好的猜测是这个问题的标题!)?以及它是如何/为什么起作用的?

我的理解是变量f 将被分配为第一个变量的最接近的值(从左到右),该变量的值不是空值或未定义,但我没有设法找到太多参考关于这项技术的资料,并且已经看到它被大量使用。

另外,这种技术是 JavaScript 特有的吗?我知道在 PHP 中做类似的事情会导致 f 具有真正的布尔值,而不是 d 本身的值。

【问题讨论】:

  • 老问题,但是关于 PHP,有一个可以使用的结构:$f=$a or $f=$b or $f=$c; // etc。 PHP 有|| 操作符和or 操作符,它们做同样的工作;但是,or 是在 赋值之后评估的,而 || 是在之前评估的。这也给你$a=getSomething() or die('oops');的perlish风格
  • 在 PHP 5.3 中,您可以省略三元运算符的中间部分,因此基于此...您也可以将其剪短一点:$f = $a ?: $b ?: $c;
  • 从 PHP 7 开始,您可以为此使用 ??$a = $b ?? 'default'
  • @SpencerRuskin 所以如果$b 为真,那么$a 将被分配$b 的值,其他'default'
  • 没错。查看此页面上的空合并运算符部分:php.net/manual/en/migration70.new-features.php

标签: javascript variables variable-assignment or-operator


【解决方案1】:

有关说明,请参阅short-circuit evaluation。这是实现这些运算符的常用方法;它不是 JavaScript 独有的。

【讨论】:

  • 请注意“陷阱”,即最后一个总是会被分配,即使它们都是未定义的、null 或 false。在链的末尾设置你知道不是 false、null 或 undefined 的东西是表明没有找到任何东西的好方法。
  • 我已经看到这种技术很多年了,但是当我想使用它时让我印象深刻的是表达式的结果没有转换为布尔值。你以后不能做if( true == f )。如果一个整数存储在 f 中,那么这个测试将总是返回 false。
  • 其实可以if(true == f),和if(f)一样:测试通过。如果你还想测试ftype,使用严格比较:if(true === f),确实会失败。
  • 是的,短路评估很常见。但这里的区别在于 JavaScript 返回停止执行的最后一个值的方式。 @Anurag 的回答更好地解释了这一点。
  • 不确定这是否是对初学者的最佳解释。我会推荐:javascript.info/logical-operators
【解决方案2】:

这是为了分配一个默认值,在这种情况下是y 的值,如果x 变量是falsy

JavaScript 中的布尔运算符可以返回一个操作数,而不是像其他语言那样总是返回一个布尔结果。

逻辑或运算符 (||) 返回其第二个操作数的值,如果第一个操作数为假,否则返回第一个操作数的值。

例如:

"foo" || "bar"; // returns "foo"
false || "bar"; // returns "bar"

Falsy 值是在布尔上下文中使用时强制转换为 false 的值,它们是 0nullundefined、空字符串、NaN 和当然false.

【讨论】:

  • +1 有没有其他类似的运算符?或者是|| 独家。
  • @Support (@Oscar):逻辑 && 运算符具有类似的行为,如果它本身 falsy 则返回第一个操作数的值并返回该值第二个操作数的,只有当第一个是 truthy 时,例如("foo" && "bar") == "bar"(0 && "bar") == 0
  • Falsy 实际上是技术术语。
  • 所以我们在这篇文章中了解了 ||、&&、“Falsy”和“Truly”。 “隐藏”礼物的最佳答案。
  • @Alex NB: "Truthy" (!"Truly")
【解决方案3】:

Javacript 将short-circuit evaluation 用于逻辑运算符||&&但是,它与其他语言的不同之处在于它返回最后一个停止执行的值的结果,而不是 truefalse 值。

以下值在 JavaScript 中被认为是虚假的。

  • ""(空字符串)
  • 0
  • 未定义

忽略operator precedence 规则并保持简单,以下示例显示了哪个值暂停了评估并作为结果返回。

false || null || "" || 0 || NaN || "Hello" || undefined // "Hello"

NaN 之前的前 5 个值是假的,所以它们都是从左到右计算的,直到它满足第一个真值 - "Hello" 这使得整个表达式为真,所以不会计算任何进一步的值,并且"Hello" 作为表达式的结果返回。同样,在这种情况下:

1 && [] && {} && true && "World" && null && 2010 // null

前 5 个值都是真值并被求值,直到它满足使表达式为假的第一个假值 (null),所以 2010 不再求值,null 作为结果返回表达方式。

您给出的示例是利用 JavaScript 的这个属性来执行赋值。它可以用于需要在一组值中获取第一个真值或假值的任何地方。下面的代码会将值 "Hello" 分配给 b,因为它更容易分配默认值,而不是执行 if-else 检查。

var a = false;
var b = a || "Hello";

您可以将下面的示例称为对该功能的利用,我相信它会使代码更难阅读。

var messages = 0;
var newMessagesText = "You have " + messages + " messages.";
var noNewMessagesText = "Sorry, you have no new messages.";
alert((messages && newMessagesText) || noNewMessagesText);

在警报中,我们检查messages 是否为假,如果是,则评估并返回noNewMessagesText,否则评估并返回newMessagesText。由于在这个例子中它是假的,我们在 noNewMessagesText 处停止并警告"Sorry, you have no new messages."

【讨论】:

  • 这是我认为最好的答案,因为以下解释:However, it's different to other languages in that it returns the result of the last value that halted the execution, instead of a true, or false value.
  • @mastazi 是的,恕我直言,它应该用粗体显示。
  • 应该是答案,它显示了在测试用例中选择的值。
  • 同意,这是我最喜欢的答案,因为它专门解决了 JavaScript 变量分配问题。此外,如果您选择使用三元作为后续变量之一来测试赋值(在运算符之后),则必须将三元括在括号中以使赋值评估正常工作。
【解决方案4】:

Javascript 变量没有类型,因此 f 可以被分配一个整数值,即使它是通过布尔运算符分配的。

f 被分配了最接近的值,不等于 false。所以0、false、null、undefined,都被传递过来了:

alert(null || undefined || false || '' || 0 || 4 || 'bar'); // alerts '4'

【讨论】:

  • 别忘了'' 在这种情况下也等于 false。
  • 赞成指出f is assigned the NEAREST value,这是非常重要的一点。
  • "Nearest" 并不完全正确,尽管它确实具有这种外观。布尔运算符|| 是一个布尔运算符,它有两个操作数:左侧和右侧。如果|| 的左侧是truthy,则操作解析到左侧,而忽略右侧。如果左边是falsy,它解析到右边。所以null || undefined || 4 || 0 实际上解析为undefined || 4 || 0 解析为4 || 0 解析为4
  • @devios1 但4 是最近的
【解决方案5】:

它没有任何魔法。像a || b || c || d 这样的布尔表达式是惰性求值的。 Interpeter 查找a 的值,它是未定义的,所以它是假的,所以它继续前进,然后它看到b 为空,它仍然给出错误的结果,所以它继续前进,然后它看到c - 同样的故事。最后它看到d 并说“嗯,它不是空的,所以我有我的结果”并将它分配给最终变量。

这个技巧适用于所有对布尔表达式进行惰性短路求值的动态语言。在静态语言中它不会编译(类型错误)。在渴望评估布尔表达式的语言中,它会返回逻辑值(即在这种情况下为 true)。

【讨论】:

  • 在漂亮的静态语言 C# 中,可以使用 ??运算符 á la: 对象 f = a ??乙?? C ?? ?? e;
  • herzmeister - 谢谢!我不知道吗?运算符可以在 C# 中链接并用于惰性求值技术
  • 正如其他地方提到的,最后一个d 将被分配,无论它是否为空/未定义。
  • 一点更正:|| 运算符总是在左侧为假时解析整个右侧操作数。作为一个布尔运算符,它只看到两个输入:左侧和右侧。解析器不会将它们视为一系列术语,因此当它找到第一个真值时它实际上不会停止除非该值也是另一个 || 的左手操作数。
【解决方案6】:

这个问题已经得到了几个很好的答案。

总之,这种技术利用了语言编译方式的一个特性。也就是说,JavaScript 会“短路”布尔运算符的求值,并将返回与第一个非 false 变量值或最后一个变量包含的任何值相关联的值。请参阅 Anurag 对那些将评估为 false 的值的解释。

出于多种原因,使用这种技术并不是一种好的做法;但是。

  1. 代码可读性:这是使用布尔运算符,如果无法理解其编译行为,则预期结果将是布尔值。

  2. 稳定性:这是使用一种语言编译方式的特性,该特性在多种语言之间是不一致的,因此,它可能会成为未来更改的目标。

  3. 已记录的功能:有一个现有的替代方案可以满足此需求并且在更多语言中保持一致。这将是三元运算符:

    () ?值 1:值 2。

使用三元运算符确实需要更多的输入,但它清楚地区分了正在评估的布尔表达式和分配的值。此外,它可以被链接起来,因此可以重新创建上面执行的默认分配类型。

var a;
var b = null;
var c = undefined;
var d = 4;
var e = 'five';

var f =  ( a ) ? a : 
                ( b ) ? b :
                       ( c ) ? c :
                              ( d ) ? d :
                                      e;

alert(f); // 4

【讨论】:

  • potentially be targeted for change in the future. 是的,但我不适用于 javascript。
  • 来到这里,看到了上述所有答案,并在想自己只是看错了任务。我刚刚在阅读 Robert C Martin 的 Clean Code,这种类型的作业肯定违反了“没有副作用”的规则......虽然作者自己说他的书只是生成好代码的众多技术之一,但我仍然感到惊讶的是,没有其他人反对这种分配。 +1
  • 感谢您的回复。我认为更多的人在编写代码时需要考虑副作用,但直到有人花了很多时间维护其他人的代码。他们通常不会考虑。
  • 你真的认为怪物比a || b || c || d || e更清晰?
  • @AlbertRothman 我没有看到任何副作用。没有任何东西发生变异。它只是 null 合并的简写,这是许多语言中非常常见的功能。
【解决方案7】:

返回输出第一个真值

如果全部为假,则返回最后一个假值。

例子:-

  null || undefined || false || 0 || 'apple'  // Return apple

【讨论】:

    【解决方案8】:

    它将新变量 (z) 设置为 x 的值,如果它是“真实的”(非零,一个有效的对象/数组/函数/不管它是什么)或 y 否则。这是在x 不存在的情况下提供默认值的一种相对常见的方式。

    例如,如果你有一个带有可选回调参数的函数,你可以提供一个不做任何事情的默认回调:

    function doSomething(data, callback) {
        callback = callback || function() {};
        // do stuff with data
        callback(); // callback will always exist
    }
    

    【讨论】:

      【解决方案9】:

      称为短路算子。

      短路求值表示,仅当第一个参数不足以确定表达式的值时,才执行或计算第二个参数。当 OR (||) 函数的第一个参数计算结果为 true 时,整体值必须为 true。

      它也可以用来设置函数参数的默认值。`

      function theSameOldFoo(name){ 
        name = name || 'Bar' ;
        console.log("My best friend's name is " + name);
      }
      theSameOldFoo();  // My best friend's name is Bar
      theSameOldFoo('Bhaskar');  // My best friend's name is Bhaskar`
      

      【讨论】:

        【解决方案10】:

        表示如果设置了x,则z的值为x,否则如果设置了y,则其值为z的值。

        和这个一样

        if(x)
          z = x;
        else
          z = y;
        

        这是可能的,因为 JavaScript 中的逻辑运算符不返回布尔值,而是返回完成操作所需的最后一个元素的值(在 OR 语句中它将是第一个非假值,在 AND 语句中它将是最后一个)。如果操作失败,则返回false

        【讨论】:

        • 这是错误的!如果 (x) { z = x; } else {z = y;} 如果第一个值为 false,则始终分配第二个值,而不取决于实际值。
        • 除了我认为如果 x 为 false 时它只是将 y 分配给 z。这就是它在 FF 中为我工作的方式,当然,这也可能取决于实现。
        • 关于返回 false 的最后一部分不是真的(没有双关语的意思)。如果第一个值是假的,|| 运算符只返回第二个值,不管它是否为真。
        • -1。您的等效代码 sn-p 是准确的,但重要的是,如果 z 的值是 truthy,则该值会被设置为 x。否则它被设置为y 的值。这意味着如果将x 设置为例如0 或空字符串"",则不会按照您说的那样做,因为这些值是falsy。跨度>
        【解决方案11】:

        它将评估 X,如果 X 不为空,则为空字符串或 0(逻辑假),然后将其分配给 z。如果 X 为 null、空字符串或 0(逻辑假),则将 y 分配给 z。

        var x = '';
        var y = 'bob';
        var z = x || y;
        alert(z);
        

        将输出'bob';

        【讨论】:

        • 你应该澄清你所说的“空”是什么意思。空字符串强制为false,但空数组或对象强制为true
        • @Daniel "null, empty, or 0" -- null 将应用于数组和对象。不过,要点是。
        【解决方案12】:

        根据 Bill Higgins 的博客 帖子; the Javascript logical OR assignment idiom(2007 年 2 月),这种行为在 v1.2 中是正确的(至少)

        他还建议了它的另一种用途(引用): "跨浏览器差异的轻量级标准化"

        // determine upon which element a Javascript event (e) occurred
        var target = /*w3c*/ e.target || /*IE*/ e.srcElement;
        

        【讨论】:

          猜你喜欢
          • 2016-07-25
          • 2016-03-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-03-22
          • 2010-12-11
          相关资源
          最近更新 更多