Question

I was testing Jakobs patch on the Sortables Class and this line this.reset() gave me a Uncaught TypeError: undefined is not a function.

I don't understand why since the Class has a method reset.

So my solution was to a var self = this; inside the same end: method (here), and called self.reset(); in the same line as I had this.reset(); before. Worked good. Why?

Then just to check (I suspected already) I did a console.log(this == self) and gave false.

Why does using self work but not this?

Fiddle

Was it helpful?

Solution

In javascript the this keyword change accordingly with the execution context

  • in global code this refer to the global object
  • inside eval the scope is the same as the calling context one, if no context provided then is the same as above
  • in all the case below if the this argument passed to .bind .call or .apply is not an object (or null) this will be the global object
  • when using a function which has been binded to a specific object using .bind then this refers to the this argument passed to bind, the function is now permabinded.
  • when running a function the context is provided from the caller, if before the function call operator () there is a dot(.) or a [] operator then this refers to the part on the left of such operator, unless the function is permabinded to something else or we are using .call or .apply if so this refers to the this argument unless the function was previously permabinded;
  • if before the function call operator () there neither the . nor the [] operators then this will refer to the global object (unless the function stores the result of the .bind function)
  • when running a constructor function (basically when using new) this refers to the object we are creating

now when using the use strict directive things changes a bit, mostly instead of the global object when the context is not given this will be null, but not in all the cases. I rarely use "use strict" so I just suggest to try it by yourself when in need.

now, what happens when a function is cached inside a variable like this:

var cache = 'A.foo'

if that you lose the context in which the original function was stored, so in this case foo will not be anymore a property on the instance A and when you run it using

cache()

the context will be evaluated using the rules I wrote above in this case the this will refer to the global object.

OTHER TIPS

The semantics of "this" in Javascript are not what is expected by OO programmers. The symbol "this" refers to the dynamic/runtime calling context, not the lexicographic context. For example, if you have an object A with "method" and then do B.method = A.method; B.method(); then the context is now B and that is what this will point to. The difference becomes very apparent in "handler" type situations where the calling context is usually the object with the handler installed.

Your solution using self is sound.

kentaromiura's answer is absolutely right.

That said, mootools provides function.bind() as a way to decide what this will refer inside of your function. this means that if you simply do this :

        var destroy = function () {
            `bind() [...]
            this.reset();
        }.bind(this);

it will work as you intended (that is, this will be the same inside of destroy() and outside).

Now, a lot of coders will balk at fiddling with the context, with good reason as it is very difficult to read and maintain. But here you have it and I think bind() is a very nifty trick of mootools.

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