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_plete(); // #1 test call, works OK
this.img1 = new Image();
this.img1.onload = this.loading_plete; // #2 gets called, but gr_max = undefined, load_count = NaN
this.img1.src = ".gif"; //just a test image
}
Tractor.prototype.loading_plete = function()
{
this.load_count += 1;
alert("this.loading_plete, 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 bee "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 /
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_plete(); // #1 test call, works OK
this.img1 = new Image();
this.img1.onload = this.loading_plete; // #2 gets called, but gr_max = undefined, load_count = NaN
this.img1.src = "http://dl.dropbox./u/217824/tmp/rearwheel.gif"; //just a test image
}
Tractor.prototype.loading_plete = function()
{
this.load_count += 1;
alert("this.loading_plete, 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 bee "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/ffJLn/
Share Improve this question edited Apr 22, 2014 at 20:54 Ben Lee 53.3k15 gold badges128 silver badges146 bronze badges asked Mar 14, 2012 at 5:01 HeadcrabHeadcrab 7,1138 gold badges43 silver badges46 bronze badges3 Answers
Reset to default 10bind
the context to the callback:
this.img1.onload = this.loading_plete.bind(this);
See: http://jsfiddle/ffJLn/1/ (same as yours but with this addition)
Here's an explanation of how bind
works in detail: https://developer.mozilla/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_plete() };
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_plete
to have the right this
.
See: http://jsfiddle/ffJLn/2/ (same as yours but with the second possibility)
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_plete;
to
var that = this;
this.img1.onload = function() { that.loading_plete(); };
You can now use es6 arrow functions which provide lexical binding:
this.img1.onload = () => { this.loading_plete(); };