What is the JavaScript >>> operator and how do you use it?
Asked Answered
B

7

174

I was looking at code from Mozilla that add a filter method to Array and it had a line of code that confused me.

var len = this.length >>> 0;

I have never seen >>> used in JavaScript before.
What is it and what does it do?

Blasting answered 30/11, 2009 at 20:59 Comment(3)
@CMS True, this code/question comes from those; however, the response here are more specific and valuable than those previous.Dicrotic
Or it's a bug or Mozilla guys are assuming this.length could be -1. >>> is unsigned shift operator so var len will always be 0 or greater.Canberra
Ash Searle found a use for it - overturning the lord of JS (Doug Crockford)'s implementation to Array.prototype.push / Array.prototype.pop - hexmen.com/blog/2006/12/push-and-pop (though he did the tests, haha).Refutative
A
239

It doesn't just convert non-Numbers to Number, it converts them to Numbers that can be expressed as 32-bit unsigned ints.

Although JavaScript's Numbers are double-precision floats(*), the bitwise operators (<<, >>, &, | and ~) are defined in terms of operations on 32-bit integers. Doing a bitwise operation converts the number to a 32-bit signed int, losing any fractions and higher-place bits than 32, before doing the calculation and then converting back to Number.

So doing a bitwise operation with no actual effect, like a rightward-shift of 0 bits >>0, is a quick way to round a number and ensure it is in the 32-bit int range. Additionally, the triple >>> operator, after doing its unsigned operation, converts the results of its calculation to Number as an unsigned integer rather than the signed integer the others do, so it can be used to convert negatives to the 32-bit-two's-complement version as a large Number. Using >>>0 ensures you've got an integer between 0 and 0xFFFFFFFF.

In this case this is useful because ECMAScript defines Array indexes in terms of 32 bit unsigned ints. So if you're trying to implement array.filter in a way that exactly duplicates what the ECMAScript Fifth Edition standard says, you would cast the number to 32-bit unsigned int like this.

In reality there's little practical need for this as hopefully people aren't going to be setting array.length to 0.5, -1, 1e21 or 'LEMONS'.

Summary:

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

(*: well, they're defined as behaving like floats. It wouldn't surprise me if some JavaScript engine actually used ints when it could, for performance reasons. But that would be an implementation detail you wouldn't get to take any advantage of.)

Alkyd answered 30/11, 2009 at 22:13 Comment(4)
+2 in depth description and table, -1 because array.length validates itself and can't be arbitrarily set to anything that is not an integer or 0 (FF throws this error: RangeError: invalid array length).Dicrotic
However, the spec deliberately allows many Array functions to be called on non-Array (eg. via Array.prototype.filter.call), so array might not actually be a real Array: it might be some other user-defined class. (Unfortunately, it can't reliably be a NodeList, which is when you'd really want to do that, as that's a host object. That leaves the only place you'd realistically do that as the arguments pseudo-Array.)Alkyd
Great explanation and great examples! Unfortunately this is another insane aspect of Javascript. I just don't understand what's so horrible about throwing an error when you receive the wrong type. It's possible to allow dynamic typing without allowing every accidental mistake to create a type casting. :(Indoctrinate
" Using >>>0 ensures you've got an integer between 0 and 0xFFFFFFFF." what would the if statement look like for this when trying to identify that the left side of the evaluation was not an int? 'lemons'>>>0 === 0 && 0 >>>0 === 0 evaluates as true? even though lemons is obviously a word..?Corrales
R
59

The unsigned right shift operator is used in the all the array extra's method implementations of Mozilla, to ensure that the length property is a unsigned 32-bit integer.

The length property of array objects is described in the specification as:

Every Array object has a length property whose value is always a nonnegative integer less than 232.

This operator is the shortest way to achieve it, internally array methods use the ToUint32 operation, but that method is not accessible and exist on the specification for implementation purposes.

The Mozilla array extras implementations try to be ECMAScript 5 compliant, look at the description of the Array.prototype.indexOf method (§ 15.4.4.14):

1. Let O be the result of calling ToObject passing the this value 
   as the argument.
2. Let lenValue be the result of calling the [[Get]] internal method of O with 
   the argument "length".
3. Let len be ToUint32(lenValue).
....

As you can see, they just want to reproduce the behavior of the ToUint32 method to comply with the ES5 spec on an ES3 implementation, and as I said before, the unsigned right shift operator is the easiest way.

Reginiaregiomontanus answered 21/6, 2010 at 4:12 Comment(3)
While the linked array extras implementation may be correct (or close to correct) the code is still a bad code example. Perhaps even a comment to clarify intention would resolve this situation.Primulaceous
Is it possible that the length of an array is not an integer? I can't imagine that, so this kind of ToUint32 seems a bit unnecessary to me.Importation
@Marcel: Keep in mind that most of the Array.prototype methods are intentionally generic, they can be used on array-like objects e.g. Array.prototype.indexOf.call({0:'foo', 1:'bar', length: 2}, 'bar') == 1;. The arguments object is also a good example. For pure array objects, it's impossible to change the type of the length property, because they implement an special [[Put]] internal method, and when an assignment is made to the length property, again is converted ToUint32 and other actions are taken, like deleting indexes above the new length...Chrysostom
O
34

That is the unsigned right bit shift operator. The difference between this and the signed right bit shift operator, is that the unsigned right bit shift operator (>>>) fills with zeroes from the left, and the signed right bit shift operator (>>) fills with the sign bit, thus preserving the sign of the numerical value when shifted.

Overlook answered 30/11, 2009 at 21:1 Comment(5)
Ivan, that would shift it by 0 places; that statement wouldn't change anything.Carlcarla
@Ivan, normally, I would say that shifting a value by zero places makes absolutely no sense. But this is Javascript, so there might be a meaning behind it. I am not a Javascript guru, but it might be a way to ensure that the value is in fact an integer in the typeless Javasacript language.Overlook
@Ivan, see Justin's answer below. It is in fact a way to ensure that the len variable contains a number.Overlook
Further, >>> converts to an integer, which unary + does not do.Fascicle
this.length >>> 0 converts a signed integer to an unsigned one. Personally I've found this useful when loading a binary file with unsigned ints in it.Ignition
D
29

Driis has sufficiently explained what the operator is and what it does. Here's the meaning behind it/why it was used:

Shifting any direction by 0 does returns the original number and will cast null to 0. It seems that the example code that you are looking at is using this.length >>> 0 to ensure that len is numeric even if this.length is not defined.

For many people, bitwise operations are unclear (and Douglas Crockford/jslint suggests against using such things). It doesn't mean that its wrong to do, but more favorable and familiar methods exist to make code more readable. A more clear way to ensure that len is 0 is either of the following two methods.

// Cast this.length to a number
var len = +this.length;

or

// Cast this.length to a number, or use 0 if this.length is
// NaN/undefined (evaluates to false)
var len = +this.length || 0; 
Dicrotic answered 30/11, 2009 at 21:10 Comment(4)
Although, your second solution would sometimes evaluate to NaN.. E.g. +{} ... It's probably best to combine the two: +length||0Mauretania
this.length is in the context of the array object, which cannot be anything besides a non-negative integer (at least in FF), so it is not a possibility here. Also, {} || 1 returns {} so you are no better off if this.length is an object. The benefit to also unary casting this.length in the first method is that it handles cases where this.length is NaN. Edited response to reflect that.Dicrotic
jslint would complain about var len = +this.length too as "confusing plusses". Douglas, you so picky!Shedd
Douglas is picky. And while his arguments are wise and typically well founded, what he says is not absolute nor gospel.Dicrotic
P
15

>>> is the unsigned right shift operator (see p. 76 of the JavaScript 1.5 specification), as opposed to the >>, the signed right shift operator.

>>> changes the results of shifting negative numbers because it does not preserve the sign bit when shifting. The consequences of this is can be understood by example, from an interpretter:

$ 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

So what is probably intended to be done here is to get the length, or 0 if the length is undefined or not an integer, as per the "cabbage" example above. I think in this case it is safe to assume that this.length will never be < 0. Nevertheless, I would argue that this example is a nasty hack, for two reasons:

  1. The behavior of <<< when using negative numbers, a side-effect probably not intended (or likely to occur) in the example above.

  2. The intention of the code is not obvious, as the existence of this question verifies.

Best practice is probably to use something more readable unless performance is absolutely critical:

isNaN(parseInt(foo)) ? 0 : parseInt(foo)
Primulaceous answered 21/6, 2010 at 3:49 Comment(4)
Sooo... @johncatfish is correct? It's to ensure this.length is non-negative?Fedak
Could the case of -1 >>> 0 ever happen and if so, is it really desirable to shift it to 4294967295? Seems like this would cause the loop to run a few more times than necessary.Criss
@deceze: Without seeing the implementation of this.length it is impossible to know. For any "sane" implementation the length of a string should never be negative, but then one might argue that in a "sane" environment we can assume the existence of a this.length property that always returns an integral number.Primulaceous
you say >>> doesn't preserve the sign bit.. ok.. So, i'd have to ask, when we deal with negative numbers.. prior to any >>> or >> conversion, are they in 2s compliement form, or are they in signed integer form, and how would we know? By the way, 2s complement I think is perhaps not said to have a sign bit.. it's an alternative to signed notation, but it is possible to determine the sign of an integerTourbillion
S
10

Two reasons:

  1. The result of >>> is an "integral"

  2. undefined >>> 0 = 0 (since JS will try and coerce the LFS to numeric context, this will work for "foo" >>> 0, etc. as well)

Remember that numbers in JS have an internal-representation of double. It's just a "quick" way of basic input sanity for length.

However, -1 >>> 0 (oops, likely not a desired length!)

Safekeeping answered 21/6, 2010 at 3:50 Comment(0)
B
0

Sample Java Code below explains well:

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));

Output is the following:

x >>> 3 = 536870904
x >> 3 = -8
11111111111111111111111111000
11111111111111111111111111111000
Braithwaite answered 2/8, 2019 at 13:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.