JavaScript OR(||)变量分配说明


351

鉴于这段JavaScript代码...

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将为变量分配第一个变量的最接近的值(从左到右),该变量的值不为null或未定义,但是我没有设法找到有关此技术的大量参考资料,并且看到它用了很多。

另外,这项技术是否专门针对JavaScript?我知道在PHP中执行类似的操作会导致f具有真正的布尔值,而不是其d本身的值。


4
古老的问题,但是关于PHP,您可以使用以下结构:$f=$a or $f=$b or $f=$c; // etc。PHP同时具有||运算符和or运算符,它们执行相同的工作。但是or赋值之后进行评估赋值||之前进行评估。这也为您带来了$a=getSomething() or die('oops');
Manngo '16

1
在PHP 5.3中,您可以省去三元运算符的中间部分,以便以此为基础...您还可以将其缩短一些,例如: $f = $a ?: $b ?: $c;
Rei

1
从PHP 7开始,您可以使用??它。$a = $b ?? 'default'
Spencer Ruskin '18

@SpencerRuskin因此$a将被分配$bif的$b值为true,other 'default'
老男孩

那就对了。请看此页面上的空合并运算符部分:php.net/manual/en/migration70.new-features.php
Spencer Ruskin,

Answers:


212

有关说明,请参阅短路评估。这是实现这些运算符的常用方法。它不是JavaScript所独有的。


57
只需记住“陷阱”,即即使它们都是未定义的,null或false,也将始终分配最后一个。在链的末尾设置您知道的东西不是虚假,空值或未定义,这是发出未发现任何信号的好方法。
2011年

我已经看过这种技术很多年了,但是当我想使用它时,令我震惊的是表达式的结果没有转换为布尔值。你以后不能做if( true == f )。如果将整数存储在f中,则此测试将始终返回false。

9
实际上,您可以执行if(true == f),这与if(f):测试将通过。如果你也想测试f,使用严格的比较:if(true === f),这确实会失败。
Alsciende

5
是的,短路评估很常见。但是,此处的区别在于JavaScript返回终止执行的最后一个值的方式。@Anurag的答案在解释这一点上做得更好。
Ben.12

不确定这是否是初学者的最佳解释。我建议:javascript.info/logical-operators
csguy

198

如果变量是falsy,则可以指定一个默认值,在这种情况下为的值。yx

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

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

例如:

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

Falsy值是谁要挟到false布尔上下文中使用时,它们是0nullundefined,一个空字符串,NaN当然false


1
+1还有这样的运算符吗?还是||排他的。
OscarRyz 2010年

9
@Support(@Oscar):逻辑&&运算符也有类似的行为,它返回第一个操作数的值,如果它本身falsy并返回第二个操作数的值,只有第一个是truthy,如("foo" && "bar") == "bar"(0 && "bar") == 0
CMS

12
Falsy实际上是技术术语。
ChaosPandion

8
因此,我们在本文中了解了||,&&,“ Falsy”和“ Truly”。“隐藏”礼物的最佳答案。
Alex

4
@Alex NB:“ Truthy”(!“ Truly”)
Bumpy

182

Javacript 对逻辑运算符和使用短路评估||&&但是,它与其他语言的不同之处在于,它返回停止执行的最后一个值的结果,而不是truefalse值。

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

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

下面的示例忽略了运算符的优先级规则,并且保持简单,下面的示例显示哪个值停止了评估,并作为结果返回。

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

直到第一个5个值NaN都是虚假的,因此它们都从左到右进行求值,直到满足第一个真实值为止- "Hello"这使整个表达式为true,因此将不对任何向上的值进行求值,并"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和alert "Sorry, you have no new messages."


36
我认为这是最好的答案,原因如下: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

1
@mastazi是的,它应该以粗体字体恕我直言。
noober

6
应该是答案,它显示了在测试用例中选择的值。
丹丹

同意,这是我最喜欢的答案,因为它专门解决了JavaScript变量分配问题。此外,如果您选择使用三元数作为后续变量之一来测试赋值(在运算符之后),则必须将三元数用括号括起来才能使赋值评估正常工作。
乔伊·T

这应该是公认的答案
艾伦

49

Javascript变量未输入类型,因此即使通过布尔运算符分配了f,也可以为其分配一个整数值。

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

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

13
''在这种情况下,请不要忘记也等于false。
Brigand

赞成指出f is assigned the NEAREST value这一点很重要。
steviejay

3
“最近”虽然确实具有这种外观,但并不是很正确。作为布尔||运算符的布尔运算符具有两个操作数:左侧和右侧。如果的左侧||true,则操作解析为左侧,而忽略右侧。如果左侧是伪造的,它将解析为右侧。所以null || undefined || 4 || 0实际上解析undefined || 4 || 0解析为4 || 0解析为4
devios1 17-10-16

29

没有任何魔术。像这样的布尔表达式a || b || c || d会延迟计算。Interpeter寻找的值a,它是未定义的,所以它是false,因此它继续前进,然后看到b哪个为null,它仍然给出错误的结果,因此它继续前进,然后看到c-同一故事。终于看到了d并说“呵呵,它不是null,所以我得到了结果”,并将其分配给最终变量。

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


6
在漂亮的静态语言C#中,可以使用?? 运算符ala:对象f = a ?? b ?? C ??d ?? e;
herzmeister 2010年

2
herzmeister-谢谢!我不知道那个?? 运算符可以用C#链接起来并用在惰性评估技术中
Marek 2012年

3
如其他地方提到的那样,最后一个d将被分配,无论它是否为null / undefined。
BlackVegetable

稍作修正:||运算符总是在左侧错误时解析为整个右侧操作数。作为布尔运算符,它只会看到两个输入:左侧和右侧。解析器不会将它们视为一系列术语,因此,它在找到第一个真实值时不会真正停止,除非该值也是another的左操作数||
devios1 17-10-16

8

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

总之,该技术利用了语言的编译功能。也就是说,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。
丹丹

来到这里,看到了以上所有答案,并在想自己那件事看起来有些不对劲。我刚刚读过罗伯特·C·马丁(Robert C Martin)的“干净代码”,这种类型的作业肯定违反了“没有副作用”的规则……而作者本人指出,他的书只是生成良好代码的许多技术之一,我仍然感到惊讶的是,没有其他人反对这种任务。+1
阿尔伯特·罗斯曼

感谢您的答复。我认为,越来越多的人在编写代码时需要考虑副作用,但是直到有人花费大量时间维护他人的代码为止。他们通常不考虑这一点。
WSimpson

1
您真的以为怪物比a || b || c || d || e吗?
devios1 17-10-16

1
@AlbertRothman我看不到任何副作用。什么都没有突变。它只是空合并的简写,这在许多语言中都是很常见的功能。
devios1 17-10-16

7

返回输出第一个真值

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

例:-

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

4

它将新变量(z)设置为x“真”(非零,有效对象/数组/函数/无论是什么)的值或y其他值。这是一种比较常见的提供默认值的方式,以防万一x不存在。

例如,如果您有一个使用可选回调参数的函数,则可以提供不执行任何操作的默认回调:

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

1

这意味着,如果x设置了,则的值z将为x,否则如果y设置了则将其值设置为z的值。

和...一样

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

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


5
这是错的!如果(x){z = x; } else {z = y;}如果第一个值为false,则始终分配第二个值,而与实际值无关。
evilpie10年

除了我认为如果x为false,它只是将y分配给z 。那就是在FF中对我起作用的方式,当然,这也可能取决于实现。
tvanfosson 2010年

7
关于返回假的最后一部分不是真的(没有双关语)。如果第一个值是false,则||运算符将仅返回第二个值,而不管它是否真实。
马修·克鲁姆利

-1。您的等效代码段是准确的,但要点是,如果该值是truezx则将其设置为该值。否则,它将设置为的值。这意味着,例如,如果将if 设置为或空字符串,那么这将不执行您所说的操作,因为这些值是falsyyx0""
丹尼尔·卡西迪

1

它称为短路运算符。

短路评估表示,仅当第一个参数不足以确定表达式的值时,才执行或评估第二个参数。当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`

0

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

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

将输出'bob';


您应该澄清“空”的含义。空字符串强制转换为false,但空数组或对象强制转换为true
丹尼尔·卡西迪

@Daniel“ null,empty或0”-对于数组和对象,null将适用。点,但是。
tvanfosson

0

根据比尔·希金斯的博客文章;Javascript逻辑或赋值习惯(2007年2月),此行为自v1.2开始(至少)

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

// determine upon which element a Javascript event (e) occurred
var target = /*w3c*/ e.target || /*IE*/ e.srcElement;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.