Where is my 'this'? Using objects method a

2020-02-06 02:43发布

问题:

I have a generic question about javascript specification or implementation of functions pointer (delegates?) which are points to object methods.

Please, read the following code snippet. Here we have an object with a method using 'this' to access an object field. When we call this method as usual (o.method();), returns value of the specified field of the object. But when we create pointer to this method (callback) and invoke it, returns an undefined value, because 'this' inside method's scope now is global object.

var o = {
    field : 'value', 
    method : function() {
        return this.field;
    }
};

o.method(); // returns 'value'

var callback = o.method;

callback(); // returns 'undefined' cause 'this' is global object

So, where is my 'this'?

回答1:

"this" is late binding. that is, it gets bound to a thing just before the function is executed. What it is bound to depends on how you call your function.

if you call it like (function invokation):

   myfunction();

"this" is bound to the global object

if you call it like (method invokation):

   myobject.myfunction();

"this" gets bound to "myobject"

you can also call it like so (call invokation):

   myfunction.call(myobject);

in which case "this" gets bound to myobject

there is also (constructor invokation):

 new MyFunction();

in which "this" gets bound to a newly constructed blank object whose prototype is MyFunction.prototype.

this is how the creators of javascript talk about it, anyway. (and I think it is discussed this way in the spec) Different ways of invoking a function.

the new version of the ecmascript standard (ecmascript5) includes the prototype library's "bind" method, which returns a new function with "this" prebound to something you specify. for instance:

  mynewfunction = myfunction.bind(myobject);
  mynewfunction();

the invokation of mynewfunction has "this" already bound to myobject.



回答2:

You can specify the context of this for example when you call a method through the .apply() or .call() methods. In your case, like you said, the context has changed. If you really need to make field be o.field, you have to tell explicitly so, for example by using a closure when defining your method method.



回答3:

You're right it wasn't valid javascript. I was thinking of using new function which allows you to have multiple instances:


function o2(value) {
    var _this = this;
    this.field = value;
    this.method = function() { 
        return _this.field;
    };
}

var test1 = new o2('blah'); var test2 = new o2('meh');

var callback1 = test1.method; var callback2 = test2.method;

alert(callback1()); alert(callback2());

Alternatively if you want to continue using a singleton you can reference o from within the object.

var o = {
    field : 'value', 
    method : function() {
       return o.field;
    }
};