Now I have a prototype like:
function A() {}
A.prototype.run = function () {
console.log('run 1');
};
Given that I cannot change anything where A is at (no control over the source). I would like to extend the method run. Not only log run 1, also log run 2. I tried several different approaches, it does not work.
A.prototype.run = function () {
this.run.call(this);
console.log('run 2');
}
Or
A.prototype.run = function () {
arguments.callee.call(this);
console.log('run 2');
}
Anyone having a solution for this? I would rather not to copy what's inside the method run. Thanks!
A.prototype._run = A.prototype.run;
A.prototype.run = function () {
this._run.call(this);
console.log('run 2');
}
You can override the run method, saving a reference to it as such;
(function (orig) {
A.prototype.run = function () {
orig.apply(this, arguments);
console.log('run 2');
}
}(A.prototype.run));
This is similar to your first attempt, but preserves the first value of run, so you can effectively do this.run.call(this) as you attempted.
Related
Okay, this is a basic outline of my code
exports.entity = {
name:"Foo",
//Etc...
start:function() {
this.attack();
},
attack:function() {
setTimeout(attack, 1000); //Doesn't work
setTimeout(this.attack, 1000); //Doesn't work
setTimeout(this, 1000); //Doesn't work
}
}
As you can probably see, I would like to call attack() from inside that function using a setTimeout. Unfortunately, everything I've tried doesn't work, and I'm running dry on ideas. I couldn't find anything on the internet. Does anyone know how I can achieve this?
Note:
When I say doesn't work, I mean that it gives me an error saying something like (insert what I tried here, e.g. 'this.attack') is not a function
What I usually do to avoid problems of scope is to split the functions. And then export the object.
const attack = () => {
console.log('attacking');
setTimeout(() => {
stop();
}, 1000)
};
const stop = () => {
console.log('stopping');
}
const start = () => {
attack();
}
module.exports = { start, stop, attack }
Otherwise you can bind(this) as it was suggested in the comments.
setTimeout has own scope that is why It is overriding this
You can use bind or take variable outside setTimeout
//using bind
setTimeout((function() {
this.attack();
}).bind(this));
//using variable
var context = this;
setTimeout(context.attack, 1000);
It can look like this:
let entity = {};
entity.name = "Foo";
// Etc...
entity.start = function() {
this.attack();
}.bind(entity);
entity.attack = function() {
console.log('attack');
setTimeout(this.attack, 1000); //Doesn't work
}.bind(entity);
exports = { entity };
When I define a javascript class with methodes and submethodes this way it works:
function Controller () {
this.OrdersSyncFreq = 3000; //ms
this.syncOrders = function () {};
this.syncOrders.start = function () { console.log("start was called"); };
this.syncOrders.stop = function () { console.log("stop was called"); };
}
But how can I define the function Controller.syncOrders.start() later using "prototype"? Something like this does not work:
Controller.prototype.syncOrders.stop = function () {
console.log("The NEW stop was called");
}
Looking a bit more around, i found out it can be written like this:
function Controller () {
this.OrdersSyncFreq = 3000; //ms
this.syncOrders(); // have to be called at init to make sure the definitions of start and stop will be active.
}
Controller.prototype.syncOrders = function () {
this.syncOrders.start = function () {
console.log("Start was called, frequence is: ",this.OrdersSyncFreq);
}.bind(this); // .bind(this) is needed to have access this of your controller instance
this.syncOrders.stop = function () {
console.log("Stop was called, frequence is: ",this.OrdersSyncFreq);
};
}
// run the code
var app = new Controller();
app.syncOrders.start(); // console: Start was called, frequence is: 3000
app.syncOrders.stop(); // console: Stop was called, frequence is: undefined
The methodes of syncOrders - Start() and Stop() do not need to be prototyped, because syncOrders will not instantiated.
Anyhow I'm not sure if it really make sense to do it like this. I did it only because of the namespacing. may be it is better to use something more simple like syncOrdersStart() and syncOrdersStop() instead.
I have a callback that gets tossed around a lot. I can't figure a way to keep it through all of functions.
function a(callback) {
callback();
}
var number = 0;
function b(callback) {
number++;
c(number, callback);
}
function c(number, callback) {
if (number != 2) {
a(function () {
b();
});
} else {
callback();
}
}
a(function() {
b(function() {
console.log('hi');
});
});
I need a way to get the outermost callback (the one with console.log) to the a() function and subsequently the b() function when I call the a() function in the c() function.
Let me know if this sounds like gibberish. I will try to clarify.
You are encountering a TypeError: undefined is not a function. This is because in c you're invoking b without passing any args so when number !== 2 you've lost your reference
I re-wrote your code and it ended up working
var number = 0;
function invoke(fn) { // do you really need this? just invoke directly
fn();
}
function count(fn) {
++number;
limit(number, fn);
}
function limit(num, fn) {
if (num < 2) // this is much safer
invoke(function () {
count(fn); // passing an arg here
});
else
fn();
}
invoke(function () {
count(function () {
console.log('hello world');
});
});
You're getting dangerously close to what is known as 'callback hell'. You'll want to avoid that if you can. Since I'm not 100% sure why you need to pass around so many callback functions, you can achieve what you're looking for by doing the following:
function increment(number, callback, callback2) {
console.log('Incrementing number ' + number + ' by 1');
number++;
callback(number, increment, callback2);
}
function verify(number, callback, callback2) {
if (number < 2) {
callback(number, verify, callback2);
} else {
callback2();
}
}
var number = 0;
increment(number, verify, function () {
console.log('Hello world!');
});
You'll notice that I renamed some functions and excluded your a() function since it did nothing but execute the callback function passed to it. Unless that function is to serve another purpose, it is useless. You also don't need to create an anonymous function every time you are passing a callback. To pass a previously defined function as a parameter or callback, simply pass the function name without the (). If you are passing an undefined function as a callback, you will need to create the anonymous function which is what is being done with the console.log() callback.
Here's a jsfiddle. You can open your console log and see what it's doing.
jsfiddle
Please also be sure to read up on callback hell and how to design your code in a way that it can be avoided. Call back hell
I have written the following function.
function obj()
{
this.a;
}
obj.prototype.catch = function()
{
alert('Catched')
}
obj.prototype.do = function()
{
alert('called');
}
What i need is, to call obj::catch() after obj::do() is called and the call must be performed from inside obj::do()
So how to pass the local function of obj to setTimeout
i have tried
obj.prototype.do = function()
{
window.setTimeout('"'+this.catch+'()"',1000);
alert('called');
}
It does not worked
Then i tried
obj.prototype.do = function()
{
window.setTimeout('"'+this+'.catch()"',1000);
alert('called');
}
which gave me the following error on Chrome console
Uncaught SyntaxError: Unexpected token ILLEGAL
So i tried the following dirty method(is it really dirty ?)
obj.prototype.do = function()
{
this.pid = randomVal(100);
window['temp'+this.pid] = this;
window.setTimeout("temp"+this.pid+".catch();",1000);
alert('called');
}
function randomVal(bound)//returns a random number between 0 and <bound>
{
return (Math.floor(Math.random()*(bound)));
}
That worked.
so why the first two methods not worked.Is there any other way to do the same thing without global variables..
The second method and last method are almost similar .But why am i gettng the error in second method..?
The worked code can be found here
http://jsfiddle.net/jXhAs/
Don't pass strings to setTimeout … ever.
var self = this; // Because the scope will change
setTimeout(function () { self.catch() },1000);
Or if you are using JS 1.8.5:
setTimeout(this.catch.bind(this),1000);
You can read more about bind
You should pass a function to setTimeout (not a string):
Example:
var self = this;
setTimeout(function(){
self.catch();
},1000);
use a closure
obj.prototype.do = function()
{
window.setTimeout((function(that){
return function(){
that.catch();
};
})(this),1000);
alert('called');
}
Why go through all of this effort, just pass the function.
function obj() {
this.a;
}
obj.prototype.
catch = function() {
alert('Catched')
}
obj.prototype.do = function() {
setTimeout(this.
catch, 1000);
}
var test = new obj();
test.do();
When I start my script I have this:
var my_great_masterpiece = new function ()
{
var self = this;
Then later in my script I have this:
response_xml: function ()
{
if (self.http_request.readyState == 4)
{
if (self.http_request.status == 404 && countXmlUrl <= 3)
{
countXmlUrl++;
self.realXmlUrl = xmlUrl[countXmlUrl];
self.request_xml();
}
if (self.http_request.status == 200)
{
self.xmlDoc = self.http_request.responseXML;
self.storage.setItem('domains_raw_xml', self.http_request.responseText);
self.main.peter_save_data();
self.timervar = setTimeout(function ()
{
// ########### Below line gives the error #############################
self.new_version_show_window();
}, 2000);
}
}
},
new_version_show_window: function ()
{
...
}
the error that I am getting is:
Error: self.new_version_show_window is
not a function
What am I doing wrong?
Thanks!
It is unclear from your code where new_version_show_window is defined. Maybe you could explicitly define it on self:
self.new_version_show_window = function () {
/* ... */
}
instead. Or you could define it in the local namespace and use it directly in the setTimeout call:
self.timervar = setTimeout(function () {
new_version_show_window();
}, 2000);
or simply:
self.timervar = setTimeout(new_version_show_window, 2000);
Because of closure, the variables declared in the outer function is also available in the inner function.
Edit
Thanks for posting the entire code. new_version_show_window is defined on this.main, so you must access it thusly:
self.timervar = setTimeout(function () {
self.main.new_version_show_window();
}, 2000);
It could be that self is a reserved word in JavaScript [1]. This could be causing you some problems so try naming the variable something different to start with.
[1] http://www.quackit.com/javascript/javascript_reserved_words.cfm
This is a problem of scope. new_version_show_window is only in scope in the construct in which is it called ( apparently a jQuery AJAX function of some sort). It will only be available to my_great_masterpiece if you define it outside the limited scope in which it now exists.