Calling an object function from onload event makes it lose the context

喜欢而已 提交于 2021-01-28 00:00:39

问题


I wanted to call a function when all required images are loaded. The number of images is known in advance, so I tried attaching a function call to the onload event of each image and count the number of times it was called.

<html>

<head>
    <script>

    var tractor;

    function Tractor()
    {
        this.init_graphics();
    }

    Tractor.prototype.init_graphics = function()
    {
        this.gr_max = 3;
        this.load_count = 0;

        this.loading_complete(); // #1 test call, works OK

        this.img1 = new Image();
        this.img1.onload = this.loading_complete; // #2 gets called, but gr_max = undefined, load_count = NaN
        this.img1.src = "http://dl.dropbox.com/u/217824/tmp/rearwheel.gif"; //just a test image
    }

    Tractor.prototype.loading_complete = function()
    {
        this.load_count += 1;
        alert("this.loading_complete, load_count = " + this.load_count + ", gr_max = " + this.gr_max);
        if(this.load_count >= this.gr_max) {this.proceed();}
    };

    function start()
    {
        tractor = new Tractor();
    }
    </script>
</head>

<body onload="start();">
</body>

</html>

When it's just called from another function of the object (see #1), it works just as I expected. When, however, it's called from onload event (see #2), the variables become "undefined" or "NaN" or something. What's happening? What am I doing wrong? How do I make it work?

I don't remember ever creating my own objects in Javascript before, so I certainly deeply apologize for this "what's wrong with my code" kind of question. I used this article as a reference, section 1.2, mainly.

Just in case, I put the same code on http://jsfiddle.net/ffJLn/


回答1:


bind the context to the callback:

this.img1.onload = this.loading_complete.bind(this);

See: http://jsfiddle.net/ffJLn/1/ (same as yours but with this addition)

Here's an explanation of how bind works in detail: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind

The basic idea is that it makes this in the bound function equal to whatever you pass as the parameter to bind.

Another option is to create a closure:

var self = this;
this.img1.onload = function() { self.loading_complete() };

Closures are functions that keep references to their context (in fact, all functions in javascript work this way). So here you are creating an anonymous function that keeps a reference to self. So this is another way to maintain context and for loading_complete to have the right this.

See: http://jsfiddle.net/ffJLn/2/ (same as yours but with the second possibility)




回答2:


When #2 gets called, your this has changed. this now refers to the new Image() rather than the Tractor object.

Try changing...

this.img1.onload = this.loading_complete;

to

var that = this;
this.img1.onload = function() { that.loading_complete(); };



回答3:


You can now use es6 arrow functions which provide lexical binding:

this.img1.onload = () => { this.loading_complete(); };



来源:https://stackoverflow.com/questions/9696200/calling-an-object-function-from-onload-event-makes-it-lose-the-context

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!