3

In the following code, I'm wondering how context is bound to this:

In obj.myMethod();, context is given to the object. So logging it gives the object.

In var myFun = obj.myMethod; then myFun();, context is given to the Window.

The only difference is you're setting the function to a variable.

    var obj = {

        myMethod : function () {
            console.log(this); //'this' is bound to context of object
        }
    };

    obj.myMethod(); //calling object property directly = Object {myMethod: function}

    var myFun = obj.myMethod;   
    myFun(); //but setting obj method property to a variable and running gives Window as context

EDIT:

Following this melonJS tutorial, I'm confused how this callback is used (Scroll down to Part 2: Loading our level, you will see complete code)

// Set a callback to run when loading is complete.
me.loader.onload = this.loaded.bind(this);

I read this tutorial on callbacks, so I understand what they're used for... But I don't understand. It says this.loaded.bind(this)

What is the difference between this first and second this statements? Aren't they the same? Why do I need to call this then .loaded.bind() then pass in this again?

So, in your example, you say I can keep context by doing var bindMe = obj.myMethod.bind(obj);, and in this case, you're using this because you're already within the object game? So this refers to the owner game?

Thank you

Dan
  • 9,391
  • 5
  • 41
  • 73
user3871
  • 12,432
  • 33
  • 128
  • 268
  • Besides bind you can also use closures, they are a very powerful tool in JavaScript: under http://stackoverflow.com/a/16063711/1641941 "the this variable" – HMR Mar 13 '14 at 00:56

2 Answers2

3

Short answer

In the expression

obj.f()

this within f will be bound to the value of obj (the expression on the left hand-side of the .).

If a function is invoked "alone", i.e.

f()

then this within f is bound to the global object (in the browser, window).

That said, you can set the context before hand using the .bind function, i.e.

var g = obj.f.bind(obj);
f(); // success! this == obj

c.f. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

You might also want to take a look at the .call and .apply functions.


Key point: functions DO NOT carry a context around. obj.f is a member access, all it does is return the value of the property f from obj. The context is set when you CALL the function, either with obj.f() or f() in f exists in the global scope, in which case the context would be the global object.

Long answer

Read the specs! :) http://www.ecma-international.org/ecma-262/5.1/#sec-10.3

Aegis
  • 1,749
  • 11
  • 12
  • 1
    Exactly what I was looking for. Thanks! But in my second part, aren't I setting the context of the variable to the objects function? Why does it lose context to the obj? I guess only bind can solve that? – user3871 Mar 12 '14 at 22:03
  • 3
    You mean in var myFun = obj.myMethod; myFun(); ? The issue there is that myFun is affected the value of obj.myMethod, which is a function. However, functions do not carry a context around; instead, the context is set when they are invoked (either through a dot-expression or directly). – Aegis Mar 12 '14 at 22:06
  • I'm also unclear of the point of call and apply. If it makes sense to add them here and clarify their use, can u do that? Thanks – user3871 Mar 12 '14 at 22:08
  • @Aegis awesome explanation! can you expand on `obj.func()` losing context to `var` assignment? – Vikram Mar 12 '14 at 22:09
  • 1
    @Vikram I tried to add some explanations on that. I do realise my answer is a bit messy; I should hopefully get better with time at structuring my thoughts :) – Aegis Mar 12 '14 at 22:15
  • @Aegis last thing. I've made an edit to my question. I'm confused on why `this.loaded.bind(this)` is needed, and how it's a callback... – user3871 Mar 12 '14 at 22:18
  • At some point in the future some piece of code is going to call onload (= this.loaded). In the body of that function (l.44 in the tutorial) you want 'this' to refer to the 'game' object. For that you need to bind 'this.loaded' before you set it. Does that make any sense? – Aegis Mar 12 '14 at 22:24
  • Everything except `is going to call onload (= this.loaded)`. How does `onload` = `this.loaded`? "onload" is one function member of game, "loaded" is another function member of game. – user3871 Mar 12 '14 at 22:31
  • I don't know how this game works but when you set `me.loader.onload = ...` you define a function that will be called when the game is loaded. It's the same thing as `window.onload = ...` if you have ever used it (some function that will be executed when the webpage has finished loading). Now as I said, functions do not carry a context around. So when `this.loaded` will be called the context will most probably be the global object. However, you would like the context to be the `game` object since `loaded` is a member of it. You could also write `this.loaded.bind(game)`. Got it? :) – Aegis Mar 12 '14 at 22:36
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/49609/discussion-between-growler-and-aegis) – user3871 Mar 12 '14 at 22:40
1

this can be thought of as the owner of the function. There are only really three rules how this can be set. It will be

  • the new object for a constructor function called with the new operator (e.g. new Car())
  • the object itself when called with the . operator (e.g. obj.fn())
  • the context set using fn.call, fn.apply or fn.bind

Otherwise it will be the window object (or null in ES5 strict mode).

Daff
  • 43,734
  • 9
  • 106
  • 120