javascript variable scope in callbacks - javascript

I'm curious how could this be written better:
function Klass(variable) {
this.variable = variable;
this.callAjax = function() {
$.get('/url', { }, function(json) {
console.log(variable); //! <-- shows undefined
}, "json");
}
}
so I create a local variable: _variable
function Klass(variable) {
this.variable = variable;
this.callAjax = function() {
var _variable = this.variable;
$.get('/url', { }, function(json) {
console.log(_variable); //! <-- its ok
}, "json");
}
}
and its fine, but I really don't this solutions,
Does someone of you have a better code?

That's quite the way.
function(json){console.log(_variable);}
forms a closure with "_variable".
"_variable" keeps the original value forever.
If your "variable" should be updated later, and you want the updated "variable"
You define
var self = this;
and call self.variable to get it.
In this way you'll get the updated "variable" each time the callback is executed.
The complete code:
function Klass(variable) {
var self = this;
this.variable = variable;
this.callAjax = function() {
$.get('/url', { }, function(json) {
console.log(self.variable);
}, "json");
}
}

Related

Javascript OOP literal access variable inside method

i have a problem accessing variable inside method in OOP.
this is my code :
var slideshow = {
elSet : $(".slideshow"),
next : function() {
},
swipe : function() {
var clear = this.autorun().loop;
onSwipe(function() {
clearInterval(clear); // not working
});
},
autorun : function() {
var self = this;
var loop = setInterval(function() {
self.next();
}, 5000);
},
initial : function() {
this.swipe();
this.autorun();
}
}
slideshow.initial();
i want to clearInterval from variable loop,
on browser console return error TypeError: this.loop(...) is undefined
what's wrong with my code?
Just assign the interval id returned by setInterval to a variable you can access, or like Barmar's answer return it.
var slideshow = {
elSet: $(".slideshow"),
next: function() {
},
swipe: function() {
var self = this;
onSwipe(function() {
//use the interval id to cancel
clearInterval(self.intervalRef);
});
},
// variable to store the interval id
intervalRef: null,
autorun: function() {
var self = this;
//assign the interval id generated by setInterval to a variable you can access
this.intervalRef = setInterval(function() {
self.next();
}, 5000);
},
initial: function() {
this.swipe();
this.autorun();
}
}
slideshow.initial();
Issues:
var clear = this.autorun().loop; Here this will have scope swipe and not object.
var loop = setInterval(function() {}) Here loop will have scope of autorun and will expire after function execution is over.
You can try something like this:
JSFiddle
function SlideShow() {
// self will hold current object reference for all functions
var self = this;
var interval = null;
function next() {
console.log('next');
}
function swipe() {
onSwipe(function() {
console.log("Clearint Interval")
clearInterval(interval);
});
}
// Private function
function onSwipe(callback) {
console.log("On Swipe");
// Check if value is passed and its a function
if (callback && typeof(callback) === 'function')
callback();
}
function loop() {
interval = setInterval(function() {
next();
}, 5000);
}
function init() {
swipe();
loop();
}
// Public properties
return {
elSet: $(".slideshow"),
next: next,
swipe: swipe,
loop: loop,
initial: init,
interval: interval
}
}
// Create a new instance of SlideShow
var slideshow = new SlideShow();
slideshow.initial();
In the swipe function, you have:
var clear = this.autorun().loop;
This expects this.autorun() to return an object, and tries to access the loop property of that object, which should contain the ID of an interval function. But autorun doesn't return anything, let alone an object with a loop property.
Change autorun to:
autorun : function() {
var self = this;
var loop = setInterval(function() {
self.next();
}, 5000);
return loop;
}
Then you can do:
var clear = this.autorun();
You also shouldn't call this.autorun() in the initial function. It's already called by this.swipe(). Running it again will cause two interval functions to run, and the ID of the second one isn't saved anywhere so that you can clear it.

why can't i call one method from another inside an object

pardon my javascript ignorance: Why can't i do something like this in javascript? Running this tells me that theCalled is not defined. the order of the functions doesn't matter of course.
var myObj = {
theCaller: function() {
console.log('The Caller');
theCalled();
},
theCalled: function() {
console.log("i was called");
}
}
myObj.theCaller();
Add "this" before you call .theCalled()
var myObj = {
theCaller: function() {
alert('The Caller');
this.theCalled();
},
theCalled: function() {
alert("i was called");
}
}
myObj.theCaller();

JSHint: Why is the value of this local variable never read?

JSHint is telling me that the value of local variable isInitOk is never read. But it is updated only if a $get success function runs and exposed with a method.
var my = function () {
var isInitOk = false;
function discoverSuccess(rsp) {
...
isInitOk = true;
}
function init() {
...
$.get(config.serverURL, discoverSuccess, 'json');
}
function assertInitOk() {
return isInitOk;
}
return {
assertInitOk: assertInitOk
};
}();
#cookiemonster is correct, this is a bug in the Eclipse plugin unfortunately:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=351470

Pass this to callback

I know what the problem is but not sure what's the best option to solve this issue. I have got a callback and I'm not able to access this from it. I don't want to have any variable outside the scope to refer this. Can I pass this as a parameter?
var myModule = Module.create({
init: function() {
ws.subscribe('/topic/notifications', this._wsNotifications, headers);
},
refresh: function() {
},
_wsNotifications: function ( message ) {
this.refresh(); //Error: 'this' is undefined because it's a callback
}
});
One way you can solve this is using function.bind at the source When you specify the callback do
ws.subscribe('/topic/notifications', this._wsNotifications.bind(this), headers);
or cache the this to a variable.
var myModule = Module.create({
self : this,
init: function() {
ws.subscribe('/topic/notifications', this._wsNotifications, headers);
},
refresh: function() {
},
_wsNotifications: function ( message ) {
self.refresh(); //Error: 'this' is undefined because it's a callback
}
});
Give this a try.
var myModule = Module.create({
var self = this;
init: function() {
ws.subscribe('/topic/notifications', this._wsNotifications, headers);
},
refresh: function() {
},
_wsNotifications: function ( message ) {
self.refresh(); //Error: 'this' is undefined because it's a callback
}
});
return interactions;
});
note the creation and use of the self variable instead of the this variable. Using this method will preserve this, even when it would normally change scope.
You can make use of ECMAscript's bind function Function.prototype.bind.
init: function() {
ws.subscribe('/topic/notifications', this._wsNotifications.bind(this), headers);
},
Now, this within _wsNotifications will refer to the object you bound it to.

Passing local functions to setTimeout()

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();​

Categories