我正在调试一些JavaScript,无法解释这个||做什么:

function (title, msg) {
  var title = title || 'Error';
  var msg   = msg || 'Error on Request';
}

为什么这个家伙使用var title = title || 'ERROR'?我有时也看到它没有var声明。


如果没有设置title,则使用'ERROR'作为默认值。

更通用的:

var foobar = foo || default;

读取:将foobar设置为foo或默认值。 你甚至可以把这个串起来很多次:

var foobar = foo || bar || something || 42;

这意味着title参数是可选的。因此,如果你不带参数调用该方法,它将使用默认值“Error”。

它是写作的简写:

if (!title) {
  title = "Error";
}

这种使用布尔表达式的简写技巧在Perl中也很常见。用这样的表达式:

a OR b

如果a或b为真,它的值为真。所以如果a为真,你根本不需要检查b。这被称为短路布尔计算,因此:

var title = title || "Error";

基本上检查title的结果是否为false。如果是,则返回"Error",否则返回title。

双管操作员

这个例子可能有用:

var section = document.getElementById('special');
if(!section){
     section = document.getElementById('main');
}

它也可以是:

var section = document.getElementById('special') || document.getElementById('main');

基本上,它检查||之前的值是否为true。如果是,则取该值,如果不是,则取||之后的值。

它将取||之后的值(据我所知):

未定义的 假 0 (Null或空字符串)

双管代表逻辑上的“或”。这不是真正的情况下,“参数未设置”,因为严格在JavaScript中,如果你有这样的代码:

function foo(par) {
}

然后调用

foo()
foo("")
foo(null)
foo(undefined)
foo(0)

不相等。

双管道(||)将把第一个参数强制转换为布尔值,如果结果布尔值为真-执行赋值,否则它将赋值正确的部分。

如果你检查未设置参数,这很重要。

我们有一个函数setSalary,它有一个可选参数。如果用户没有提供参数,则应该使用默认值10。

如果你这样检查:

function setSalary(dollars) {
    salary = dollars || 10
}

这将为调用提供一个意想不到的结果,例如:

setSalary(0)

它仍然会按照上面描述的流程设置10。

再解释一下……

||操作符是逻辑或操作符。如果第一部分为真,则结果为真;如果第二部分为真,则结果为真;如果两部分都为真,则结果为真。为了清晰起见,这里是一个表格:

 X | Y | X || Y 
---+---+--------
 F | F |   F    
---+---+--------
 F | T |   T    
---+---+--------
 T | F |   T    
---+---+--------
 T | T |   T    
---+---+--------

Now notice something here? If X is true, the result is always true. So if we know that X is true we don't have to check Y at all. Many languages thus implement "short circuit" evaluators for logical-or (and logical-and coming from the other direction). They check the first element and if that's true they don't bother checking the second at all. The result (in logical terms) is the same, but in terms of execution there's potentially a huge difference if the second element is expensive to calculate.

那么这和你的例子有什么关系呢?

var title   = title || 'Error';

Let's look at that. The title element is passed in to your function. In JavaScript if you don't pass in a parameter, it defaults to a null value. Also in JavaScript if your variable is a null value it is considered to be false by the logical operators. So if this function is called with a title given, it is a non-false value and thus assigned to the local variable. If, however, it is not given a value, it is a null value and thus false. The logical-or operator then evaluates the second expression and returns 'Error' instead. So now the local variable is given the value 'Error'.

这是因为在JavaScript中实现了逻辑表达式。它不会返回一个合适的布尔值(真或假),而是返回它在一些规则下给出的值,这些规则被认为是等价于真,什么被认为是等价于假。查看JavaScript参考,了解JavaScript在布尔上下文中认为什么是真或假。

什么是双管运算符(||)?

双管道操作符(||)是逻辑或操作符。在大多数语言中,它是这样工作的:

如果第一个值为false,则检查第二个值。如果这个值为真,它就返回真,如果第二个值为假,它就返回假。 如果第一个值为真,它总是返回真,不管第二个值是什么。

它的工作原理是这样的:

function or(x, y) {
  if (x) {
    return true;
  } else if (y) {
    return true;
  } else {
    return false;
  }
}

如果你还是不明白,看看这张表:

      | true   false  
------+---------------
true  | true   true   
false | true   false  

换句话说,只有当两个值都为假时,它才为假。

在JavaScript中有什么不同?

JavaScript有点不同,因为它是一种松散类型的语言。在这种情况下,这意味着您可以使用||操作符,其值不是布尔值。虽然它没有任何意义,但你可以将这个操作符用于例如一个函数和一个对象:

(function(){}) || {}

那里发生了什么?

如果值不是布尔值,JavaScript将隐式转换为布尔值。这意味着如果值是假的(例如0,"",null, undefined(参见JavaScript中的所有假值)),它将被视为假的;否则它就被当作真的。

所以上面的例子应该给出true,因为空函数是true。其实并不是这样。它返回空函数。这是因为JavaScript的||操作符不能像我开头写的那样工作。它的工作原理如下:

如果第一个值为假值,则返回第二个值。 如果第一个值为真值,则返回第一个值。

惊讶吗?实际上,它与传统的||操作符“兼容”。它可以写成如下函数:

function or(x, y) {
  if (x) {
    return x;
  } else {
    return y;
  }
}

如果你传递一个真值作为x,它返回x,也就是说,一个真值。所以如果你在if从句中使用它:

(function(x, y) {
  var eitherXorY = x || y;
  if (eitherXorY) {
    console.log("Either x or y is truthy.");
  } else {
    console.log("Neither x nor y is truthy");
  }
}(true/*, undefined*/));

你会得到" x或y是对的"

如果x是假的,要么xory是y,在这种情况下,你会得到"要么x要么y是真的"如果y是真的;否则你就会得到" x和y都不是真理"

真正的问题

现在,当你知道||算子是如何工作的,你可能自己就能知道x = x || y是什么意思。如果x为真,x被赋值给x,所以实际上什么都不会发生;否则y赋值给x。通常用于定义函数中的默认形参。然而,它通常被认为是一种糟糕的编程实践,因为它阻止您将错误的值(不一定是未定义或null)作为参数传递。考虑下面的例子:

function badFunction(/* boolean */flagA) {
  flagA = flagA || true;
  console.log("flagA is set to " + (flagA ? "true" : "false"));
}

乍一看,它是有效的。然而,如果你传递false作为flagA参数会发生什么(因为它是布尔值,即可以为真或假)?这将成为现实。在这个例子中,没有办法将flagA设置为false。

更好的方法是显式检查flagA是否未定义,如下所示:

function goodFunction(/* boolean */flagA) {
  flagA = typeof flagA !== "undefined" ? flagA : true;
  console.log("flagA is set to " + (flagA ? "true" : "false"));
}

虽然它更长,但它总是有效的,而且更容易理解。


您还可以使用ES6语法作为默认函数参数,但请注意,它不适用于老式浏览器(如IE)。如果您希望支持这些浏览器,您应该使用Babel编译您的代码。

请参见MDN上的逻辑运算符。

虽然Cletus的回答是正确的,但我觉得应该在JavaScript中添加更多关于“评估为假”的细节。

var title = title || 'Error';
var msg   = msg || 'Error on Request';

不仅仅是检查是否提供了title/msg,而且还检查它们中的任何一个是假的。即下列其中一项:

假的。 0(零) ""(空字符串) null。 未定义的。 NaN(一个特殊的数字值,意思不是一个数字!)

在这一行中

var title = title || 'Error';

如果title为真(即,不是假的,所以title = "titleMessage"等),那么布尔OR(||)运算符已经找到了一个“真”值,这意味着它的计算结果为真,因此它短路并返回真值(title)。

如果title是假的(即上面的列表之一),那么布尔OR(||)运算符已经找到了一个“假”值,现在需要计算运算符的另一部分“Error”,该运算符的计算结果为真,因此返回。

如果运算符两边的值都为false,它也会返回第二个“falsy”运算符(经过一些快速的firebug控制台实验)。

i.e.

return ("" || undefined)

返回undefined,这可能是为了允许您在尝试将title/message默认为""时使用此问题中询问的行为。也就是跑步之后

var foo = undefined
foo = foo || ""

Foo将被设置为""

为了对我前面所说的一切进行解释,我应该给你们一些例子来理解逻辑概念。

var name = false || "Mohsen"; # name equals to Mohsen
var family = true || "Alizadeh" # family equals to true

这意味着如果左边的语句被赋值为true,那么它将被结束,左边的语句将被返回并赋值给变量。在其他情况下,右侧将返回并分配。

和运算符有相反的结构,如下所示。

var name = false && "Mohsen" # name equals to false
var family = true && "Alizadeh" # family equals to Alizadeh

我还要补充一点:这种简写令人厌恶。它误用了一个意外的解释器优化(如果第一个操作为真,就不麻烦第二个操作)来控制赋值。这种用法与操作符的目的无关。我不认为它应该被使用。

我更喜欢用三元运算符来初始化,例如,

var title = title?title:'Error';

这使用一行条件操作来达到正确的目的。它仍然与真实玩难看的游戏,但这是JavaScript为你。

" x = x || y是什么意思"

分配默认值。

这意味着提供一个y到x的默认值, 如果x还在等待它的值,但还没有收到它,或者为了回到默认值而故意忽略它。

||为布尔或运算符。在JavaScript中,undefined, null, 0, false被认为是假值。

它只是意味着

true || true = true
false || true = true
true || false = true
false || false = false

undefined || "value" = "value"
"value" || undefined = "value"
null || "value" = "value"
"value" || null = "value"
0 || "value" = "value"
"value" || 0 = "value"
false || "value" = "value"
"value" || false = "value"