6

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?

2
  • 2
    Even var x = [].reverse; x(); throws the same error. I don't know why it was window for you :( Commented Feb 24, 2014 at 4:12
  • @thefourtheye: sorry forgot to mention.. the code above was run in Chrome Console. Commented Feb 24, 2014 at 4:18

3 Answers 3

5

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.

Sign up to request clarification or add additional context in comments.

3 Comments

You mean to say, in strict mode undefined will be used? I tried this on Node.js and got the same error for var x = [].reverse; x();. I havn't even put "use strict";
@thefourtheye - yes. In strict mode, this is set to undefined if called as x().
@thefourtheye - in this case, it doesn't really matter whether you're in strict mode or not because x() isn't going to work either way (it will fail differently, but still fail either way). You need to be associating the method with an array object. I don't know what you're trying to do, but you either need to do array.reverse() or something like x.call(array).
1

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]

Comments

0

The original question is about the output of the following code.

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

But the output of the snippet above is

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

Actually the equivalent call as follow gives the same error:

Array.prototype.reverse.call();

So, The answer of the question on JavaScript Puzzler is not correct. Though the Array.prototype.reverse return this, the snippet will still throw an error, caused by lacking of an associating object.

This question can be used to test, if the tested one did understand the function definition via var, in which the var only holds the methods and drops the associating object.

Solution: (bind the associating object by calling)

// An associated object can be bound as below.
   var x = [].reverse;
   x.bind([1,2,3])();
// output : [3,2,1]
// equivalent to 
   Array.prototype.reverse.call([1,2,3]);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.