フィルターメソッドをArrayに追加するMozillaのコードを見ていましたが、混乱させるコード行がありました。
var len = this.length >>> 0;
JavaScriptで>>>を使用するのを見たことがありません。
それは何であり、何をしますか?
非数値を数値に変換するだけでなく、32ビットの符号なし整数として表現できる数値に変換します。
JavaScriptのNumbersは倍精度のfloat(*)ですが、ビットごとの演算子(<<
、>>
、&
、|
および~
)は用語で定義されています32ビット整数での演算。ビット単位の演算を実行すると、数値が32ビット符号付き整数に変換され、計算を実行してから数値に戻す前に、32より大きい小数部と上位ビットが失われます。
したがって、0ビットの右シフト>>0
のように、実際の効果なしでビット単位の操作を行うと、数値をすばやく丸めて32ビット整数範囲に確実に収めることができます。さらに、トリプル>>>
演算子は、符号なしの操作を行った後、計算結果を他の符号付き整数ではなく符号なし整数としてNumberに変換するため、負の値を32に変換するために使用できます。大きな数値としてのビット2の補数バージョン。 >>>0
を使用すると、0〜0xFFFFFFFFの整数が得られます。
この場合、ECMAScriptは32ビットの符号なし整数に関して配列インデックスを定義するため、これは便利です。したがって、array.filter
をECMAScript Fifth Editionの標準が示す内容とまったく同じ方法で実装しようとする場合、このように32ビットの符号なし整数に数値をキャストします。
(実際には、人々が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を使用したとしても驚かないでしょう。しかし、それは実装の詳細ではありません。の利点。)
length
プロパティがnsigned 32-bit integerであることを保証するために、Mozillaのすべてのarray extra'sメソッド実装で符号なし右シフト演算子が使用されます。
配列オブジェクトのlength
プロパティは、仕様では 記述 です。
すべてのArrayオブジェクトには、値が常に2未満の非負整数であるlengthプロパティがあります32。
この演算子はそれを実現する最短の方法です。内部的に配列メソッドは ToUint32
操作ですが、そのメソッドにはアクセスできず、実装目的で仕様に存在します。
Mozilla array extras実装は ECMAScript 5 に準拠しようとします。Array.prototype.indexOf
メソッド(§15.4.4.14):
1。 Oを、引数としてthis値 を渡してToObjectを呼び出した結果とします。 2。 lenValueを、 引数 "length"でOの[[Get]]内部メソッドを呼び出した結果とします。 3。 lenをToUint32(lenValue)。 .... とする
ご覧のとおり、彼らは単にToUint32
ES3実装のES5仕様に準拠する方法。前述したように、 符号なし右シフト演算子 が最も簡単な方法です。
それは 符号なし右ビットシフト 演算子です。これと signed right bit shift operator の違いは、unsignedright bit shift operator(>>>))左からゼロで埋め、signed右ビットシフト演算子(>>)は符号ビットで埋められ、シフトされたときに数値の符号を保持します。
Driis は、演算子が何であり、何をするかを十分に説明しています。その背後にある意味/使用された理由は次のとおりです。
0
で任意の方向にシフトすると、元の数値が返され、null
が0
にキャストされます。あなたが見ているコード例は、this.length >>> 0
が定義されていない場合でもlen
が数値であることを保証するためにthis.length
を使用しているようです。
多くの人にとって、ビット単位の操作は不明確です(そしてDouglas Crockford/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;
>>>
は、unsigned右シフト演算子です( p。 JavaScript 1.5仕様の )、>>
とは異なり、signed右シフト演算子。
>>>
は、がシフト時に符号ビットを保持しないため、負の数をシフトした結果を変更します。この結果は、インタープリターからの例によって理解できます:
$ 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)
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