22

I see in almost all examples of a knockout.js viewmodels the line var self = this and then all local variables are references as self.variableName. What is the advantage of this over using this.variableName?

Neil
  • 2,488
  • 7
  • 30
  • 53
  • 4
    Because `this` changes in every scope, but `self` will contain default `this` value. – Narek Jun 18 '13 at 07:46
  • 1
    possible duplicate of [var self = this?](http://stackoverflow.com/questions/337878/var-self-this) and http://stackoverflow.com/questions/962033/what-underlies-this-javascript-idiom-var-self-this – nemesv Jun 18 '13 at 07:47

3 Answers3

39

Normally the main reason for using this approach is to make the current this available to subfunctions or closures. For example:

var myObject = {
  param: 123,
  method: function(){
    alert( this.param );
  },
  method2: function(){
    setTimeout(function(){
      alert( this.param );
    },100);
  }
}

In the above calling myObject.method will give you the correct alert of 123. However calling myObject.method2 will give you undefined. This is because this inside the anonymous function used with setTimeout does not refer to myObject, depending on the JavaScript interpreter it will point to different things. However, if you have:

method2: function(){
  var self = this;
  setTimeout(function(){
    alert( self.param );
  },100);
}

This works because the current state of this — at the right point — is captured, and will always reference myObject for every function scope that it is available to.

The problem is not limited to the use of setTimeout. At any point where you have anonymous functions, subfunctions or closures this trick will come in handy. Sometimes people use self, or that or something a bit more descriptive depending on what the current reference represents.


rather than storing as a variable

There is an alternative to using self or any other variable to "remember" the state of this at any particular point, and that is to "bind" your anonymous or sub functions with a particular context. Many modern interpreters now support the Function.prototype.bind method, which can be used thusly:

var method = function(){
  console.log(this);
};
var methodWithWindow = method.bind(window);
var methodWithDocument = method.bind(document);
var methodWithObject = method.bind({random:"object"});

Calling each of the bound methods in turn would give you the following console output:

Window
Document
Object {random:"object"}

If you wish to support older browsers you can use a polyfill, or if you prefer a much simpler implementation, one that doesn't worry about binding arguments as well. The basics of what the bind code does is the following:

!Function.prototype.bind && (Function.prototype.bind = function(context){
  var method = this;
  return function(){
    method.apply(context, arguments);
  }
})

So, how would the initial example look using bind?

method2: function(){
  setTimeout((function(){
    console.log(this); // `this` will be the same as the `this` passed to bind.
  }).bind(this),100);
}

As you can see above, once bound, the returned function (closure) retains that specified context; so it can be passed around where ever you want and still keep a this reference to the object you want. This is useful in the method2 example because we bundle the method up with our current context and pass it to setTimeout which will execute the bound method later (long after we have exited the current block execution).

The same does occur for when using self or any other variable. The variable would be captured within the function's scope chain, and would still be there for access when the function is eventually called again. The benefit of using bind however is that you can override the context easily if you so wish, you would have to code your own specific methods to do so to override a self variable.

WARNING: It is worth noting here that when you bind a function, a new function is returned. This can cause confusing situations if you mix bound functions with event listeners and then attempt to remove the listeners using the original function rather than the bound version.

Also, because binding returns a new function, if you bind a bound function you are in fact wrapping a function in a function, with another function. You should be aware of this because it affects performance and will prove trickier to manage in terms of avoiding memory leaks. My preferred approach to binding is to use closures with their own deconstruction methods (i.e. rely on self, but make sure you have methods to nullify it's content), but this does take more forward thinking and is not so relevant in smaller JS projects; or one off function bindings — especially if the bound method is never caught in any reference.


without self and bind?

It is also worth mentioning that sometimes you can achieve the same result without using bind at all, and instead use apply — which should be natively available in anything you may choose to use. The major difference being that nothing is wrapped up with the function, and calling apply actually executes the function there and then with a different context — the first argument passed to apply.

var externalMethod = function(){
  console.log(this); // will output myObject when called below
};

var myObject = {
  method2: function(){
    externalMethod.apply(this);
  }
};


What is this?

Just to elaborate this answer with further detail about this — before the recent comments get deleted. this will refer to one of four things, depending on how the function you are using it within was called:

myObject.method()

The above will have a this of myObject, unless method has had a .bind(context) operation applied. In which case this will be whatever the last bound context was.

unattachedFunction()

Will have a this of the global context (usually window in browser environments), unless unattachedFunction has had a .bind(context) operation applied. In which case this will be whatever the last bound context was.

anyFunction.apply(otherObject)

or

anyFunction.call(otherObject)

Both will always have a this of otherObject, because calling in this way will override any binding.

new myObject()

Will have a this that refers to a new instance of myObject, this will override any binding.


Simple thought experiment

Taking all the above into account, what would this be inside referencedMethod?

var referencedMethod = myObject.method;
referencedMethod();

Correct! it will be the global context. This is why if you want to share methods with other objects or code — but still retain the original owner as context — you really need to either bind, or keep the function bundled with its owner object so you can call or apply.

Pebbl
  • 31,117
  • 6
  • 57
  • 63
  • does it refer to first higher level function ? or when it's called inside a function which is used as a function parameter, til a field variable, it do this? (sorry to use C# ... based terms, don't know the equivalent in js) – deadManN Jun 13 '15 at 06:29
  • 1
    `this` will refer to one of three things, depending on how the function you are using `this` within was called: `myObject.method()` will have a `this` of `myObject`, `unattachedMethod()` will have a `this` of the global context (usually `window` in browser environments), and `anyFunction.apply(otherObject)` will always have a `this` of `otherObject`. The first two I mention would be overridden by any `.bind(differentObject)` operation, whereas the latter `.apply()` or `.call()` wouldn't. Hope that makes sense @deadManN – Pebbl Jun 13 '15 at 07:48
  • thank you, but is it only about `apply` and `call`? or its about functions that take `otherObject` as input, which parameter take priority of using `this` object, like ... the function do that, to this object, or just existance of parameter cause this, or specific kind of parameter cause it like... x(funcObj) / x(strObj) / Y(classObj) – deadManN Jun 13 '15 at 08:20
  • 1
    I'm not quite sure what you mean @deadManN. There are only three real ways to call a function in JavaScript. As a stand-alone function or a variable containing a function `standAlone()` or `var sa = myObject.method; sa();`, as a method of an object `myObject.method()` or via `call/apply`. Only the latter two specify what is called the context i.e. what `this` refers to. For the method call the object that is specified on the left-hand-side is used as the context, so `myObject.method()` means `this` is `myObject`, for `call` and `apply` it is the first argument that is used. – Pebbl Jun 13 '15 at 17:24
  • 1
    you get me right, thank you... sorry for bad language, i'm not native – deadManN Jun 14 '15 at 05:22
2

Self is used to make sure the original this is maintained within the object.

This comes in handy when using event handlers and so on.

You can read more about this here

The first answer covers it basically, also it shows a good link. Check it out.

Community
  • 1
  • 1
Tikkes
  • 4,219
  • 4
  • 30
  • 57
1

It is used for reference purposes. this under Javascript behaves different than in other languages. For more details look at MDN Docs on this

Thomas Junk
  • 5,296
  • 2
  • 25
  • 39