Arrayにフィルターメソッドを追加するMozillaのコードを見ていましたが、混乱を招くコード行がありました。
var len = this.length >>> 0;
私は>>>がJavaScriptで使用されるのを見たことがありません。
それは何ですか、何をしますか?
Array.prototype.push
/ Array.prototype.pop
- hexmen.com/blog/2006/12/push-and-popを(彼はテストをしたものの、笑)。
Arrayにフィルターメソッドを追加するMozillaのコードを見ていましたが、混乱を招くコード行がありました。
var len = this.length >>> 0;
私は>>>がJavaScriptで使用されるのを見たことがありません。
それは何ですか、何をしますか?
Array.prototype.push
/ Array.prototype.pop
- hexmen.com/blog/2006/12/push-and-popを(彼はテストをしたものの、笑)。
回答:
非数値を数値に変換するだけでなく、32ビットの符号なし整数として表現できる数値に変換します。
JavaScriptの数字は、倍精度浮動小数点数(*)であるが、ビット単位の演算子(<<
、>>
、&
、|
および~
)は、32ビット整数の操作で定義されています。ビット単位の演算を行うと、数値が32ビットの符号付きintに変換され、計算を実行してからNumberに変換する前に、小数部と32より上位のビットが失われます。
そのため、0ビットの右シフトのように、実際に影響を与えずにビット単位の演算を行う>>0
ことは、数値を丸めて32ビットのint範囲にあることを確認する簡単な方法です。さらに、トリプル>>>
演算子は、符号なし演算を実行した後、その計算結果を、他の演算子が行う符号付き整数ではなく、符号なし整数としてNumberに変換するため、負の値を32ビットの2の補数に変換するために使用できます。大きな数値としてのバージョン。を使用>>>0
すると、0〜0xFFFFFFFFの整数が得られます。
この場合、ECMAScriptは32ビットの符号なし整数で配列インデックスを定義するため、これは便利です。したがってarray.filter
、ECMAScriptの第5版の標準の内容とまったく同じ方法で実装しようとしている場合は、このように数値を32ビットのunsigned intにキャストします。
(実際にはうまくいけば、人々が設定されようとしていないとして、このために少し実用的な必要性がありますarray.length
し0.5
、-1
、1e21
または'LEMONS'
あなたが知っていることはありませんので、。しかし、これは私たちが話しているJavaScriptの作者であるが...)
概要:
1>>>0 === 1
-1>>>0 === 0xFFFFFFFF -1>>0 === -1
1.7>>>0 === 1
0x100000002>>>0 === 2
1e21>>>0 === 0xDEA00000 1e21>>0 === -0x21600000
Infinity>>>0 === 0
NaN>>>0 === 0
null>>>0 === 0
'1'>>>0 === 1
'x'>>>0 === 0
Object>>>0 === 0
(*:まあ、フロートのように振る舞うように定義されています。パフォーマンス上の理由から、JavaScriptエンジンが実際にintを使用したとしても驚くことではありません。しかし、それは実装の詳細ではありません。の利点。)
RangeError: invalid array length
。
Array.prototype.filter.call
)で呼び出すことができるため、array
実際にはそうではないArray
可能性があります。それは、他のユーザー定義クラスである可能性があります。(残念ながら、それが確実にNodeListであるとは限りません。これは、本当にそれを実行したい場合です。これは、ホストオブジェクトであるためです。これにより、arguments
疑似配列として現実的に実行できる唯一の場所が
if
ステートメント評価の左側はint型ではなかったことを識別しようとすると、このためのように見えますか?'lemons'>>>0 === 0 && 0 >>>0 === 0
真と評価しますか?レモンは明らかに言葉ですが..?
符号なし右シフト演算子は、Mozilla のすべての配列extraのメソッド実装で使用され、length
プロパティが符号なし32ビット整数であることを確認します。
length
配列オブジェクトのプロパティは、仕様では次のように説明されています。
すべてのArrayオブジェクトにはlengthプロパティがあり、その値は常に2 32未満の負でない整数です。
この演算子はそれを実現するための最短の方法です。内部的に配列メソッドがToUint32
操作を使用しますが、そのメソッドにはアクセスできず、実装目的で仕様に存在します。
Mozilla 配列エクストラの実装はECMAScript 5に準拠しようとしています。Array.prototype.indexOf
メソッドの説明(15.4.4.14)をご覧ください。
1. thisを渡してToObjectを呼び出した結果をOとする 引数として。 2. lenValueをOの[[Get]]内部メソッドを呼び出した結果とする 引数「長さ」。 3. lenをToUint32(lenValue)にします。 ....
ご覧のToUint32
ように、ES3実装のES5仕様に準拠するようにメソッドの動作を再現したいだけで、前に述べたように、符号なし右シフト演算子が最も簡単な方法です。
ToUint32
はちょっと不必要に思えます。
Array.prototype
メソッドは意図的にジェネリックであり、配列のようなオブジェクトで使用できることに注意してArray.prototype.indexOf.call({0:'foo', 1:'bar', length: 2}, 'bar') == 1;
ください。arguments
オブジェクトは、良い例です。以下のために、純粋な配列オブジェクトは、タイプ変更することは不可能だlength
、彼らは特別を実装するので、プロパティを[Put
]]内部メソッド、および割り当てをした場合length
プロパティ、再び変換されるToUint32
と他の動作は上記のインデックスを削除するように、取得され新しい長さ...
これは、符号なし右ビットシフト演算子です。このとの間の差の符号付き右ビットシフト演算は、ということである符号なし右ビットシフト演算子(>>>は)左からゼロで埋め、そして署名された右ビットシフト演算子(>>従って、符号ビットを有する)塗りつぶしシフト時に数値の符号を保持します。
>>>
単項で+
は行われない整数に変換します。
Driisは、オペレーターとは何か、オペレーターが何をするかについて十分に説明しています。その背後にある意味/使用された理由は次のとおりです。
doによって任意の方向にシフトする0
と、元の数が返され、にキャストさnull
れ0
ます。あなたが見ているサンプルコードは、定義されていなくても数値であるthis.length >>> 0
ことを確認するために使用しているようです。 len
this.length
多くの人にとって、ビットごとの操作は不明確です(そして、ダグラス・クロックフォード/ jslintはそのようなものの使用を勧めていません)。それが間違っているという意味ではありませんが、コードを読みやすくするためのより好都合で使い慣れた方法が存在します。ことを確認するために、より明確な方法len
では、0
次の2つの方法のいずれかです。
// Cast this.length to a number
var len = +this.length;
または
// Cast this.length to a number, or use 0 if this.length is
// NaN/undefined (evaluates to false)
var len = +this.length || 0;
NaN
.. Egが+{}
:...それは、2つ組み合わせることがおそらく最善です+length||0
>>>
ある符号なし右シフト演算は、(JavaScriptの1.5仕様の、P。76を参照のとは対照的に)>>
、署名された右シフト演算子。
>>>
シフト時に符号ビットを保持しないため、負の数をシフトした結果を変更します。この結果は、例によって、インタプリタから理解できます。
$ 1 >> 0
1
$ 0 >> 0
0
$ -1 >> 0
-1
$ 1 >>> 0
1
$ 0 >>> 0
0
$ -1 >>> 0
4294967295
$(-1 >>> 0).toString(16)
"ffffffff"
$ "cabbage" >>> 0
0
したがって、おそらくここで行うことを意図しているのは、長さを取得すること、または"cabbage"
上記の例のように、長さが定義されていないか整数でない場合は0を取得することです。この場合、それはthis.length
決して起こらないと仮定しても安全だと思います< 0
。それにもかかわらず、この例は 2つの理由で厄介なハックであると主張します。
<<<
負の数を使用する場合の動作、上記の例ではおそらく意図しない(または発生する可能性が高い)副作用。
この質問の存在が確認するように、コードの意図は明白ではありません。
パフォーマンスが絶対に重要でない限り、ベストプラクティスはおそらくもっと読みやすいものを使用することです。
isNaN(parseInt(foo)) ? 0 : parseInt(foo)
-1 >>> 0
発生する可能性はありますか?このようにすると、ループが必要以上に数回実行されます。
this.length
に知ることは不可能です。「健全な」実装では、文字列の長さが負になることはありませんが、「健全な」環境ではthis.length
常に整数を返すプロパティの存在を想定できると主張する人もいます。
2つの理由:
>>>の結果は「積分」です
undefined >>> 0 = 0(JSはLFSを数値コンテキストに変換しようとするため、これは "foo" >>> 0などでも機能します)
JSの数値はdoubleの内部表現を持つことに注意してください。これは、長さの基本的な入力健全性の「迅速な」方法にすぎません。
ただし、-1 >>> 0(おっと、おそらく望ましい長さではありません!)
以下のサンプルJavaコードはよく説明しています:
int x = 64;
System.out.println("x >>> 3 = " + (x >>> 3));
System.out.println("x >> 3 = " + (x >> 3));
System.out.println(Integer.toBinaryString(x >>> 3));
System.out.println(Integer.toBinaryString(x >> 3));
出力は次のとおりです。
x >>> 3 = 536870904
x >> 3 = -8
11111111111111111111111111000
11111111111111111111111111111000