构造x = x ||是什么 你的意思是?


250

我正在调试一些JavaScript,无法解释它的||作用?

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

有人可以给我一个提示,为什么这个人正在使用var title = title || 'ERROR'?我有时也看到它而没有var声明。


44
人们已经回答了这个问题……但是要特别注意,如果第一个值falsy不是JUST,则选择第二个值undefined。我见过的次数doWeDoIt = doWeDoIt || true足以让我哭泣。(即doWeDoIt现在永远不会false
Matt


4
对于具有C#经验的人,双管道运算符等效于null-coalesce运算符??。JavaScript的评估非空物体 true(或更好evalualtes空对象为false)
USR-本地ΕΨΗΕΛΩΝ

3
别担心-JS是唯一允许这种可怕的编码的愚蠢语言,并且教导说将每个函数嵌套到代码行中并丢弃它们是合适的,这是第二次使它们一次性可使用。:)我从事编码工作已经30年了,直到不久之前我才接触JS,我感到您只能说的痛苦是,保持“毫无意义,仅在JS中” cheetsheet方便,这是我唯一的方式过去了!:)
Collin Chaffin

1
请考虑将接受的答案更改为我的答案
米哈尔Perłakowski

Answers:


210

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

它是写作的简写:

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

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

a OR b

它计算true是否为abtrue。因此,如果a为真,则完全不需要检查b。这称为短路布尔评估,因此:

var title = title || "Error";

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


3
抱歉,我很挑剔,但是该参数不是可选的,因此已选中该参数
themightybun

4
这不是答案,我也同意最后一个评论,它不是可选的。由于Perl语句实际上使SENSE并以完全不同的方式进行评估,因此即使是Perl引用,此答案也没有正确的地方。JS评估了一个更加“转换”的布尔逻辑方法,我也发现它在读取/写入时更加混乱。下面标题为“什么是双管道运算符”的答案实际上是正确的答案。
Collin Chaffin

198

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

双管道运算符(||)是逻辑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会将隐式转换为boolean。这意味着,如果该值是falsey(例如0""nullundefined(还参见在JavaScript中所有falsey值)),它将被视为false; 否则将被视为true

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

  • 如果第一个值是falsey,则返回第二个值
  • 如果第一个值是真实的,则返回第一个值

惊讶吗 实际上,它与传统的||运算符“兼容” 。它可以写成下面的函数:

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."if if y真实的信息。否则你会得到"Neither x nor y is truthy"

实际问题

现在,当您知道||操作员的工作方式时,您可能可以自己弄清楚这x = x || y意味着什么。如果x为true,x则分配给x,因此实际上什么也没发生;否则y分配给x。它通常用于定义函数中的默认参数。但是,它通常被认为是不好的编程习惯,因为它阻止您传递错误的值(不一定是undefinednull)作为参数。考虑以下示例:

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

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

最好像这样显式检查flagAis 是否是一个更好的主意undefined

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

尽管时间更长,但它始终有效并且更易于理解。


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

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


13
+1-迄今为止最正确,最完整的答案。并且,对于那些有这个问题的人(包括JS新手在内的我们一些资深编码员)当然应该将整个答案的重点放在以下这一行:“尽管没有意义”,因为这种“ loosley类型”根本就没有意义对于那些没有它成长的人。对我们来说,布尔运算符就是这样,而且仅此而已……无论谁想到,在读/写代码时必须停下来思考一下,将非布尔值转换为布尔值是一个好主意,忘了那天吃药!:)
Collin Chaffin

2
+1,简而言之:title = title || 'Error'意味着if (title) { title = title; } else { title = 'Error'; }
Andre Elrico

我实际上不同意“尽管没有道理”这一行。我知道该行不会在C语言中进行编译,但是,例如,如果您来自Ruby甚至是Groovy,就可以理解。在Ruby中,您可以将其表示得更短,如title ||= 'Error'
艾略特·尼尔森

28

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

更通用:

var foobar = foo || default;

读取:将foobar设置为foodefault。您甚至可以将其链接很多次:

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

1
我发现它令人困惑,因为变量具有相同的名称。如果不这样做,则容易得多。
诺伯特·诺伯森

14

多解释一下...

||操作是logical- or操作。如果第一部分为true,则结果为true;如果第二部分为true,则结果为true;如果两个部分均为true,则结果为true。为了清楚起见,它在表格中:

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

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

那么,这与您的示例有什么关系?

var title   = title || 'Error';

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

由于JavaScript中逻辑表达式的实现,因此可以工作。它不会返回正确的布尔值(truefalse),而是返回在某些规则下给出的关于等价于true和的等效值false。查找您的JavaScript参考,以了解JavaScript在布尔上下文中认为正确还是错误。


8

双管道代表逻辑“或”。当未设置“参数”时,实际上不是这种情况,因为严格来说,如果您有这样的代码,则在javascript中:

function foo(par) {
}

然后打电话

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

不相等。

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

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

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

如果您像这样进行检查:

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

这样会给通话带来意外结果

setSalary(0) 

仍然按照上述流程设置10。


8

基本上,它检查||之前的值 计算结果为true,如果是,则采用该值;否则,采用||之后的值。

||之后的值 (就目前我所记得的):

  • 未定义
  • 0
  • ''(空或空字符串)

1
假|| 空|| 未定义|| 0 || ” || “你忘了空”
Dziamid

7

尽管Cletus的答案是正确的,但我认为应该在JavaScript中添加更多有关“评估为假”的信息。

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

不仅检查是否提供了title / msg,而且还检查了其中两个是否都是falsy。即以下之一:

  • 假。
  • 0(零)
  • “”(空字符串)
  • 空值。
  • 未定义。
  • NaN(特殊的数字值,表示非数字!)

所以在行

var title = title || 'Error';

如果标题是真实的(即不是虚假的,则标题=“ titleMessage”等),则布尔OR(||)运算符找到一个'true'值,这意味着它的值为true,因此会短路并返回真实值(标题)。

如果标题是虚假的(即上面的列表之一),则布尔OR(||)运算符已找到“假”值,现在需要评估运算符的另一部分“错误”,其评估结果为true ,因此返回。

(在经过快速的Firebug控制台快速试验之后)如果该运算符的两边都评估为false,则它还会返回第二个“ falsy”运算符。

return ("" || undefined)

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

var foo = undefined
foo = foo || ""

foo将设置为“”


5

双管操作员

这个例子有用吗?

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

也可以是

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

4

为了在我之前说的所有内容中添加一些解释,我应该给您一些示例以了解逻辑概念。

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

3

|| 是布尔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"

2

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

分配默认值。

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


那是该构造的确切含义,也是它的唯一含义。在很大程度上,它是编写函数的子例程,可以作为原型,独立函数以及要应用于其他元素的借用方法来获取。其主要且唯一的职责是修改目标的参考。示例:function getKeys(x) { x = x || this ; .... }可以将其未经修改地用作独立函数,用作原型中的属性方法以及用作可以将另一个元素作为其自变量的元素方法,例如[[element] .getKeys(anotherElement);”
Bekim Bacaj

-5

而且我还必须添加一件事:这种速记方式令人讨厌。它滥用了意外的解释器优化(如果第一个操作是真实的,则不会打扰第二个操作)来控制分配。这种使用与操作员的目的无关。我认为不应该使用它。

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

var title = title?title:'Error';

这是出于正确目的而使用单行条件运算。它仍然会像实在玩难看的游戏,但这就是您的Javascript。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.