Scoping problem with Javascript callback

前端 未结 3 1483
眼角桃花
眼角桃花 2021-01-24 11:28

I am having some trouble getting a callback function to work. Here is my code:

SomeObject.prototype.refreshData = function()
{
  var read_obj = new SomeAjaxCall         


        
相关标签:
3条回答
  • 2021-01-24 12:03

    Well the most straightforward thing to do is to just wrap "this.readSuccess" in another function:

    SomeObject.prototype.refreshData = function()
    {
      var obj = this;
      var read_obj = new SomeAjaxCall("read_some_data", { }, 
        function() { obj.readSuccess(); }, function() { obj.readFail(); });
    }
    

    Some Javascript frameworks provide a utility to "bind" a function to an object, which simply means that it creates one of those little functions for you. Note that the variable "obj" will be "remembered" by those little functions, so when your handlers are called the "this" reference will be to the object that was used to call "refreshData".

    0 讨论(0)
  • 2021-01-24 12:09

    Your problem here is not exactly a closure or scoping problem. The problem is that when you assign this.readSuccess to a variable, you assign the function itself without any notion of the object it originaly belongs to.

    In the same way, you can take a regular, "stand-alone" function and use it as method of an object:

    function hello() {
        alert("Hello "+this.planet);
    }
    var planet = "Earth";
    hello(); // -> 'Hello Earth'
    
    var Venus = {
        planet: "Venus"
    };
    hello.apply(Venus); // -> 'Hello Venus'
    Venus.hello = hello;
    Venus.hello(); // -> 'Hello Venus'
    

    And your problem can be replicated in this example

    var helloVenus = Venus.hello;
    helloVenus(); // -> 'Hello Earth'
    

    So your problem is to assign this.readSuccess to some variable and having it called as a method of this. Which can be done with a closure as demonstrated by Pointy. Since I don't know what "SomeAjaxCall" actually does, it's hard to know if the value of this is actually lost and if var obj = this is actually needed. Chances are that it's not, so you can be fine with this kind of code:

    var helloVenus = function() { Venus.hello() }
    helloVenus(); // -> 'Hello Venus'
    

    In your case, that would be (edit: adding the arguments passed to the handler) :

    SomeObject.prototype.refreshData = function()
    {
      var read_obj = new SomeAjaxCall(
        "read_some_data",
        { },
        function () { this.readSuccess.apply(this, arguments) },
        function () { this.readFail.apply(this, arguments) }
      );
    }
    

    As noted previously, several js frameworks offer a bind function to simplify this kind of issue. But you don't need a complete framework just for this : here is a perfectly fine Function#bind method that works an plain javascript:

    Function.prototype.bind = function(obj) {
        var __method = this;
        var args = [];
        for(var i=1; i<arguments.length; i++)
            args.push(arguments[i]);
        return function() {
            var args2 = [];
            for(var i=0; i<arguments.length; i++)
                args2.push(arguments[i]);
            return __method.apply(obj, args.concat(args2));
        };
    }
    

    With the help of Function#bind, you can write:

    SomeObject.prototype.refreshData = function()
    {
      var read_obj = new SomeAjaxCall(
        "read_some_data",
        { },
        this.readSuccess.bind(this),
        this.readFail.bind(this)
      );
    }
    
    0 讨论(0)
  • 2021-01-24 12:19

    The following site seems to suggest that the problem may be more in your "class" building than in the usage. If you read down to the "rewrite using prototype properties", they write that that particular method of "class" structuring will keep the methods global instead of instance-based. Perhaps another creation method?

    http://devedge-temp.mozilla.org/viewsource/2001/oop-javascript/

    0 讨论(0)
提交回复
热议问题