web-dev-qa-db-ja.com

JavaScript >>>演算子とは何ですか?どのように使用しますか?

フィルターメソッドをArrayに追加するMozillaのコードを見ていましたが、混乱させるコード行がありました。

var len = this.length >>> 0;

JavaScriptで>>>を使用するのを見たことがありません。
それは何であり、何をしますか?

138
Kenneth J

非数値を数値に変換するだけでなく、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.length0.5-11e21、または'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を使用したとしても驚かないでしょう。しかし、それは実装の詳細ではありません。の利点。)

192
bobince

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仕様に準拠する方法。前述したように、 符号なし右シフト演算子 が最も簡単な方法です。

56
CMS

それは 符号なし右ビットシフト 演算子です。これと signed right bit shift operator の違いは、unsignedright bit shift operator(>>>))左からゼロで埋め、signed右ビットシフト演算子(>>)は符号ビットで埋められ、シフトされたときに数値の符号を保持します。

30
driis

Driis は、演算子が何であり、何をするかを十分に説明しています。その背後にある意味/使用された理由は次のとおりです。

0で任意の方向にシフトすると、元の数値が返され、null0にキャストされます。あなたが見ているコード例は、this.length >>> 0が定義されていない場合でもlenが数値であることを保証するためにthis.lengthを使用しているようです。

多くの人にとって、ビット単位の操作は不明確です(そしてDouglas Crockford/jslintは、そのようなものの使用に反対するよう提案しています)。間違っているという意味ではありませんが、コードを読みやすくするために、より有利で馴染みのある方法が存在します。 len0であることを確認するより明確な方法は、次の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; 
28
Justin Johnson

>>>は、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つの理由:

  1. 負の数を使用する場合の<<<の動作は、上記の例では意図しない(または発生する可能性が高い)副作用です。

  2. この質問の存在が検証するため、コードの意図は明らかではありません

ベストプラクティスは、おそらくパフォーマンスが絶対に重要でない限り、より読みやすいものを使用することです。

isNaN(parseInt(foo)) ? 0 : parseInt(foo)
15
fmark

2つの理由:

  1. >>>の結果は「積分」です

  2. undefined >>> 0 = 0(JSはLFSを数値コンテキストに強制しようとするため、これは "foo" >>> 0などにも機能します)

JSの数値はdoubleの内部表現を持つことに注意してください。これは、長さに対する基本的な入力の健全性の「クイック」方法です。

ただし、、-1 >>> 0(おっと、おそらく望ましい長さではありません!)

10
user166390

サンプル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
0
nitinsridar