三元運算子javascript - 運算元是什麼
是什麼 !!(不是)JavaScript中的運算符? (20)
我看到一些代碼似乎使用了一個我不認識的運算符,以兩個感嘆號的形式出現,如下所示: !!
。 有人可以告訴我這個運營商做了什麼?
我看到這個的背景是,
this.vertical = vertical !== undefined ? !!vertical : this.vertical;
JavaScript中的某些運算符執行隱式類型轉換,有時用於類型轉換。
一元!
運算符將其操作數轉換為布爾值並取消它。
這個事實導致您可以在源代碼中看到以下習語:
!!x // Same as Boolean(x). Note double exclamation mark
! 是“boolean not”,它基本上將“enable”的值強制轉換為其布爾相反的值。 第二 ! 翻轉此值。 因此, !!enable
表示“不能啟用”,為您提供enable
作為布爾值的值。
!!
將其右側的值轉換為其等效的布爾值。 (想想窮人的“打字”方式)。 它的目的通常是向讀者傳達代碼並不關心變量中的值是什麼,而是它的“真值”值 。
!!
構造是將任何JavaScript表達式轉換為其布爾等效項的簡單方法。
例如: !!"he shot me down" === true
和!!0 === false
。
!!expr
根據表達式的真實性返回一個布爾值( true
或false
)。 在非布爾類型上使用時更有意義。 考慮這些示例,尤其是第3個示例及以後的示例:
!!false === false
!!true === true
!!0 === false
!!parseInt("foo") === false // NaN is falsy
!!1 === true
!!-1 === true // -1 is truthy
!!"" === false // empty string is falsy
!!"foo" === true // non-empty string is truthy
!!"false" === true // ...even if it contains a falsy value
!!window.foo === false // undefined is falsy
!!null === false // null is falsy
!!{} === true // an (empty) object is truthy
!![] === true // an (empty) array is truthy; PHP programmers beware!
!!foo
應用unary not運算符兩次並用於轉換為布爾類型,類似於使用unary plus +foo
轉換為數字並連接空字符串''+foo
以轉換為字符串。
您也可以使用與基元類型相對應的構造函數( 不使用new
)來顯式地轉換值,而不是這些hacks,即
Boolean(foo) === !!foo
Number(foo) === +foo
String(foo) === ''+foo
if
和while
語句和?
運算符使用真值來確定要運行的代碼分支。 例如,零和NaN數字以及空字符串為false,但其他數字和字符串為true。 對象為true,但未定義的值和null
都為false。
雙重否定運算符!!
計算值的真值。 它實際上是兩個運算符,其中!!x
表示!(!x)
,其行為如下:
- 如果
x
是假值,則!x
為true
,並且!!x
為false
。 - 如果
x
是真值,則!x
為false
,並且!!x
為true
。
當在布爾上下文的頂層使用時( if
, while
或?
), !!
運營商在行為上是無操作的。 例如, if (x)
和if (!!x)
表示相同的事情。
實際用途
然而,它有幾個實際用途。
一種用法是將對像有損壓縮到其真值,這樣您的代碼就不會持有對大對象的引用並使其保持活動狀態。 將!!some_big_object
分配給變量而不是some_big_object
,可以將其用於垃圾收集器。 這對於生成對像或false值(例如null
或未定義值(例如瀏覽器功能檢測)的情況非常有用。
另一個用途,我在答案中提到了C的相應!!
操作員 ,使用“lint”工具查找常見的拼寫錯誤和打印診斷信息。 例如,在C和JavaScript中,布爾運算的一些常見拼寫錯誤會產生其輸出不完全為布爾值的其他行為:
-
if (a = b)
是賦值,則使用b
的真值;if (a == b)
是相等比較。 -
if (a & b)
是按位AND;if (a && b)
是邏輯AND。2 & 5
是0
(假值);2 && 5
是真的。
!!
操作員向lint工具保證,您所寫的內容就是您的意思:執行此操作,然後獲取結果的真值。
第三種用途是產生邏輯XOR和邏輯XNOR。 在C和JavaScript中, a && b
執行邏輯AND(如果雙方都為真,則為true), a & b
執行按位AND。 a || b
a || b
執行邏輯OR(如果至少有一個為真,則為true)和a | b
a | b
執行按位OR。 有一個按位XOR(異或)作為a ^ b
,但沒有內置運算符用於邏輯XOR(如果恰好一側為真,則為true)。 例如,您可能希望允許用戶在兩個字段中的一個字段中輸入文本。 你可以做的是將每個轉換為真值並比較它們: !!x !== !!y
。
煮一些茶:
!!
不是運營商。 它是兩用的!
- 這是邏輯“非”運算符。
理論上:
!
確定價值不是什麼的“真相”:
事實是
false
不是true
(這就是為什麼!false
結果是true
)事實是,
true
並非false
(這就是原因!true
結果是false
)
!!
確定價值不是什麼的“真相”:
事實是,
true
並非true
(這就是為什麼!!true
結果是true
)事實是
false
並非false
(這就是為什麼!!false
結果為false
)
我們希望在比較中確定的是關於參考值的“真相”,而不是參考本身的值 。 有一個用例我們可能想知道一個值的真相,即使我們期望該值為false
(或假),或者我們期望該值不是boof的類型。
在實踐中:
考慮一個簡潔的功能,通過動態類型 (又名“鴨子打字”)檢測功能功能(在這種情況下,平台兼容性)。 我們想編寫一個函數,如果用戶的瀏覽器支持HTML5 <audio>
元素,則返回true
,但如果<audio>
未定義,我們不希望該函數拋出錯誤; 我們不想使用try ... catch
來處理任何可能的錯誤(因為它們很嚴重); 而且我們也不想在函數內部使用一個不能一致地揭示該特性的真相的檢查(例如,即使HTML5 <audio>
, document.createElement('audio')
仍將創建一個名為<audio>
的元素<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>
的參數和要查找的attribute
,但它們每個都根據比較確定的值返回不同的值。
但等等,還有更多!
你們中的一些人可能已經註意到,在這個具體的例子中,人們可以使用稍微更高效的方法來檢查一個屬性,以檢查相關對像是否具有屬性。 有兩種方法可以做到這一點:
// 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
我們離題了......
無論這種情況多麼罕見,可能存在一些場景,其中最簡潔,最高效,最優選的方法是從非布爾值,可能是未定義的值獲得true
的確是通過使用!!
。 希望這可笑地清除它。
在看到所有這些很棒的答案後,我想補充一點使用原因 !!
。Currenty我正在使用Angular 2-4(TypeScript),我希望返回一個布爾值,就像false
我的用戶未經過身份驗證一樣。如果他未經過身份驗證,則令牌字符串將為null
或""
。我可以通過使用下一個代碼塊來完成此操作:
public isAuthenticated(): boolean {
return !!this.getToken();
}
它不是一個單一的運營商,而是兩個。 它等同於以下內容,是一種將值轉換為布爾值的快速方法。
val.enabled = !(!enable);
它將後綴轉換為布爾值。
它模擬了Boolean()
轉換函數的行為。 第一個NOT
返回一個布爾值,無論給出什麼操作數。 第二個NOT
否定了Boolean
值,因此給出了變量的true
布爾值。 最終結果與對Boolean()
使用Boolean()
函數相同。
我只想補充一點
if(variableThing){
// do something
}
是相同的
if(!!variableThing){
// do something
}
但是當某些事情未定義時,這可能是一個問題。
// a is undefined, b is empty object.
var a, b = {};
// Both of these give error a.foo is not defined etc.
// you'd see the same behavior for !!a.foo and !!b.foo.bar
a.foo
b.foo.bar
// This works -- these return undefined
a && a.foo
b.foo && b.foo.bar
b && b.foo && b.foo.bar
這裡的技巧是&&
s 鏈將返回它找到的第一個falsey值 - 這可以被提供給if語句等。所以如果b.foo未定義,它將返回undefined並跳過該b.foo.bar
語句,我們得不到錯誤。
上面的返回未定義,但如果你有一個空字符串,false,null,0,undefined這些值將返回,並且很快我們在鏈中遇到它們 - []
並且{}
都是真實的。
我懷疑這是C ++的遺留物,人們會覆蓋它! 運營商,但不是bool運營商。
因此,要獲得負面(或肯定)答案,您首先需要使用! 運算符得到一個布爾值,但如果你想檢查肯定的情況會使用!!
看來!!
運算符導致雙重否定。
var foo = "Hello World!";
!foo // Result: false
!!foo // Result: true
返回變量的布爾值。
相反,可以使用Boolean
類。
(請閱讀代碼說明)
var X = "test"; // X value is "test" as a String value
var booleanX = !!X // booleanX is `true` as a Boolean value beacuse non-empty strings evaluates as `true` in boolean
var whatIsXValueInBoolean = Boolean(X) // whatIsXValueInBoolean is `true` again
console.log(Boolean(X) === !!X) // writes `true`
即,使用Boolean(X) = !!X
請檢查下面的代碼片段↓
let a = 0
console.log("a: ", a) // writes a value in its kind
console.log("!a: ", !a) // writes '0 is NOT true in boolean' value as boolean - So that's true.In boolean 0 means false and 1 means true.
console.log("!!a: ", !!a) // writes 0 value in boolean. 0 means false.
console.log("Boolean(a): ", Boolean(a)) // equals to `!!a`
console.log("\n") // newline
a = 1
console.log("a: ", a)
console.log("!a: ", !a)
console.log("!!a: ", !!a) // writes 1 value in boolean
console.log("\n") // newline
a = ""
console.log("a: ", a)
console.log("!a: ", !a) // writes '"" is NOT true in boolean' value as boolean - So that's true.In boolean empty strings, null and undefined values mean false and if there is a string it means true.
console.log("!!a: ", !!a) // writes "" value in boolean
console.log("\n") // newline
a = "test"
console.log("a: ", a) // writes a value in its kind
console.log("!a: ", !a)
console.log("!!a: ", !!a) // writes "test" value in boolean
console.log("Boolean(a) === !!a: ", Boolean(a) === !!a) // writes true
這是進行類型轉換的一種非常模糊的方式。
!
不是 。 所以!true
是false
,而且!false
是true
。 !0
為true
, !1
為false
。
所以你要將一個值轉換為布爾值,然後將其反轉,然後再將其反轉。
// Maximum Obscurity:
val.enabled = !!userId;
// Partial Obscurity:
val.enabled = (userId != 0) ? true : false;
// And finally, much easier to understand:
val.enabled = (userId != 0);
這是雙重操作。 第一個!
將值轉換為布爾值並反轉其邏輯值。 第二個!
將邏輯值反轉回來。
這麼多答案做了一半的工作。 是的, !!X
可以被解讀為“X的真實性[表示為布爾]”。 但是!!
實際上,對於確定單個變量是否(或者即使許多變量是真實的)真實或虛假也是如此重要。 !!myVar === true
和myVar
。 將!!X
與“真實”布爾值進行比較並不是很有用。
你獲得了什麼!!
能夠以可重複,標準化(和JSLint友好)的方式檢查多個變量的真實性。
簡單鑄造:(
那是...
-
0 === false
是false
。 -
!!0 === false
是true
。
以上不太有用。 if (!0)
給出的結果與if (!!0 === false)
。 我想不出將變量轉換為布爾值然後與“true”布爾值進行比較的好例子。
請參閱JSLint的指示中的 “==和!=”(注意:Crockford正在移動他的網站;這個鏈接可能會在某些時候死亡),原因如下:
==和!=運算符在比較之前鍵入強制。 這很糟糕,因為它會導致'\ t \ r \ n'== 0為真。 這可以掩蓋類型錯誤。 JSLint無法可靠地確定是否正確使用==,因此最好不要使用==和!=並始終使用更可靠的===和!==運算符。
如果您只關心某個值是真或假,那麼請使用簡短形式。 代替
(foo != 0)
說啊
(foo)
而不是
(foo == 0)
說
(!foo)
請注意,在將布爾值與數字進行比較時,會出現一些非直觀的情況 ,其中布爾值將強制轉換為數字( true
為1
, false
為0
)。 在這種情況下, !!
可能在精神上有用。 雖然,再次, 這些是您將非布爾值與硬類型布爾值進行比較的情況,即imo,這是一個嚴重的錯誤。 if (-1)
仍然是去這裡的方式。
╔═══════════════════════════════════════╦═══════════════════╦═══════════╗
║ Original ║ Equivalent ║ Result ║
╠═══════════════════════════════════════╬═══════════════════╬═══════════╣
║ if (-1 == true) console.log("spam") ║ if (-1 == 1) ║ undefined ║
║ if (-1 == false) console.log("spam") ║ if (-1 == 0) ║ undefined ║
║ Order doesn't matter... ║ ║ ║
║ if (true == -1) console.log("spam") ║ if (1 == -1) ║ undefined ║
╠═══════════════════════════════════════╬═══════════════════╬═══════════╣
║ if (!!-1 == true) console.log("spam") ║ if (true == true) ║ spam ║ better
╠═══════════════════════════════════════╬═══════════════════╬═══════════╣
║ if (-1) console.log("spam") ║ if (truthy) ║ spam ║ still best
╚═══════════════════════════════════════╩═══════════════════╩═══════════╝
根據您的引擎,事情變得更加瘋狂。 例如,WScript贏得了獎項。
function test()
{
return (1 === 1);
}
WScript.echo(test());
由於一些歷史的Windows jive ,它會在消息框中輸出-1! 在cmd.exe提示符下嘗試,看看! 但是WScript.echo(-1 == test())
仍然給你0,或者WScript是false
。 把目光移開 這很可怕。
比較真實:)
但是,如果我有兩個值,我需要檢查相同的truthi / falsi-ness?
假設我們有myVar1 = 0;
和myVar2 = undefined;
。
-
myVar1 === myVar2
為0 === undefined
,顯然是假的。 -
!!myVar1 === !!myVar2
是!!0 === !!undefined
並且是真的! 同樣誠實! (在這種情況下,兩者都“有真實性”。)
因此,你真正需要使用“boolean-cast變量”的唯一地方是,如果你有一個情況,你要檢查兩個變量是否具有相同的真實性,對吧? 就是用!!
如果你需要看看兩個變量是真實的還是假的 (或者不是),那就是相同 (或不真實 )。
我無法想到一個偉大的,非人為的用例。 也許你在表單中有“鏈接”字段?
if (!!customerInput.spouseName !== !!customerInput.spouseAge ) {
errorObjects.spouse = "Please either enter a valid name AND age "
+ "for your spouse or leave all spouse fields blank.";
}
所以現在,如果您對配偶姓名和年齡都有兩者或一個假人,你可以繼續。 否則,您只有一個具有值的字段(或非常早期排列的婚姻),並且需要在您的errorObjects
集合上創建額外的錯誤。
編輯2017年10月24日:
期望顯式布爾值的第三方庫
這是一個有趣的案例...... !!
當第三方庫期望顯式布爾值時,可能會有用。
例如, JSX中的False(React)具有特殊含義 ,不會在簡單的虛假中觸發。 如果您嘗試在JSX中返回類似下面的內容,則期望在messageCount
使用int ...
{messageCount && <div>You have messages!</div>}
...當你沒有消息時,你可能會驚訝地看到React呈現0
。 您必須為JSX顯式返回false才能呈現。 上面的語句返回0
,JSX愉快地呈現,應該如此。 它不能告訴你沒有Count: {messageCount && <div>Get your count to zero!</div>}
(或者不那麼做作的東西)。
一個修復涉及bangbang,強制
0
進入!!0
,這是false
:
{!!messageCount && <div>You have messages!</div>}
JSX的文檔建議你更明確,編寫自我評論代碼,並使用比較強制轉換為布爾值。
{messageCount > 0 && <div>You have messages!</div>}
我更自在地用三元組來處理虛假 -
{messageCount ? <div>You have messages!</div> : false}
請記住, 這是一個JSX約定 ,而不是JavaScript固有的約定 。
但是如果你在渲染的JSX中看到奇怪的0
,那就考慮鬆散的虛假管理。
雙布爾否定。 通常用於檢查值是否未定義。