给出这段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本身的值。


当前回答

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

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

假 零 ""(空字符串) 0 南 未定义的

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

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);

在警报中,我们检查消息是否为假消息,如果是,则计算并返回noNewMessagesText,否则计算并返回newMessagesText。因为在这个例子中它是假的,所以我们在noNewMessagesText停止并警告“对不起,您没有新消息。”

其他回答

根据Bill Higgins的博客文章;Javascript逻辑或赋值习惯(2007年2月),这个行为在v1.2(至少)是正确的。

他还提出了另一种用法(引用): “跨浏览器差异的轻量级规范化”

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

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

这和

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

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

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

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

假 零 ""(空字符串) 0 南 未定义的

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

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);

在警报中,我们检查消息是否为假消息,如果是,则计算并返回noNewMessagesText,否则计算并返回newMessagesText。因为在这个例子中它是假的,所以我们在noNewMessagesText停止并警告“对不起,您没有新消息。”

它没有任何魔力。布尔表达式如a || b || c || d被延迟计算。Interpeter寻找a的值,它是未定义的,所以它是假的,所以它继续前进,然后它看到b是空的,它仍然给出假的结果,所以它继续前进,然后它看到c -同样的故事。最后它看到d,然后说,嗯,它不是空的,所以我得到了我的结果,然后它把它赋值给final变量。

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

它将计算X,如果X不为空字符串或0(逻辑错误),那么它将把它赋值给z。如果X为空字符串或0(逻辑错误),那么它将把y赋值给z。

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

将输出'bob';