operators and or - 何が!! JavaScriptでは演算子(not not)演算子ですか?





15 Answers

型変換を行うことは、あまりにも曖昧な方法です。

! そうではありません 。 そう!truefalse!falsetrueです。 !0trueで、 !1falseです。

したがって、値をブール値に変換してから反転し、反転します。

// Maximum Obscurity:
val.enabled = !!userId;

// Partial Obscurity:
val.enabled = (userId != 0) ? true : false;

// And finally, much easier to understand:
val.enabled = (userId != 0);
論理否定演算子 条件式 反転

2つの感嘆符の形で認識できない演算子を使用するようなコードがいくつか見られました!! 。 誰かがこのオペレータのしていることを教えてもらえますか?

私がこれを見た文脈は、

this.vertical = vertical !== undefined ? !!vertical : this.vertical;



いくつかのお茶を醸造する:

!! 演算子ではありません。 それは二重使用です! これは論理的な "not"演算子です。

理論的には:

! 価値がないものの「真実」を決定する:

  • 真実は、 falseが真実でないということtrue (それが理由!false結果がtrue

  • 真実は真実がfalseでないfalse (それが理由!true false !true結果)

!! 価値がないものの「真実」を決定する:

  • 真実は、真実がtrueはないということ true (それが!!true結果true

  • 真実は、 falsefalseはないという false (それは!!false結果です!!false

比較で決定したいの 、参照自体の価値ではなく、参照の価値に関する 「真実」です。 値がfalse (または偽)であることが予想される場合でも、値がbooleanないと予想される場合でも、値の真理を知りたいユースケースがあります。

実際には:

動的タイピング (別名「ダックタイピング」)によって、機能の機能性(この場合はプラットフォームの互換性)を検出する簡潔な機能を検討してください。 ユーザーのブラウザがHTML5の<audio>要素をサポートしている場合にtrueを返す関数を記述したいが、 <audio>が定義されていない場合は関数がエラーをスローしないようにしたい。 起こりうるエラーを処理するためにtry ... catchを使用することは望ましくありません。 また 、その機能に関する真実を一貫して明らかにしない関数内のチェックを使用したくない場合あります(たとえば、 document.createElement('audio')はHTML5 <audio>はサポートされていません)。

ここに3つのアプローチがあります:

// 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引数を受け取りattributeが、それぞれが比較が何を決定するかに基づいて異なる値を返します。

しかし、待って、もっと!

この特定の例で 、問題のオブジェクトがプロパティを持っているかどうかをチェックする、 よりパフォーマンスの良い手段を使って単にプロパティをチェックすることができることに気付いた人もいます。 これを行うには2つの方法があります:

// 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を得るための手段が実際には!! 。 うまくいけば、これはばかげてそれをクリアします。




!!fooはunary not演算子を2回適用し、unary plus +fooを使用して数値にキャストし、空の文字列''+fooを連結してstringにキャストするのと同様のブール型にキャストするために使用されます。

これらのハックの代わりに、プリミティブ型に対応するコンストラクタ関数を( new 使わずに )明示的に値をキャストするために使うこともできます。

Boolean(foo) === !!foo
Number(foo)  === +foo
String(foo)  === ''+foo



これは単なる論理NOT演算子です。つまり、何かをブール値に変換するために使用されます。例:

true === !!10

false === !!0



これは2倍の操作でnot 。 最初の! ブール値に変換し、その論理値を反転します。 二番目に! 論理値を反転させる。




それは!! 演算子は二重否定になります。

var foo = "Hello World!";

!foo // Result: false
!!foo // Result: true



私は言及する価値があると思いますが、論理AND / ORと組み合わせた条件はブール値を返さないが、最後の成功か最初の失敗は&&と最初の成功または最後の失敗の場合は|| 条件チェーンの

res = (1 && 2); // res is 2
res = (true && alert) // res is function alert()
res = ('foo' || alert) // res is 'foo'

条件を真のブールリテラルにキャストするために、二重否定を使用することができます。

res = !!(1 && 2); // res is true
res = !!(true && alert) // res is true
res = !!('foo' || alert) // res is true



それは1つの演算子ではなく、2つです。 これは以下に相当し、ブール値に値をキャストする簡単な方法です。

val.enabled = !(!enable);



ifwhileステートメントと? 演算子は、実行するコードの分岐を決定するために真理値を使用します。 たとえば、ゼロとNaN番号と空文字列はfalseですが、他の数字と文字列は真です。 オブジェクトはtrueですが、未定義の値とnullは両方ともfalseです。

二重否定演算子!! 値の真理値を計算します。 実際には!!x!(!x)意味し、次のように動作します。

  • xがfalseの場合、 !xtrue!!xfalseです。
  • xが真の値なら、 !xfalseであり、 !!xtrueです。

ブール・コンテキスト( ifwhile 、または? )の最上位レベルで使用すると、 !! オペレータは行動的にノーオペレーションです。 たとえば、 if (x)if (!!x)が同じものを意味するとします。

実用

しかし、いくつかの実用的な用途があります。

1つの使用法は、オブジェクトをその真理値に不可逆に圧縮することで、コードが大きなオブジェクトへの参照を保持せず、そのオブジェクトを存続させます。 !!some_big_object!!some_big_object代わりに変数にsome_big_objectすると、ガベージコレクタのためにそれをsome_big_objectます。 これは、オブジェクトや、ブラウザの機能の検出など、 nullや未定義の値などのfalse値を生成する場合に便利です。

私はCの対応についての答えで述べた別の使用!! 一般的なタイプミスや印刷診断を探す「糸くず」ツールを使用しています。 たとえば、CとJavaScriptの両方で、ブール演算の一般的な誤植は、出力がブール値ではない他の振る舞いを生成します。

  • if (a = b)が代入であり、 b真理値を使用した場合、 if (a == b)は等価比較です。
  • if (a & b)がビット単位のANDである場合 if (a && b)は論理ANDです。 2 & 50 (偽の値)です。 2 && 5は真です。

!! オペレーターはあなたが書いたことがあなたが意味するものであることを糸くずツールに安心させます。この操作を行い、結果の真理値を取る。

第3の用途は、論理XORおよび論理XNORを生成することである。 CとJavaScriptの両方でa && bは論理ANDを実行し(両辺が真の場合はtrue)、 a & bはビット単位のANDを実行します。 a || b a || bは論理ORを実行し(少なくとも1つが真であれば真)、 a | b a | bはビット単位のORを実行します。 a ^ bとしてビット単位の排他的論理和(排他的論理和)がありますが、論理XORの組込み演算子はありません(真偽が真であれば真です)。 たとえば、ユーザーが2つのフィールドのいずれかに正確にテキストを入力できるようにする場合があります。 あなたができることは、それぞれを真理値に変換して比較することです: !!x !== !!y




たくさんの素晴らしい答えがありますが、これまでに読んだことがあれば、これは私に「それを手に入れる」ことができました。 Chrome(など)でコンソールを開き、次のように入力します。

!(!(1))
!(!(0))
!(!('truthy')) 
!(!(null))
!(!(''))
!(!(undefined))
!(!(new Object())
!(!({}))
woo = 'hoo'
!(!(woo))
...etc, etc, until the light goes on ;)

当然のことながら、これは単にsomeThingと入力するだけで同じですが、括弧を追加すると理解しやすくなります。




!! NOT操作を2回一緒に使用してい! boolean値に値を変換し、それを逆にする、ここではどのように見て簡単な例です!! 作品:

まず、あなたが持っている場所:

var zero = 0;

!0を行うと、ブール値に変換され、0がfalsyであるためtrueと評価されるので、逆の値を取得してブール値に変換するので、 trueと評価されtrue

!zero; //true

逆のブール値のバージョンを望んでいないので、結果を得るために逆にすることができます! だから私たちは別のものを使うの!

基本的に、 !! 確かに、私たちが得る価値は真実ではなく、真実であるか、偽ではないかなどです。

だから、それはjavascriptでBoolean関数を使うのと似ていますが、値をブール値に変換する簡単で短時間の方法です:

var zero = 0;
!!zero; //false



JavaScriptの演算子の中には、暗黙の型変換を実行するものがあり、型変換に使用されることがあります。

単調! 演算子はそのオペランドをブール値に変換し、それを否定します。

この事実はあなたのソースコードで見ることができる次のイディオムにつながります:

!!x // Same as Boolean(x). Note double exclamation mark



a = 1;
alert(!a) // -> false : a is not not defined
alert(!!a) // -> true : a is not not defined

!a場合、 aが定義されていないかどうかをチェックし、 !!aは変数が定義されているかどうかをチェックします。

!!a !(!a)と同じ!(!a) aが定義されている場合、 atrue!afalse!!atrueです。




私はちょうどそれを追加したい

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

ここでのトリックは、 &&のチェーンが見つけた最初の偽の値を返します 。これはif文などに与えられます。したがって、b.fooが未定義の場合、未定義を返し、 b.foo.barをスキップしb.foo.bar私たちは何の誤りもありません。

上記の戻り値は未定義ですが、空の文字列、偽、null、0、未定義の値が返されると、すぐにチェーン内でそれらの値が返されます。 []{}はどちらも真実です。




!!ブール・コンストラクターを使用する場合と似ていますが、おそらくブール関数のようになります。

console.log(Boolean(null)); // Preffered over the Boolean object

console.log(new Boolean(null).valueOf()); // Not recommended for coverting non-boolean values

console.log(!!null); // A hacky way to omit calling the Boolean function, but essentially does the same thing. 


// The context you saw earlier (your example)
var vertical;

function Example(vertical)
{
        this.vertical = vertical !== undefined ? !!vertical : 
        this.vertical; 
        // Let's break it down: If vertical is strictly not undefined, return the boolean value of vertical and set it to this.vertical. If not, don't set a value for this.vertical (just ignore it and set it back to what it was before; in this case, nothing).   

        return this.vertical;
}

console.log( "\n---------------------" )

// vertical is currently undefined

console.log(new Example(vertical).vertical); // The falsey or truthy value of this.vertical
console.log(!!new Example(vertical).vertical); // Coerced value of this.vertical

vertical = 12.5; // set vertical to 12.5, a truthy value.
console.log(new Example(vertical).vertical); // The falsey or truthy value of this.vertical which happens to be true anyway
console.log(!!new Example(vertical).vertical); // Coerced value of this.vertical

vertical = -0; // set vertical to -0, a falsey value.
console.log(new Example(vertical).vertical); // The falsey or truthy value of this.vertical which happens to be false either way
console.log(!!new Example(vertical).vertical); // Coerced value of this.vertical

JavaScriptのfalse false強制し、真理値trueに強制ます。虚偽と真理値はステートメントでも使用でき、基本的に対応するブール値に「マップ」します。しかし、出力(戻り値)がほとんど異なるので、適切なブール値を頻繁に使用する必要はないでしょう。 if

これはキャスティングと似ているかもしれませんが、現実的にはこれは単なる偶然の可能性があり、ブールキャストのように意図的に作られているわけではありません。ですから、それをそれと呼ぶことはしません。

なぜ、どのように動作するのか

簡潔にするため、次のようになります! ( !null )。一方、nullあるfalsey、そう!nullだろう。その後!trueだろう、それは、本質的になり、バック反転し、この時間を除いて、それは前にあったものに、適切なブール値(あるいはその逆truthy値のような{}1)。


あなたの例に戻る

全体として、あなたが見た文脈は単に定義さthis.verticalれているかどうかに応じて調整verticalされます。結果として得られるブール値のverticalに設定されます。そうでない場合、変更されません。言い換えれば、if verticalが定義されている。this.verticalそのブール値に設定されます。そうでなければ、同じままです。私はそれ自体があなたがどのように使うのか!!、そしてそれが何をするのかの例であると思います。


垂直I / Oの例

この例題を実行して、入力の垂直方向の値でフィーリングしてみましょう。コンテキストのコードを完全に理解できるように、結果がどのようなものになるかを確認してください。入力には、有効なjavascript値を入力します。文字列をテストする場合は、引用符を含めることを忘れないでください。CSSとHTMLコードをあまり気にしないでください。単純にこのスニペットを実行し、それを使って遊んでください。しかし、非DOM関連のJavaScriptコード(Exampleコンストラクタと垂直変数の使用)を見てみたいかもしれません。

var vertical = document.getElementById("vertical");
var p = document.getElementById("result");

function Example(vertical)
{
        this.vertical = vertical !== undefined ? !!vertical : 
        this.vertical;   

        return this.vertical;
}

document.getElementById("run").onclick = function()
{

  p.innerHTML = !!( new Example(eval(vertical.value)).vertical );
  
}
input
{
  text-align: center;
  width: 5em;
} 

button 
{
  margin: 15.5px;
  width: 14em;
  height: 3.4em;
  color: blue;
}

var 
{
  color: purple;
}

p {
  margin: 15px;
}

span.comment {
  color: brown;
}
<!--Vertical I/O Example-->
<h4>Vertical Example</h4>
<code id="code"><var class="var">var</var> vertical = <input type="text" id="vertical" maxlength="9" />; <span class="comment">// enter any valid javascript value</span></code>
<br />
<button id="run">Run</button>
<p id="result">...</p>




Related