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

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

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

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

175574 次浏览

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

更通用的:

var foobar = foo || default;

读取:设置foobar为foodefault。 你甚至可以把这个链接很多次:

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

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

它是写作的简写:

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

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

a OR b

如果abtrue,则它的计算结果为true。因此,如果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或空字符串)

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

function foo(par) {
}

然后调用

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

不相等。

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

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

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

如果你这样检查:

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

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

setSalary(0)

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

再解释一下……

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

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

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

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

var title   = title || 'Error';

我们来看看。title元素被传递给你的函数。在JavaScript中,如果不传递参数,它默认为空值。同样在JavaScript中,如果你的变量是空值,逻辑运算符会认为它是假的。因此,如果这个函数被调用时带有一个给定的标题,它是一个非假值,因此被赋值给局部变量。但是,如果没有给定值,则为空值,因此为假值。逻辑操作符-or然后计算第二个表达式并返回'Error'。现在局部变量的值是'Error'。

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

什么是双管道操作符(||)?

双管道操作符(||)是逻辑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""nullundefined(另见JavaScript中的所有错误值)),它将被视为false;否则将被视为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*/));

你得到"Either x or y is truthy."

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

真正的问题

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

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

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

更好的方法是显式检查flagA是否为undefined,如下所示:

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

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


你也可以使用ES6默认函数参数的语法,但请注意它在较老的浏览器(如IE)中不起作用。如果你想支持这些浏览器,你应该用巴别塔编译你的代码。

另见MDN上的逻辑运算符

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

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

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

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

在这一行中

var title = title || 'Error';

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

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

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

即。

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被认为是falsy值。

它只是意味着

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"