288

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

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

这家伙为什么要使用var title = title || 'ERROR'?我有时也会在没有var声明的情况下看到它。

4

12 回答 12

237

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

它是写作的简写:

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

这种布尔表达式的速记技巧在 Perl 中也很常见。用表达式:

a OR b

它评估为trueifabis true。所以如果a是真的,你根本不需要检查b。这称为短路布尔评估,因此:

var title = title || "Error";

基本上检查是否title评估为false. 如果是,则“返回” "Error",否则返回title

于 2010-05-10T11:00:26.717 回答
234

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

双管道运算符 ( ||) 是逻辑OR运算符。在大多数语言中,它的工作方式如下:

  • 如果第一个值为false,则检查第二个值。如果是true,则返回true,如果第二个值为false,则返回false
  • 如果第一个值是true,它总是返回true,不管第二个值是什么。

所以基本上它就像这个函数一样工作:

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 中的所有假值)),它将被视为false; 否则它被视为true.

所以上面的例子应该给出true,因为空函数是真实的。好吧,它没有。它返回空函数。那是因为 JavaScript 的||操作符不像我一开始写的那样工作。它的工作方式如下:

  • 如果第一个值为false,则返回第二个值
  • 如果第一个值是值,则返回第一个值

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

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

你明白了"Either x or y is truthy."

如果x是假的,那eitherXorY就是y。在这种情况下,你会得到"Either x or y is truthy."如果y是真的;否则你会得到"Neither x nor y is truthy".

实际问题

现在,当您知道||operator 的工作原理后,您可能会自己弄清楚它的x = x || y含义。如果x是真实的,x则分配给x,所以实际上什么也没发生;否则y分配给x。它通常用于定义函数中的默认参数。但是,它通常被认为是一种不好的编程习惯,因为它会阻止您将虚假值(不一定是undefinedor null)作为参数传递。考虑以下示例:

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

乍一看似乎是有效的。但是,如果您false作为flagA参数传递会发生什么(因为它是布尔值,即可以是trueor false)?它会变成true. 在此示例中,无法设置flagAfalse

明确检查 is 是否flagA是一个更好的主意undefined,如下所示:

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

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


您还可以将 ES6 语法用于默认函数参数,但请注意它在旧浏览器(如 IE)中不起作用。如果你想支持这些浏览器,你应该使用Babel转译你的代码。

另请参阅MDN 上的逻辑运算符

于 2016-01-10T16:18:39.613 回答
29

如果未设置标题,则使用“错误”作为默认值。

更通用:

var foobar = foo || default;

读取:将 foobar 设置为fooor default。你甚至可以多次链接它:

var foobar = foo || bar || something || 42;
于 2010-05-10T10:59:57.903 回答
14

再解释一下……

||运算符是逻辑or运算符。如果第一部分为真,则结果为真,如果第二部分为真,则结果为真,如果两个部分都为真,则结果为真。为了清楚起见,这里是一个表格:

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

现在注意到这里的东西了吗?如果X为真,则结果始终为真。因此,如果我们知道这X是真的,我们根本不需要检查Yor因此,许多语言为逻辑-(和and来自另一个方向的逻辑-)实现“短路”评估器。他们检查第一个元素,如果这是真的,他们根本不会检查第二个元素。结果(在逻辑上)是相同的,但在执行方面,如果第二个元素的计算成本很高,则可能存在巨大差异。

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

var title   = title || 'Error';

让我们看看。该title元素被传递给您的函数。在 JavaScript 中,如果您不传入参数,则默认为空值。同样在 JavaScript 中,如果您的变量为空值,则逻辑运算符将其视为 false。因此,如果在给定标题的情况下调用此函数,则它是一个非假值,因此分配给局部变量。但是,如果没有给它一个值,它是一个空值,因此是假的。然后逻辑or运算符计算第二个表达式并返回“错误”。所以现在局部变量被赋予了值'Error'。

这是因为在 JavaScript 中实现了逻辑表达式。它不返回正确的布尔值(truefalse),而是返回根据某些规则给出的值,即什么被认为等同于true和什么被认为等同于false. 查找您的 JavaScript 参考以了解 JavaScript 在布尔上下文中认为是真还是假。

于 2010-05-10T11:14:53.490 回答
10

基本上,它检查||评估之前的值是否为真。如果是,就取这个值,如果不是,就取后面的值||

它将在||(据我记得)之后取值的值:

  • 不明确的
  • 错误的
  • 0
  • ''(空或空字符串)
于 2010-05-10T11:02:12.443 回答
8

双管道代表逻辑“或”。当“未设置参数”时,情况并非如此,因为如果您有这样的代码,则严格在 JavaScript 中:

function foo(par) {
}

然后调用

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

不等价。

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

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

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

如果您像这样进行检查:

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

这会给如下调用带来意想不到的结果:

setSalary(0)

它仍将按照上述流程设置 10。

于 2010-05-10T11:11:38.127 回答
8

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

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

不仅检查是否提供了 title/msg ,还检查其中任何一个是否为falsy。即以下之一:

  • 错误的。
  • 0(零)
  • ""(空字符串)
  • 空值。
  • 不明确的。
  • NaN(一个特殊的数字值,意思是非数字!)

所以在行

var title = title || 'Error';

如果 title 为真(即不假,因此 title = "titleMessage" 等),则布尔 OR (||) 运算符找到一个“真”值,这意味着它的计算结果为真,因此它短路并返回真正的价值(标题)。

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

如果运算符的双方都评估为假,它似乎(在一些快速的萤火控制台实验之后)也会返回第二个“假”运算符。

IE

return ("" || undefined)

返回未定义,这可能是为了让您在尝试将标题/消息默认为“”时使用此问题中询问的行为。即运行后

var foo = undefined
foo = foo || ""

foo 将被设置为 ""

于 2016-01-14T10:11:47.817 回答
6

|| 是布尔OR运算符。与 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"
于 2019-12-19T08:55:39.940 回答
5

双管操作员

这个例子可能有用:

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

它也可以是:

var section = document.getElementById('special') || document.getElementById('main');
于 2010-05-10T11:01:22.610 回答
4

为了对我之前所说的所有内容添加一些解释,我应该给你一些例子来理解逻辑概念。

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

这意味着如果左侧评估为真语句,它将完成并且左侧将被返回并分配给变量。在其他情况下,将返回并分配右侧。

运算符具有如下相反的结构

var name = false && "Mohsen" # name equals to false
var family = true && "Alizadeh" # family equals to Alizadeh
于 2016-01-14T21:34:43.123 回答
2

引用:“构造 x = x || y 是什么意思?”

分配默认值。

这意味着为 x 提供一个默认值 y,以防 x 仍在等待其值但尚未收到它,或者为了回退到默认值而故意省略它。

于 2016-05-09T13:34:18.930 回答
-5

我还要补充一点:这种速记是可憎的。它滥用了意外的解释器优化(如果第一个操作是真实的,则不会打扰第二个操作)来控制分配。这种使用与运营商的目的无关。我不相信它应该被使用。

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

var title = title?title:'Error';

这使用单行条件操作来实现其正确目的。它仍然会以真实的方式玩难看的游戏,但那是 JavaScript 给你的。

于 2016-04-29T19:43:33.093 回答