Question

I did an JavaScript experiment in browser's console -

First I created a new object foo as following

  var foo = {
    bar: function() { return this.baz; },
    baz: 1
  };

Now when I run the following code again in console it returns "number"

  (function(){
    return typeof foo.bar();
  })();

But when I run following anonymous function it returns "undefined"

  (function(){
    return typeof arguments[0]();
  })(foo.bar);

As far as I know arguments[0] in above function return foo.bar (also proved by the following example) then why the above code returns "undefined" instead of "number"?


When I run

      (function(){
        return arguments[0];
      })(foo.bar);

returns function () { return this.baz; }


Also

  (function(){
    return typeof arguments[0];
  })(foo.bar());

Returns "number" then why not

  (function(){
    return typeof arguments[0]();
  })(foo.bar);

returns the same? Is there any fundamental law in JavaScript that is working here?

Was it helpful?

Solution 2

Let me simplify the problem ...

var foo = {
    bar: function() { return this.baz; },
    baz: 1
};


var ref = foo.bar;

console.log(typeof ref()); // undefined
console.log(typeof foo.bar()); // number

It is because 'this' inside the function object 'bar' does not always refer to 'foo'. It changes on how you call it. If you call it from an object not foo it will show undefined. Note that ref is not foo but foo.bar.

Now if you change foo to the following it will give 'number' output in both cases ...

var foo = {
    bar: function() { return foo.baz; },
    baz: 1
};

Note that

console.log(ref === foo.bar); // true

but foo.bar() is not equal to ref() (In first case) because when you call foo.bar() the javascript engine passes foo as 'this' but when you call ref() which is originally window.ref(), it passes window object (or other global object in case of non-browser environment) as 'this'

OTHER TIPS

this depends on how you call the function. When using dot notation, JavaScript sets the context of this to the receiver. In your case there is no receiver, but a reference to the function, so you lost the context. You have to pass it explicitly:

arguments[0].call(foo);

arguments[0] is the same function object as foo.bar but the value of this is dynamic. In foo.bar(), this gets assigned to foo because you used foo. (dot notation). But in arguments[0]() there's no dot (no receiver) so this is the default value, or window.

It's the same function but different invocation.

Elaboration on elclanrs' answer.

foo.bar is a method; an instruction of how to do something. In object-oriented programming languages, the only object that can use that instruction is a foo or an object related to foo; but in JavaScript, anybody can try to run it if the code asks them to.

In your second anonymous function, you are getting a method to run, running it, and returning the type of the result. However, it's not a foo that is running this function; it's anonymous, so the window is the object that's running it. The window runs foo, which tries to return this.baz; however, the window doesn't HAVE a baz, so that's why you're getting undefined.

To test it further, try setting window.baz and see if you get the right result, and also try elclanrs' suggestion of using the call() method to ensure it gets called from a foo's scope.

EDIT

You're right, the type of arguments[0] and foo.bar IS the same; they're both "function". I think the confusion is over JavaScript's treatment of functions as first-class objects.

If you're familiar with object-oriented languages like Java or C++, then you would expect that when you call bar, it's always being called by a foo that has a baz property; however, this isn't the case in JavaScript. Any function can be called by ANY object, which means the result may or not make sense.

The difference between the two, as elclanrs says, is all about the .. Let's say I made my own object phew = {baz: 44}. I could, validly, "steal" a method from foo like this: phew.myMethod = foo.bar. Now, phew knows the instructions contained in bar, and if I call phew.myMethod(), I would get 44 as my result because phew is calling the method, and phew's baz is 44; it doesn't matter where the method is defined! All that matters is what the method says to do, and bar says to return the baz of whoever called it.

So now, going back to your code, you're calling arguments[0](). It does seem like it should be the same, but because functions are first-class objects, when you passed it as a parameter, all you really passed was a function called bar. When you called arguments[0](), it was like calling bar(), which is different from calling foo.bar() just like it's different from calling phew.myMethod(), even though they all are exactly the same function.

For more info, try this SO post

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top