JavaScript中分配运算符中的AND运算符

86

我知道在 JavaScript 中可以这样做:

var oneOrTheOther = someOtherVar || "these are not the droids you are looking for...";

如果第一个表达式的值不为空(null)、未定义(undefined)或为假(false),则变量oneOrTheOther将取得第一个表达式的值。否则,它将获得第二个表达式的值。

然而,当我们使用逻辑与运算符时,变量oneOrTheOther被赋予什么值?

var oneOrTheOther = someOtherVar && "some string";

someOtherVar 不为假时会发生什么?
someOtherVar 为假时会发生什么?

我正在学习JavaScript,并且好奇在与AND运算符结合时会发生什么。


3
试试看。http://www.jsfiddle.net/uv6LR/ - icktoofay
1
请看我在相关帖子中的回答:http://stackoverflow.com/questions/3088098/in-javascript-what-does-it-mean-when-there-is-a-logical-operator-in-a-variable-d/3088498#3088498 - Anurag
在你的例子中,如果 someOtherVar 未定义,它将抛出一个错误。使用 window.someOtherVar 将允许它在 someOtherVar 未定义时取第二个值。 - Rich
7个回答

118

逻辑与运算符 (&&) 的基本原理是: 当第一个操作数为真值(truthy)时,返回第二个操作数的值;当第一个操作数为假值(falsy)时,则直接返回第一个操作数的值。例如:

true && "foo"; // "foo"
NaN && "anything"; // NaN
0 && "anything";   // 0

请注意,falsy值是那些在布尔上下文中强制转换为false的值,它们包括nullundefined0NaN、空字符串,当然还有false,其他任何值都会强制转换为true


啊,好的。谢谢。这很有道理,毕竟它是OR运算符的反向操作。 - Alex
因此,当与布尔值一起使用时,&& 如果两个操作数都为 true,则返回 true;否则返回 false。 (https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Logical_Operators#Description) - Bardelman
我喜欢这个例子。如果您能包含一些关于&&被称为“守卫”运算符的内容,那将非常好,因为这对于空值检查是很好的上下文。您甚至可以在这里引用Douglas Crockford:http://javascript.crockford.com/survey.html - Akrikos

44

&& 有时被称为 保护符 运算符。

variable = indicator && value

只有当指示器为真值时,它才能用于设置值。


3
非常清晰的回答。其他的答案让我感到困惑,但这个表达得非常清楚明白。谢谢! - ctaymor
我认为这个答案显然是错误的。在执行上述语句之后,“variable”的值是表达式“indicator && value”的值,无论它是什么。因此,赋值左侧变量的值总是被设置为某些东西,而不管右侧发生了什么(除非抛出错误)。不是吗? - Panu Logic

27

入门示例

如果你正试图访问"user.name",但出现了这种情况:

Uncaught TypeError: Cannot read property 'name' of undefined 

不用担心。现代浏览器今天就可以使用ES6可选链接。

const username = user?.name;

请参阅 MDN:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Optional_chaining

以下是一些更深入的解释,这些解释可能有助于理解“守卫运算符”。

在可选链式调用出现之前,您可以使用&& 运算符来解决赋值问题,通常称为 守卫运算符,因为它可以“守卫”不发生 undefined 错误。

以下是一些您可能觉得奇怪但请继续阅读,后面会有解释。

var user = undefined;
var username = user && user.username;
// no error, "username" assigned value of "user" which is undefined

user = { username: 'Johnny' };
username = user && user.username;
// no error, "username" assigned 'Johnny'

user = { };
username = user && user.username;
// no error, "username" assigned value of "username" which is undefined

说明:在保卫操作中,每个项都会被一个接一个地从左到右逐个评估。如果某个值的结果是假值,则停止评估并将该值分配给变量。如果到达最后一项,则无论其是否为假值,都会分配该项。

假值指的是这些值之一:undefined、false、0、null、NaN、'',而真值则表示假值。

额外内容:OR运算符

另一个常用的奇怪赋值方法是OR运算符,通常用于插件等:

this.myWidget = this.myWidget || (function() {
   // define widget
})();

如果“this.myWidget”为假,它将只分配代码部分。这很方便,因为您可以在任何地方声明代码,并多次声明,而不必关心以前是否已经分配,因为知道它只会被分配一次,因为使用插件的人可能会意外地多次声明脚本标记src。

说明:每个值按从左到右的顺序逐个评估。如果一个值为真,它停止评估并分配该值,否则继续进行,如果达到最后一项,则无论其是否为假,都将进行分配。

额外加分:在赋值中结合&&和||

现在你拥有终极权力,可以做非常奇怪的事情,比如在回文中使用它的非常奇怪的例子。

function palindrome(s,i) {
 return (i=i || 0) < 0 || i >= s.length >> 1 || s[i] == s[s.length - 1 - i] && isPalindrome(s,++i);
}

这里有深入的解释:JavaScript中的回文检查

祝你编码愉快。


谢谢,很棒的例子!对我理解 && 和 || 运算符有很大帮助!+1 - Lucky
谢谢您的回答!我很好奇JS会尝试访问最深层级属性多久?例如,如果您正在等待响应命中后端,使用var x = y && y.z是否安全? - Scott Savarie

20

Crockford也在这里称它为'guard operator': http://javascript.crockford.com/survey.html - Akrikos

3
根据ECMAScript 5.1注释第11.11节
对于逻辑或运算符(||),
expr1 || expr2如果可以转换为true,则返回expr1;否则,返回expr2。因此,当与布尔值一起使用时,||如果任一操作数为true,则返回true;如果两者都为false,则返回false。
在给定的示例中,
var oneOrTheOther = someOtherVar || "these are not the droids you are looking for...move along"; 结果将是someOtherVar的值,如果Boolean(someOtherVar)为true。(请参阅表达式的真实性)。 如果它是假的,则结果将是“这些不是您要找的机器人...继续前进”。
对于逻辑AND运算符(&&),
如果可以将expr1转换为false,则返回expr1;否则,返回expr2。因此,当与布尔值一起使用时,&&如果两个操作数都为true,则返回true;否则返回false。
在给定的示例中,
情况1:当Boolean(someOtherVar)为false时:它将返回someOtherVar的值。
情况2: 当Boolean(someOtherVar)为true时:它将返回“these are not the droids you are looking for...move along”。

1
我看待这个问题的方式不同于大多数答案,希望能对某些人有所帮助。
要计算涉及到||的表达式,你可以在找到一个真值项时停止表达式的计算。在这种情况下,你有两个知识点,而不仅仅是一个:
1.给定真值项,整个表达式评估为true。
2.知道了第一条,你可以终止计算并返回最后一个被评估的项。
例如,false || 5 || "hello"一直评估到包括5,因为它是真值,所以这个表达式评估为true并返回5。
因此,表达式的值用于if语句,但是最后评估的项用于变量赋值。
类似地,使用&&评估表达式涉及到在第一个假值项处终止。然后它产生一个false值,并返回最后一个被评估的项。(编辑:实际上,它返回最后一个被评估的非假值项。如果没有这样的项,则返回第一个。)
如果你现在阅读以上答案中的所有示例,一切都很清晰 :)
(这只是我的看法,以及我对它实际运作方式的猜测。但这并未经核实。)

0

我在工作中经常看到“&&”被滥用于赋值语句。这个问题有两个方面的考虑: 1)“指示器”检查有时是一个带有开销的函数,开发人员没有考虑到这一点。 2)开发人员很容易将其视为安全检查,而不考虑他们正在将false分配给他们的变量。我希望他们具有类型安全的态度,因此我让他们将这个:

var currentIndex = App.instance && App.instance.rightSideView.getFocusItemIndex();

改成这个:

var currentIndex = App.instance && App.instance.rightSideView.getFocusItemIndex() || 0;

这样他们就会得到一个预期的整数。


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