什么构造x = x || 你的意思是?
我正在debugging一些JavaScript,并不能解释这是什么||
呢?
function (title, msg) { var title = title || 'Error'; var msg = msg || 'Error on Request'; }
有人可以给我一个提示,为什么这个人使用var title = title || 'ERROR'
var title = title || 'ERROR'
? 我有时也会看到它没有var
声明。
这意味着title
参数是可选的。 所以如果你调用没有参数的方法,它将使用默认值"Error"
。
这是写作的简写:
if (!title) { title = "Error"; }
这种布尔expression式的简写技巧在Perl中也是很常见的。 用expression式:
a OR b
如果a
或b
为true
则评估为true
。 所以如果a
是真的,你根本不需要检查b
。 这被称为短路布尔评估,所以:
var title = title || "Error";
基本上检查title
评估是否为false
。 如果是,则“返回” "Error"
,否则返回title
。
什么是双pipe操作符( ||
)?
双pipe道运算符( ||
)是逻辑OR
运算符 。 在大多数语言中,它的工作原理如下:
- 如果第一个值为
false
,则检查第二个值。 如果是,则返回true
,如果为false
,则返回false
。 - 如果第一个值为
true
,则无论第二个值是什么,总是返回true
。
所以它基本上是(注意,它实际上是一个伪代码,因为你必须给这个函数一个名字或者包装它(
和)
以使其工作):
function(x, y) { if (x) { return true; } else if (y) { return true; } else { return false; } }
如果你还不明白,看看这张表:
| true false ------+--------------- true | true true false | true false
换句话说,只有两个值都是假的,它才是错误的。
在JavaScript中它有什么不同?
JavaScript有点不同,因为它是一种松散types的语言 。 在这种情况下,这意味着你可以使用||
运算符的值不是布尔值。 虽然没有任何意义,但是可以使用这个操作符,例如一个函数和一个对象:
(function(){}) || {}
那里发生了什么?
如果值不是布尔值,那么JavaScript会将隐式对话转换为布尔值 。 这意味着如果值是falsey(例如0
, ""
, null
, undefined
(也可以参考JavaScript中的所有falsey值 )),则它将被视为false
; 否则视为true
。
所以上面的例子应该是true
,因为空function是真的。 那么,它不。 它返回空函数。 这是因为JavaScript的||
操作员不像我一开始写的那样工作。 它的工作原理如下:
- 如果第一个值是falsey ,则返回第二个值 。
- 如果第一个值是真的 ,它返回第一个值 。
惊讶吗? 实际上,它与传统的“兼容” 运营商。 可以写成如下函数:
function(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
是假的,那么x
or eitherXorY
就是y
。 在这种情况下,你会得到"Either x or y is truthy."
如果y
真的是真的 否则你会得到"Neither x nor y is truthy"
。
实际的问题
现在,当你知道如何||
运营商的工作,你可以自己做出什么x = x || y
x = x || y
意思是 如果x
是真的, x
被分配给x
,所以实际上什么也没有发生。 否则y
被分配给x
。 它通常用于定义默认参数来运行,因为默认的函数参数是在ES6中引入的,旧版浏览器不支持。 然而,它通常被认为是一个糟糕的编程习惯 ,因为它会阻止你传递一个错误的值(不一定是undefined
或null
)作为参数。 考虑下面的例子:
function badFunction(/* boolean */flagA) { flagA = flagA || true; console.log("flagA is set to " + (flagA ? "true" : "false")); }
一见钟情看起来有效。 但是,如果你传递false
作为flagA
参数会发生什么(因为它是布尔值,即可以是true
或false
)? 这将成为true
。 在这个例子中,没有办法将flagA
设置为false
。
比较好的例子是显式检查flagA
是否undefined
,如下所示:
function goodFunction(/* boolean */flagA) { flagA = typeof flagA !== "undefined" ? flagA : true; console.log("flagA is set to " + (flagA ? "true" : "false")); }
虽然时间更长,但它总能正常工作,而且更容易理解(哪个OP通过问这个问题已经certificate了)。
也可以看看
- 逻辑运营商 (MDN)
- 提供默认值
如果没有设置标题,请使用“错误”作为默认值。
更一般的:
var foobar = foo || default;
读取:将foobar设置为foo
或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中,如果你的variables是一个空值,它被逻辑运算符认为是错误的。 所以如果这个函数是用给定的标题调用的,那么它是一个非错误的值,因此被分配给局部variables。 但是,如果它没有被赋予一个值,那么它是一个空值,因此是错误的。 逻辑or
运算符然后评估第二个expression式,并返回“错误”。 所以现在局部variables的值是'Error'。
这是因为JavaScript中的逻辑expression式的实现。 它不返回一个合适的布尔值( true
或false
),而是返回它在某些规则下给出的值,它被认为等同于true
,被认为等价于false
。 查看JavaScript引用,了解JavaScript在布尔上下文中认为是真或假的内容。
双pipe代表逻辑“或”。 当“参数未设置”时,这并不是真正的情况,因为严格地说在JavaScript中,如果你有像这样的代码:
function foo(par) { }
然后打电话
foo() foo("") foo(null) foo(undefined) foo(0)
并不等同。
双pipe道(||)会将第一个参数强制转换为布尔值,如果结果布尔值为true,则执行分配,否则将分配正确的部分。
这一点很重要,如果你检查未设置的参数。
比方说,我们有一个函数setSalary有一个可选参数。 如果用户不提供参数,则应使用默认值10。
如果你这样做的检查:
function setSalary(dollars) { salary = dollars || 10 }
这会给通话带来意想不到的结果
setSalary(0)
它仍然会按照上面描述的stream程设置10。
基本上它会检查||之前的值 评估为真,如果是的话,则取该值,否则取||之后的值。
它将采用||之后的值的值 (就目前我所记得的):
- 未定义
- 假
- 0
- ''(空string或空string)
双pipe操作员
这个例子有用吗?
var section = document.getElementById('special'); if(!section){ section = document.getElementById('main'); }
也可以
var section = document.getElementById('special') || document.getElementById('main');
虽然Cletus的回答是正确的,但我觉得应该在JavaScript中对“评估为false”join更多的细节。
var title = title || 'Error'; var msg = msg || 'Error on Request';
是不是只是检查是否提供标题/味精,而且如果其中任何一个是虚假的 。 即以下之一:
- 假。
- 0(零)
- “”(空string)
- 空值。
- 未定义。
- NaN(一个特殊的数值,意思是非数字!)
所以在行中
var title = title || 'Error';
如果标题是truthy(即不是falsy,所以title =“titleMessage”等),那么布尔OR(||)运算符find了一个“true”值,这意味着它的计算结果为true,所以它短路并返回真正的价值(标题)。
如果标题是假的(即上面的列表之一),那么布尔OR(||)运算符已经find一个'假'的值,现在需要评估运算符的其他部分'Error',其值为真,并因此返回。
如果运营商的双方评估为错误,那么似乎(在一些快速的萤火虫控制台实验之后),它返回第二个“虚假”运营商。
即
return ("" || undefined)
返回未定义,这可能允许您在尝试将标题/消息默认为“”时使用此问题中提到的行为。 即在运行之后
var foo = undefined foo = foo || ""
foo将被设置为“”
为了给我之前的所有人增加一些解释,我应该给你一些例子来理解逻辑概念。
var name = false || "Mohsen"; # name equals to Mohsen var family = true || "Alizadeh" # family equals to true
这意味着如果左侧被评估为真正的语句,它将被完成并且左侧将被返回并被分配给该variables。 在其他情况下,右侧将被退回并分配。
而运营商有如下相反的结构。
var name = false && "Mohsen" # name equals to false var family = true && "Alizadeh" # family equals to Alizadeh
Quote:“什么构造x = x || y是什么意思?
指定一个默认值。
这意味着如果x仍然在等待它的值,但还没有收到它,或者为了回到默认值而被故意省略,那么给y提供一个默认的值给x 。
而且我还要再补充一件事情:这种简写是可憎的。 它误用了一个意外的解释器优化(不打扰第二个操作,如果第一个是真的)来控制一个任务。 这种使用与操作者的目的没有任何关系。 我不相信它应该被使用。
我更喜欢三元运算符进行初始化,例如,
var title = title?title:'Error';
这使用一个单行条件操作来达到正确的目的。 它仍然玩真实的难看的游戏,但是,这是你的Javascript。