Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

calling Array.prototype.reverse() on empty array?

Tags:

javascript

Note: the code in this question was run in Chrome Console.

I encountered this problem when I was doing the JS-puzzler, question 21 (well.. it didn't gave a ordering though). The question ask about the result of:

var x = [].reverse; x();

and the answer is window. As the answer states:

[].reverse will return this and when invoked without an explicit receiver object it will default to the default this AKA window.

Based on this understanding, I wrote a bit of code to test:

function Bar(){
  var x = [].reverse;
  console.log(x());
}
new Bar();

And guess what.. this code raise an error:

TypeError: Array.prototype.reverse called on null or undefined

I want to ask why the x() called in the new Bar is not showing the this object, but raising exception instead?

like image 661
songyy Avatar asked Feb 24 '14 04:02

songyy


2 Answers

When you call a function as in x(), the this pointer will be set to either window or undefined (in strict mode). It is the method of calling the function that determines that value of this.

The methods of calling that let you control the value of this are:

x.call(xxx)
x.apply(xxx)
foo.x()

Calling as just:

x()

will set this to the default value which is window in normal JS mode orundefined in strict mode.

The other thing you may want to understand is that once you do:

var x = [].reverse;

Then, x only holds a reference to the reverse() function. There is no association at all with the [] that you originally used. So, when you call x(), you're just calling the reverse() function with no object association and thus this gets set to the default value which is window in normal JS mode or undefined in JS strict mode.

like image 53
jfriend00 Avatar answered Sep 30 '22 17:09

jfriend00


It's because you're getting a function reference without the scope it executes on. The reverse function, in its source, references this. If you call a function properly:

var obj = {
    run: function() { console.log(this) }
};

obj.run(); // this will be obj, as expected

But if you call it like this:

var broken = obj.run;
broken(); // this will be the global object

It's just the way javascript execution works in regards to scope. Calling a function with dot notation on an object will make this the object it's on.

If you're in a modern browser, you can bind the value of this to the right thing:

var arr = [1,2,3];
var boundReverse = arr.reverse.bind( arr );

boundReverse() // [3, 2, 1]
like image 20
Andy Ray Avatar answered Sep 30 '22 16:09

Andy Ray