我正在调试一些 JavaScript,但无法解释这是做什么||
的:
function (title, msg) {
var title = title || 'Error';
var msg = msg || 'Error on Request';
}
这家伙为什么要使用var title = title || 'ERROR'
?我有时也会在没有var
声明的情况下看到它。
我正在调试一些 JavaScript,但无法解释这是做什么||
的:
function (title, msg) {
var title = title || 'Error';
var msg = msg || 'Error on Request';
}
这家伙为什么要使用var title = title || 'ERROR'
?我有时也会在没有var
声明的情况下看到它。
这意味着title
参数是可选的。因此,如果您调用不带参数的方法,它将使用默认值"Error"
.
它是写作的简写:
if (!title) {
title = "Error";
}
这种布尔表达式的速记技巧在 Perl 中也很常见。用表达式:
a OR b
它评估为true
ifa
或b
is true
。所以如果a
是真的,你根本不需要检查b
。这称为短路布尔评估,因此:
var title = title || "Error";
基本上检查是否title
评估为false
. 如果是,则“返回” "Error"
,否则返回title
。
||
)?双管道运算符 ( ||
) 是逻辑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 有点不同,因为它是一种松散类型的语言。在这种情况下,这意味着您可以将||
运算符与非布尔值一起使用。尽管没有意义,但您可以将此运算符与例如函数和对象一起使用:
(function(){}) || {}
如果值不是布尔值,JavaScript 会隐式转换为布尔值。这意味着如果该值是假的(例如0
, ""
, null
, undefined
(另见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
。在这种情况下,你会得到"Either x or y is truthy."
如果y
是真的;否则你会得到"Neither x nor y is truthy"
.
现在,当您知道||
operator 的工作原理后,您可能会自己弄清楚它的x = x || y
含义。如果x
是真实的,x
则分配给x
,所以实际上什么也没发生;否则y
分配给x
。它通常用于定义函数中的默认参数。但是,它通常被认为是一种不好的编程习惯,因为它会阻止您将虚假值(不一定是undefined
or null
)作为参数传递。考虑以下示例:
function badFunction(/* boolean */flagA) {
flagA = flagA || true;
console.log("flagA is set to " + (flagA ? "true" : "false"));
}
乍一看似乎是有效的。但是,如果您false
作为flagA
参数传递会发生什么(因为它是布尔值,即可以是true
or false
)?它会变成true
. 在此示例中,无法设置flagA
为false
。
明确检查 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 上的逻辑运算符。
如果未设置标题,则使用“错误”作为默认值。
更通用:
var foobar = foo || default;
读取:将 foobar 设置为foo
or default
。你甚至可以多次链接它:
var foobar = foo || bar || something || 42;
再解释一下……
||
运算符是逻辑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 中,如果您的变量为空值,则逻辑运算符将其视为 false。因此,如果在给定标题的情况下调用此函数,则它是一个非假值,因此分配给局部变量。但是,如果没有给它一个值,它是一个空值,因此是假的。然后逻辑or
运算符计算第二个表达式并返回“错误”。所以现在局部变量被赋予了值'Error'。
这是因为在 JavaScript 中实现了逻辑表达式。它不返回正确的布尔值(true
或false
),而是返回根据某些规则给出的值,即什么被认为等同于true
和什么被认为等同于false
. 查找您的 JavaScript 参考以了解 JavaScript 在布尔上下文中认为是真还是假。
基本上,它检查||
评估之前的值是否为真。如果是,就取这个值,如果不是,就取后面的值||
。
它将在||
(据我记得)之后取值的值:
双管道代表逻辑“或”。当“未设置参数”时,情况并非如此,因为如果您有这样的代码,则严格在 JavaScript 中:
function foo(par) {
}
然后调用
foo()
foo("")
foo(null)
foo(undefined)
foo(0)
不等价。
双管道 (||) 会将第一个参数转换为布尔值,如果结果布尔值为真 - 进行分配,否则它将分配正确的部分。
如果您检查未设置的参数,这很重要。
假设我们有一个函数 setSalary,它有一个可选参数。如果用户不提供参数,则应使用默认值 10。
如果您像这样进行检查:
function setSalary(dollars) {
salary = dollars || 10
}
这会给如下调用带来意想不到的结果:
setSalary(0)
它仍将按照上述流程设置 10。
虽然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 将被设置为 ""
|| 是布尔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"
这个例子可能有用:
var section = document.getElementById('special');
if(!section){
section = document.getElementById('main');
}
它也可以是:
var section = document.getElementById('special') || document.getElementById('main');
为了对我之前所说的所有内容添加一些解释,我应该给你一些例子来理解逻辑概念。
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
引用:“构造 x = x || y 是什么意思?”
分配默认值。
这意味着为 x 提供一个默认值 y,以防 x 仍在等待其值但尚未收到它,或者为了回退到默认值而故意省略它。
我还要补充一点:这种速记是可憎的。它滥用了意外的解释器优化(如果第一个操作是真实的,则不会打扰第二个操作)来控制分配。这种使用与运营商的目的无关。我不相信它应该被使用。
我更喜欢使用三元运算符进行初始化,例如,
var title = title?title:'Error';
这使用单行条件操作来实现其正确目的。它仍然会以真实的方式玩难看的游戏,但那是 JavaScript 给你的。