我看到一些代码似乎使用了我不认识的运算符,以两个感叹号的形式,像这样:!!。有人能告诉我这个接线员做什么吗?
我看到这件事的背景是,
this.vertical = vertical !== undefined ? !!vertical : this.vertical;
我看到一些代码似乎使用了我不认识的运算符,以两个感叹号的形式,像这样:!!。有人能告诉我这个接线员做什么吗?
我看到这件事的背景是,
this.vertical = vertical !== undefined ? !!vertical : this.vertical;
当前回答
在看到所有这些伟大的答案后,我想补充一个使用!!的理由!!。目前,我正在使用Angular 2-4(TypeScript),当我的用户未通过身份验证时,我希望将布尔值返回为false。如果他未通过身份验证,则令牌字符串将为null或“”。我可以通过使用下一段代码来实现这一点:
public isAuthenticated(): boolean {
return !!this.getToken();
}
其他回答
沏茶:
!! 不是运算符。这是双重用途!--这是逻辑“not”运算符。
理论上:
! 确定值不是什么的“真相”:
事实是假的不是真的(这就是为什么!假的结果真实)事实是真的不是假的(这就是为什么!真的结果假)
!! 确定值不是什么的“真相”:
事实是真的不是假的(这就是为什么!!真的结果是真的)事实是,假的不是假的(这就是为什么!!假的结果是假的)
我们希望在比较中确定的是参考值的“真相”,而不是参考本身的值。在一个用例中,我们可能想知道值的真实性,即使我们希望值为false(或false),或者如果我们希望值不是布尔类型。
在实践中:
考虑一个简洁的函数,它通过动态类型(也称为“鸭子类型”)来检测特性功能(在本例中,还包括平台兼容性)。如果用户的浏览器支持HTML5<audio>元素,我们希望编写一个返回true的函数,但如果<audio<未定义,我们不希望该函数抛出错误;我们不想使用try。。。捕捉以处理任何可能的错误(因为它们很严重);此外,我们也不希望在函数中使用无法始终揭示功能真相的检查(例如,document.createElement('audio')仍将创建一个名为<audio>的元素,即使不支持HTML5<audio')。
以下是三种方法:
// this won't tell us anything about HTML5 `<audio>` as a feature
var foo = function(tag, atr) { return document.createElement(tag)[atr]; }
// this won't return true if the feature is detected (although it works just fine)
var bar = function(tag, atr) { return !document.createElement(tag)[atr]; }
// this is the concise, feature-detecting solution we want
var baz = function(tag, atr) { return !!document.createElement(tag)[atr]; }
foo('audio', 'preload'); // returns "auto"
bar('audio', 'preload'); // returns false
baz('audio', 'preload'); // returns true
每个函数都接受一个<tag>参数和一个要查找的属性,但它们都会根据比较结果返回不同的值。
但等等,还有更多!
你们中的一些人可能注意到,在这个特定的示例中,可以使用稍微更高性能的方法来检查对象是否具有属性。有两种方法可以做到这一点:
// the native `hasOwnProperty` method
var qux = function(tag, atr) { return document.createElement(tag).hasOwnProperty(atr); }
// the `in` operator
var quux = function(tag, atr) { return atr in document.createElement(tag); }
qux('audio', 'preload'); // returns true
quux('audio', 'preload'); // returns true
我们离题了。。。
无论这些情况多么罕见,可能存在一些情况,其中最简洁、最高效,因此最优选的从非布尔值(可能是未定义的值)获得真值的方法确实是使用!!。希望这可笑地澄清了这一点。
这是检查未定义、“未定义”、null、“null”、“”
if (!!var1 && !!var2 && !!var3 && !!var4 ){
//... some code here
}
if和while语句以及?运算符使用真值来确定要运行的代码分支。例如,零和NaN数字以及空字符串为假,但其他数字和字符串为真。对象为true,但未定义的值和null均为false。
双重否定运算符!!计算值的真值。实际上是两个操作员,哪里!!x表示!(!x),并且行为如下:
如果x为假值!x为真,并且!!x为假。如果x是真值!x为假,并且!!x为真。
当在布尔上下文的顶层使用时(if、while或?)!!从行为上讲,操作员是一个no-op。例如,if(x)和if(!!x)表示相同的意思。
实际用途
然而,它有几个实际用途。
一种用法是将对象压缩到其真值,这样代码就不会保存对大对象的引用并保持其活动。分配!!some_big_object设置为变量,而不是some_biguobject让垃圾收集器使用它。这对于生成对象或假值(例如空值或未定义值)的情况非常有用,例如浏览器特征检测。
另一个用法,我在一个关于C对应的答案中提到了!!操作员使用“lint”工具查找常见的打字错误和打印诊断。例如,在C和JavaScript中,布尔运算的一些常见错误会产生其他输出不太布尔的行为:
如果(a=b)是赋值,然后使用b的真值;如果(a==b)是相等比较。如果(a&b)是位AND;如果(a&&b)是逻辑AND。2和5为0(假值);2&&5为真。
这个操作员向lint工具保证,您所写的就是您的意思:执行此操作,然后获取结果的真值。
第三种用途是产生逻辑XOR和逻辑XNOR。在C和JavaScript中,a&b都执行逻辑and(如果两边都为true,则为true),a&b执行逐位and。a||b执行逻辑或(如果至少有一个为真,则为真),a|b执行逐位或。有一个按位XOR(异或)作为^b,但没有用于逻辑XOR的内置运算符(如果只有一侧为真,则为真)。例如,您可能希望允许用户仅在两个字段中的一个字段中输入文本。您可以做的是将每个值转换为一个真值,并将它们进行比较:!!x!==!!y
以下是AngularJS的一段代码:
var requestAnimationFrame = $window.requestAnimationFrame ||
$window.webkitRequestAnimationFrame ||
$window.mozRequestAnimationFrame;
var rafSupported = !!requestAnimationFrame;
他们的意图是根据requestAnimationFrame中函数的可用性将rafSupported设置为true或false。
通常可以通过以下方式进行检查:
if(typeof requestAnimationFrame === 'function')
rafSupported =true;
else
rafSupported =false;
这条短路可以用!!
rafSupported = !!requestAnimationFrame;
因此,如果requestAnimationFrame被分配了一个函数,那么!requestAnimationFrame将为false,还有一个!这是真的。
如果requestAnimationFrame未定义,则!requestAnimationFrame将是真的,还有一个!这将是错误的。
看来是!!运算符导致双重否定。
var foo = "Hello, World!";
!foo // Result: false
!!foo // Result: true