31

the following function is designed to implement the indexOf property in IE. If you've ever had to do this, I'm sure you've seen it before.

if (!Array.prototype.indexOf){

  Array.prototype.indexOf = function(elt, from){

    var len = this.length >>> 0;
    var from = Number(arguments[1]) || 0;

    from = (from < 0)
         ? Math.ceil(from)
         : Math.floor(from);

    if (from < 0)
      from += len;

    for (; from < len; from++){
      if (from in this &&    
          this[from] === elt)
        return from;
    }

    return -1;    
  };
}

I'm wondering if it's common to use three greater than signs as the author has done in the initial length check?

var len = this.length >>> 0

Doing this in a console simply returns the length of the object I pass to it, not true or false, which left me pondering the purpose of the syntax. Is this some high-level JavaScript Ninja technique that I don't know about? If so, please enlighten me!

Salman A
  • 262,204
  • 82
  • 430
  • 521
Hacknightly
  • 5,109
  • 1
  • 26
  • 27

4 Answers4

34

>>> is the Zero-fill right shift operator. The >>> 0 is an abuse of the operator to convert any numeric expression to an "integer" or non-numeric expression to zero. Here is what it does:

This operator shifts the first operand the specified number of bits to the right. Excess bits shifted off to the right are discarded. Zero bits are shifted in from the left. The sign bit becomes 0, so the result is always positive.

Here is an explanation of the convert-to-integer behavior which applies to all bitwise operations:

Bitwise operators treat their operands as a sequence of 32 bits (zeros and ones), rather than as decimal, hexadecimal, or octal numbers. [...] Bitwise operators perform their operations on such binary representations, but they return standard JavaScript numerical values.

Together, these statements assert that expr >>> 0 will always return a positive number as follows:

  1. expr is cast to a 32-bit integer for bitwise operation
  2. >>> 0 has no effect (no bits are shifted)
  3. The result is converted to a Number

Here are a few expressions and their outcome:

        1 >>> 0 // 1 -- Number cast to 32-bit integer then back to Number
      "1" >>> 0 // 1 -- String cast to 32-bit integer then back to Number
undefined >>> 0 // 0 -- failed cast yields zero

Other interesting cases:

      1.1 >>> 0 // 1          -- decimal portion gets it
       -1 >>> 0 // 4294967295 -- -1 = 0xFFFFFFFF
                //               Number(0xFFFFFFFF) = 4294967295
      "A" >>> 0 // 0          -- cast failed
    "1e2" >>> 0 // 100        -- 1x10^2 is 100
   "1e10" >>> 0 // 1410065408 -- 1x10^10 is 10000000000
                //               10000000000 is 0x00000002540BE400
                //               32 bits of that number is 0x540BE400
                //               Number(0x540BE400) is 1410065408

Note: you will notice that none of them return NaN.

Salman A
  • 262,204
  • 82
  • 430
  • 521
23

Source: LINK

This is the zero-fill right shift operator which shifts the binary representation of the first operand to the right by the number of places specified by the second operand. Bits shifted off to the right are discarded and zeroes are added on to the left. With a positive number you would get the same result as with the sign-propagating right shift operator, but negative numbers lose their sign becoming positive as in the next example, which (assuming 'a' to be -13) would return 1073741820:

Code:

result = a >>> b;
Michael Haren
  • 105,752
  • 40
  • 168
  • 205
Brandon McKinney
  • 1,412
  • 11
  • 9
  • Wow, I was waaaaay off : ) Thank you sir, I have been enlightened, you get the tick. – Hacknightly Apr 21 '11 at 16:46
  • 8
    So what exactly is the effect of the usage in the example `var len = this.length >>> 0`? That would seem to do nothing. – Jamie Treworgy Apr 21 '11 at 16:49
  • Yes, but I was mainly just trying to figure out the usage in general. I can pretty much deduce from there what's going on. – Hacknightly Apr 21 '11 at 16:50
  • 7
    If you can deduce that please share! I think what's most interesting about this question is not what the bit shift operator does, but why you might do it with zero as an operand. – Jamie Treworgy Apr 21 '11 at 16:51
  • Sorry, after reviewing the docs, I realize that I have NO clue what the operator is accomplishing in the example. Hopefully some high level ninja will come through with the details. – Hacknightly Apr 21 '11 at 16:54
  • 1
    I have a guess which is that the intent is the same as `var len = this.length || 0` e.g. if the length property does not exist then set len = 0. – Jamie Treworgy Apr 21 '11 at 16:56
  • 22
    @jamietre: The end result is that any value will be converted to a number. If it isn't able to be converted, the number will be 0. Also, any decimal places will be stripped away. It is similar to doing `~~this.length`. So `"123" >>> 0` will be `123`, or `123.45 >>> 0` will be `123`, or `"some unconvertable value" >>> 0` will be `0`. – RightSaidFred Apr 21 '11 at 16:57
  • Excellent explanation @RightSaidFred. `||` would not convert a truthy non-numeric value. And a handy javascript trick I never knew before. – Jamie Treworgy Apr 21 '11 at 17:01
  • 1
    @RightSaidFred in this case, isn't this overkill? We *know* that `this` in an array with a `length` property that returns whole, positive numbers...right? – Michael Haren Apr 21 '11 at 17:14
  • @Michael Haren - while I'm sure my own implementation would start somewhere around line 25 of the mozilla code, I bet there are a number of possible conditions that could result in it being some non-array other than `null` (which is already checked). Somehow. Anyway, trust in mozilla. They know what's best for you. – Jamie Treworgy Apr 21 '11 at 17:18
  • @Michael: As @jamietre stated, it [appears to be based on code from Mozilla](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf#section_5), which is meant for general consumption, and is therefore coded for safety. In your personal code you probably wouldn't need to do this. – RightSaidFred Apr 21 '11 at 17:26
  • 1
    @jamietre @rightsaidfred I'm happy to rely on Mozilla's implementation, it'd just be nice to know *why* they do it that way. – Michael Haren Apr 21 '11 at 17:33
  • I can't answer why the implementation is done the way it is, but what the >>> operator does on an over-simplified level is trim the right-most X positions from a binary number. An example... 10 >>> 1 = 5 This is because decimal 10 is represented in binary as 1010. The >>> operator trims the last 1 position in this case, leaving 101 which back in decimal is 5. – Brandon McKinney Apr 21 '11 at 19:45
  • 4
    The only thing I can assume is that since bitwise operators are usually very very fast, it is done this way thinking in regards to optimal performance. No overhead of calling a function or performing a boolean comparison or anything. – Brandon McKinney Apr 21 '11 at 19:48
8

The >>> (right-shift) binary operator is simply shifting the right-most bits of a number a specified number of times, and padding with zeroes to the left.

Note: In the following examples, the number in braces after a number signals what base it's in. 2 is for binary, 10 for decimal.

For example, 4 >>> 1 would do:

4(10) = 100(2)

4(10) >>> 1(10) = 010(2) = 2(10)
        shift once to the right

Other examples:

4(10) >>> 2(10) = 100(2) >>> 2(10) = 001(2) = 1(10)

10(10) >>> 4(10) = 1010(2) >>> 4(10) = 0000(2) = 0(10)

15(10) >>> 1(10) = 1111(2) >>> 1(10) = 0111(2) = 7

The way I remember it is to move the necessary amount of bits to the right, and then write the number. Like, in the last example, I simply moved everything to the right once, so the result is 0111.

Shifting 0 times does...nothing. No idea why it's there.

Zirak
  • 38,920
  • 13
  • 81
  • 92
  • This is wrong. Bitwise operations convert the number to a *signed* 32-bit integer, unless they are on the leftside of an unsigned right shift by `0`. In that case, the number is converted to an *unsigned* 32-bit integer. –  Feb 27 '23 at 02:45
2

Behold the zero-fill right-shift operator.

https://developer.mozilla.org/en/JavaScript/Reference/Operators/Bitwise_Operators

Mike Hofer
  • 16,477
  • 11
  • 74
  • 110