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();
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 };
This is the question:
Define a function named print which just print out the parameters it gets.
But it will not print out anything if it's called normally.
Only in a setTimeout callback will become effective.
e.g:
setTimeout(function() {
print('123'); //===> 123
});
print('456'); //===> nothing output
I have one solution but I don't think it's a good way, I rewrite the setTimeout.
I want a better solution curiously.
var print = function() {
'use strict';
var __origSetTimeout = window.setTimeout;
window.setTimeout = function(fn, delay) {
var _fn = new Function(`(${fn.toString().replace(/print\(/g, 'print.call(this,')}).call(this);`);
return __origSetTimeout.call(window, _fn.bind({
isFromSetTimeout: true
}), delay);
};
return function print(word) {
if (!this || !!this && !this.isFromSetTimeout) return;
console.log(word);
};
}.call(null);
You can use scope to solve this, for example
function A(){
let print = function(str){
console.log(str);
}
this.setTimeout = function(){
setTimeout(function(){
print('123');
}, 1000);
}
}
let a = new A();
a.setTimeout();
You could use a monkey patch for an extension of the print function with an additional check for a this object and a property for printing.
// simple function with output
function print(s) {
console.log(s);
}
// apply monkey patch
void function () {
var p = print;
print = function () {
if (this && this.timeout) {
p.apply(this, arguments);
}
}
}();
// bind additional information
setTimeout(print.bind({ timeout: true }, '123'));
print('456');
I want to do something like this:
var build= (function(){
//my function body
})();
function test(){
//somthing then call build
build() //i want to call build function again in my code
}
How can I do this?
I tried this in angular:
var buildRoot = (() => {
$SubNode.get({
TypeID: vendorAdminService.NodeType.Category
}, function(data: vendorAdminService.IGetNodeParameters) {
$scope.ProductTree = data.TreeNodeModelItem;
$scope.AjaxLoading = false;
}, function(err) {
// alert(err)
})
})();
$mdDialog.show(confirm).then(function() {
$Category.Remove(node.ID)
buildRoot
}, function() {
});
but it does not work.
Anybody can guide me??
You need to return a function in your IIFE.
If you IIF is not trivial and has many functionalities you could also consider using Reveal Module Pattern.
var build = (function() {
var f = function() {
console.log('hello');
};
f();
return f;
})();
function test() {
build();
}
test();
Just use a named function.
Your IIFE needs to return a function, for later calling. But then is no need for an anonymous function.
function build() {
//my function body
}
or
var build = function () {
//my function body
};
var build = (function() {
var init = function() {
// magic code
};
return {
init: init
}
}());
function test() {
build.init()
}
test();
You include all your functionalities inside your build object, and you'll be able to call them as soon as you return them from inside that object. This effectively is called the revealing module pattern
For more information, read this
I see that there are missing semi-colons ";"
$mdDialog.show(confirm).then(function() {
$Category.Remove(node.ID);
buildRoot();
}, function() {
});
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.
var Test = (function() {
return {
useSub: function () {
this.Sub.sayHi();
},
init: function () {
$(document).ready(this.useSub);
}
};
})();
Test.Sub = (function () {
return {
sayHi: function () {
alert('hi');
}
};
})();
Test.useSub(); // works
Test.init(); // explodes
Above I am trying to create a Test namespace and add an object Sub to it. I was doing fine until I tried using the object in jQuery. The error is "Uncaught TypeError: Cannot call method 'sayHi' of undefined". If there is a better way to do this, I am open to it.
Edit:
Obviously this was demo code. In my real application the solution that I went with because I think it is the most clear is this one:
var Namespace (function () {
return {
init: function () {
$(document).ready(function() {
Namespace.onReady();
}
},
onReady: function() {
alert('Now I am back in the Namespace scope. Proceed as planned');
}
};
})();
Edit2: All jQuery callbacks seem to require they are used in this manner or else the scoping is screwed up.
I think it is a scope problem. If you do
$(document).ready(this.useSub);
then this.useSub will be executed in the window scope (so inside the function, this refers to the window object) and there doesn't exist a Sub attribute.
Try:
init: function () {
var obj = this;
$(function(){obj.useSub()});
}
For some reason it does not work using $(document).ready(function(){obj.useSub()}); but it works with the $() shortcut.
Here is one way
var Test = {
useSub : function () {
Test.Sub.sayHi();
},
init: function () {
$(document).ready(Test.useSub);
},
Sub: {
sayHi: function () {
alert('hi');
}
}
};
in this line:
$(document).ready(this.useSub);
you're passing a reference to a function and the scope is lost- when the function runs, this no longer means Test.