鉴于这段javascript…
1 2 3 4 5 6 7 8 9
| 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');的珍珠风格。
- 在php 5.3中,可以省略三元运算符的中间部分,因此基于此…你也可以把它剪短一点,做成这样的东西:$f = $a ?: $b ?: $c;。
- 从php 7开始,您可以使用??来实现这一点。$a = $b ?? 'default'
- @如果$b是真的,那么会把$a的值赋给$b,其他'default'?
- 这是正确的。请参阅本页上的空合并运算符部分:php.net/manual/en/migration70.new-features.php
说明见短路评估。这是实现这些操作符的一种常见方法;它不是Javascript独有的。
- 注意"gotcha",即最后一个总是被分配,即使它们都是未定义的、空的或假的。在链的末尾设置您知道的内容不是假的、空的或未定义的,这是一个很好的方法来表示没有找到任何内容。
- 我已经看过这种技术很多年了,但是当我想使用它的时候,令我吃惊的是表达式的结果不是强制转换为布尔值。你以后不能做if( true == f )。如果整数存储在f中,则此测试将始终返回false。
- 实际上,你可以做if(true == f),这和if(f)是一样的:测试会通过的。如果您还想测试f的类型,请使用严格的比较:if(true === f),这确实会失败。
- 是的,短路评估很常见。但这里的区别在于javascript返回停止执行的最后一个值的方式。@阿努拉格的回答在解释这一点上做得更好。
这样做是为了指定一个默认值,在这种情况下,如果x变量不稳定,则指定y的值。
javascript中的布尔运算符可以返回一个操作数,而不像其他语言那样总是一个布尔结果。
逻辑或运算符(||返回第二个操作数的值,如果第一个操作数不正确,则返回第一个操作数的值。
例如:
1 2
| "foo" ||"bar"; // returns"foo"
false ||"bar"; // returns"bar" |
错误值是在布尔上下文中使用时强制使用false的值,它们是0、null、undefined、空字符串、NaN,当然还有false。
- +1.是否有其他类似的接线员?或者是||独占的。
- @支持(@oscar):逻辑&&运算符有类似的行为,如果第一个操作数本身错误,则返回第一个操作数的值,如果第一个操作数是真的,则返回第二个操作数的值,例如("foo" &&"bar") =="bar"和(0 &&"bar") == 0。
- falsy实际上是技术术语。
- 因此,我们在这篇文章中了解了、&;&;、"falsy"和"really"。最好的答案是"隐藏的"礼物。
- @亚历克斯NB:"特鲁西"(!)真的""
JavaScript对逻辑运算符||和&&使用短路评估。但是,它不同于其他语言,因为它返回停止执行的最后一个值的结果,而不是true或false值。
以下值在JavaScript中被认为是错误的。
忽略了运算符优先规则,并保持简单,下面的示例显示哪个值使计算停止,并作为结果返回。
1
| false || null ||"" || 0 || NaN ||"Hello" || undefined //"Hello" |
到NaN的前5个值是不稳定的,因此它们都是从左到右进行计算的,直到满足第一个真实值"Hello",这使得整个表达式为真,因此任何进一步向上的值都不会进行计算,并且"Hello"作为表达式的结果返回。同样,在这种情况下:
1
| 1 && [] && {} && true &&"World" && null && 2010 // null |
前5个值都是真实的,并且被评估,直到它满足第一个使表达式为假的错误值(null,所以2010不再被评估,null作为表达式的结果返回。
您给出的示例是使用javascript的这个属性来执行分配。它可以用于任何需要在一组值中获得第一个真实或不稳定值的地方。下面的代码将把值"Hello"分配给b,因为这样可以更容易地分配默认值,而不是执行if-else检查。
1 2
| var a = false;
var b = a ||"Hello"; |
您可以将下面的示例称为对该特性的利用,我相信它会使代码更难阅读。
1 2 3 4
| var messages = 0;
var newMessagesText ="You have" + messages +" messages.";
var noNewMessagesText ="Sorry, you have no new messages.";
alert((messages && newMessagesText) || noNewMessagesText); |
在警报中,我们检查messages是否错误,如果错误,则评估并返回noNewMessagesText,否则评估并返回newMessagesText。因为在这个例子中它是不稳定的,所以我们停在非消息文本处,并警告"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.。
- @是的,它应该用粗体字imho。
- 应该是答案,它显示了在测试用例中选择的值。
- 同意,这是我最喜欢的答案,因为它专门解决了JavaScript变量分配问题。此外,如果选择使用三元作为后续变量之一来测试赋值(在运算符之后),则必须将三元括在括号中,以便赋值计算正常工作。
- 这是最好的。解释为什么不能像Java那样获取值true / false。
javascript变量不是类型化的,因此可以为f分配一个整数值,即使它是通过布尔运算符分配的。
F被指定为不等于假的最接近值。所以0、false、null、undefined都被传递:
1
| alert(null || undefined || false || '' || 0 || 4 || 'bar'); // alerts '4' |
- 别忘了,在这种情况下,''也等于假。
- 赞成指出f is assigned the NEAREST value这是一个非常重要的观点。
- "最近"并不完全正确,尽管它确实有这样的外观。布尔型||运算符,作为布尔型运算符,有两个操作数:左侧和右侧。如果||的左侧是真实的,则该操作将解析为左侧,而右侧将被忽略。如果左侧不稳,则会分解为右侧。因此,null || undefined || 4 || 0实际解析为undefined || 4 || 0解析为4 || 0解析为4。
它没有任何魔力。像a || b || c || d这样的布尔表达式的计算比较缓慢。interpeter查找a的值,它是未定义的,所以它是假的,所以它继续前进,然后它看到b是空的,它仍然给出错误的结果,所以它继续前进,然后它看到c是同一个故事。最后,它看到d并说"哈,它不是空的,所以我得到了我的结果",它将它赋给最终的变量。
这种技巧在所有动态语言中都有效,这些语言对布尔表达式进行延迟的短路评估。在静态语言中,它不会编译(类型错误)。在渴望评估布尔表达式的语言中,它将返回逻辑值(在本例中为真)。
- 在相当静态的语言中,C可以使用??operator&225;la:对象f=a?B?C?D?E;
- 赫尔兹梅斯特-谢谢!我不知道??操作员可以用C链接,并用于懒惰的评估技术。
- 如其他地方所述,无论最后一个d是否为空/未定义,都将被分配。
- 稍微更正一下:当左侧不稳定时,||运算符总是解析为整个右侧操作数。作为布尔运算符,它只看到两个输入:左侧和右侧。解析器不会将它们视为一系列术语,因此当它找到第一个真实值时,它实际上不会停止,除非该值也是另一个||的左手操作数。
这个问题已经得到了好几个答案。
总之,这种技术利用了语言编译的一个特性。也就是说,javascript"短路"布尔运算符的计算,并返回与第一个非假变量值或最后一个变量包含的任何内容相关联的值。请参阅Anurag对这些值的解释,这些值将被评估为false。
然而,由于几个原因,使用这种技术并不是很好的实践。
代码可读性:这是使用布尔运算符,如果不理解这种编译方式的行为,则预期结果将是布尔值。
稳定性:这使用了一个编译语言的特性,该特性在多个语言中不一致,因此,它可能是未来变化的目标。
有文档记录的特性:有一个现有的替代方案可以满足这个需求,并且跨更多语言保持一致。这将是三元运算符:
()值1:值2。
使用三元运算符确实需要更多的类型,但它清楚地区分了正在计算的布尔表达式和正在分配的值。此外,还可以链接它,因此可以重新创建上面执行的默认分配类型。
1 2 3 4 5 6 7 8 9 10 11 12 13
| 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马丁的《干净的代码》,这种类型的作业绝对违反了"没有副作用"的规则……虽然作者自己声明他的书只是生成好代码的众多技术之一,但我仍然惊讶于没有其他人反对这种作业。+ 1
- 感谢您的回复。我认为更多的人在编写代码时需要考虑到副作用,但是直到有人花了很多时间维护其他人的代码。他们经常不考虑。
- 你真的认为怪物比a || b || c || d || e更清楚吗?
- @阿尔伯罗斯曼,我看不到任何副作用。没有什么变异。它只是空合并的简写,在许多语言中这是一个非常常见的特性。
返回输出第一个真值。
如果全部为假,则返回最后一个假值。
例子:
1
| null || undefined || false || 0 || 'apple' // Return apple |
它将新变量(z设置为x的值,如果它是"truthy"(非零,有效的对象/数组/函数/不管它是什么)或y的话。这是在不存在x的情况下提供默认值的相对常见的方法。
例如,如果您有一个接受可选回调参数的函数,则可以提供一个不做任何事情的默认回调:
4
它被称为短路操作器。
短路计算表示,只有当第一个参数不足以确定表达式的值时,才执行或计算第二个参数。当or()函数的第一个参数的计算结果为true时,整体值必须为true。
它还可以用于设置函数参数的默认值。`
1 2 3 4 5 6
| 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` |
即设置x时,z的值为x,否则设置y时,其值为z的值。
它和
1 2 3 4
| if(x)
z = x;
else
z = y; |
这是可能的,因为javascript中的逻辑运算符不返回布尔值,而是完成操作所需的最后一个元素的值(在OR语句中,它将是第一个非假值,在AND语句中,它将是最后一个)。如果操作失败,则返回false。
- 这是错的!如果(x)z=x;else z=y;如果第一个值为假,则始终指定第二个值,而不取决于实际值。
- 但我认为如果x是假的,它会把y赋给z。当然,这也是我在FF中的工作方式,这可能也依赖于实现。
- 关于返回错误的最后一部分不是真的(没有双关语的意图)。如果第一个值是错误的,则||运算符只返回第二个值,而不管它是否正确。
- - 1。您的等效代码片段是准确的,但重要的一点是,如果该值是真实的,那么z将被设置为x的值。否则设置为EDOCX1的值(19)。这意味着,如果将x设置为(例如)0或空字符串"",则不会按照您的说法执行,因为这些值是错误的。
根据BillHiggins的博客文章:javascript逻辑或分配习语(2007年2月),这种行为在v1.2版时是正确的(至少如此)
他还建议另一种用途:"跨浏览器差异的轻型规范化"
4
它将计算x,如果x不为空、空字符串或0(逻辑错误),则将其分配给z。如果x为空、空字符串或0(逻辑错误),则将y分配给z。
1 2 3 4
| var x = '';
var y = 'bob';
var z = x || y;
alert(z); |
将输出"bob";
- 你应该澄清你所说的"空"是什么意思。空字符串强制到false,但空数组或对象强制到true。
- @丹尼尔"空、空或0"--空将应用于数组和对象。不过,这一点值得商榷。