Reputation: 3120
window.onerror = function(e){alert(e)};
function main(){
this.work = [];
this.start_working = function() {
try{
if(this.work.length > 0){
var y = this.work.shift();
y.func(y.args);
}
}
catch(e){alert(e)};
};
this.add_work = function(f, a){
this.work.push({func:f, args:a});
};
this.foo = function(){
function footoo(){alert("bar");}
this.add_work(footoo);
};
this.foothree = function(){
this.add_work(this.foo);
};
this.start = function(){
setInterval(function(){this.start_working();}.bind(this), 1);
};
};
x = new main();
x.start();
x.foothree();
This is the watered down version of a function I am using elsewhere to run animations sequentially.
Expected behavior:
this.foothree
is processed by the interval adding foo to the interval. this.foo
is then processed adding footoo
to the interval which is finally processed alerting "bar".
Problem:
when this.foothree
is processed, an error is thrown:
TypeError: this.add_work is not a function.
Why don't I use something simpler:
Basically I need a function which allows me to compose a more complex animation made of simpler animations to the queue to be processed so I can reuse that animation. Foothree
in this instance is just simulating a call which would add the real animation, footoo
, to the queue to be processed. Footoo
would be composed of simpler animations, foo
, which would be executed sequentially.
Upvotes: 2
Views: 54
Reputation: 2115
this
returns the [[ThisValue]]
property of the EnvironmentRecord
of the LexicalEnvironment
of the ExecutionContext
of the running function (see the spec).
Its value depends on how the function is called. If you call
this.foo = function(){
function footoo(){alert("bar");}
this.add_work(footoo);
};
in the function being declared there is no add_work
method.
You should adopt var _self = this;
pattern in order to point the correct calling context.
Basically the code should be rewritten as follows:
function main(){
var _self = this;
this.work = [];
this.start_working = function() {
try{
if(_self.work.length > 0){
var y = _self.work.shift();
y.func(y.args);
}
}
catch(e){alert(e)};
};
this.add_work = function(f, a){
_self.work.push({func:f, args:a});
};
this.foo = function(){
function footoo(){alert("bar");}
_self.add_work(footoo);
};
this.foothree = function(){
_self.add_work(_self.foo);
};
this.start = function(){
setInterval(function(){_self.start_working();}, 1);
};
};
Edit:
removed .bind(this)
from original code.
Upvotes: 5
Reputation: 55769
This question has two components.
First it is a question about this
in JavaScript aka the "target" or "receiver" of a function.
The target of a function in JavaScript depends on whether you are in strict mode, how the function was called and whether it was bound using bind
.
Assuming strict mode (you should always put 'use strict';
at the top of your JavaScript):
foo(); // this inside foo will be undefined
a.foo(); // this inside foo will be a
a.foo.call(o); // this inside foo will be o
a.foo.apply(o); // this inside foo will be o
a.foo.bind(o)(); // this inside foo will be o
The second aspect to this question is what the author is attempting to do. I am pretty sure the complexity he is introducing to chain animations is unnecessary, and that he should be using requestAnimationFrame
, but discussion of this would require another question.
Example:
function foo() {
document.write('foo', this, '<br/>');
bar();
}
function bar() {
document.write('bar', this, '<br/>');
}
foo();
document.write('------<br/>');
foo.call({});
Upvotes: 1