I have in JavaScript class (function) with variable this.foo and function this.bar(), this.bar() I call in interval but have a small problem, JavaScript forgets this.foo and i cant use this.foo in this.bar(). Why?
function Somethink(element) {
this.foo = element;
this.bar = function () {
// And now this.foo is undefined
}
setInterval(this.bar, 1000)
}
It happens because setInterval calls this.bar in context of global object, not in the context of current object. Try to call it in this way:
var self = this;
setInterval(function () { self.bar() }, 1000);
Update
As it has been pointed in comments, another option is to use bind()
setInterval(this.bar.bind(this), 1000);
because this is the window scope when the interval runs. You need to use a closure or bind()
window.setInterval(this.bar.bind(this), 1000);
function Somethink(element) {
var foo = element;
var bar = function () {
}
setInterval(bar, 1000)
}
Use variables instead. 'This' changes context depending where you call it
The behavior is correct. At the time when bar() is called, this might anything. The usual workaround is to assign this to a local variable:
function Somethink(element) {
var that = this; // trick
that.foo = element;
that.bar = function () {
// Use "that" in here
}
setInterval(that.bar, 1000)
}
that will make sure the code keeps a reference to the original value of this.
You can do like this :
function Somethink(element) {
this.foo = element;
this.bar = function () {
// And now this.foo is undefined
}
var self = this
setInterval(self.bar, 1000)
}
Related
Can you please help me to find the error in the code? I need to pass one method's scope to another method.
var obj = {
doIt: function() {
var a = 10;
this.doThat.call(this);
},
doThat: function() {
console.log(a);
}
};
obj.doIt();
If you want to access a in the scope of context, you can try this.
var obj = {
doIt: function() {
this.a = 10;
this.doThat.call(this);
},
doThat: function() {
console.log(this.a);
}
};
obj.doIt();
You do pass the "context" (aka this) around. a however, is not part of the current context, but of the current scope. So you either move a into the context:
var obj = {
doIt: function() {
this.a = 10;
this.doThat();
},
doThat: function() {
console.log(this.a);
}
};
Or you directly pass the value of a into doThat:
//...
this.doThat(a);
doThat(a) { /*...*/ }
You need to understand that there is difference between context and scope. scope is going to be something which will dictate which variables are accessible from a particular site whereas context is what will be the value of this at particular site or inside a function.
so if you want to use value of a in function doThat you need to bind value of a with this which is context in function doIt like: this.a = 10; and then access it using console.log(this.a) inside function doThat
I have read this answer and IIFE but I can't seem to find the correct solution to my problem.
I have a simple class here:
define(['jquery'], function($) {
// Need 'self' because someCallback() is being called with .call() and 'this' changes
var self;
function Foo(number) {
self = this;
this.someNumber = number;
}
Foo.prototype = {
someCallback: function () {
//Use self because 'this' changes to a DOM element
var num = self.someNumber;
//Do something with the num
return num * 2;
}
};
return Foo;
});
and someCallBack() is being called by a jQuery plugin using .call(). Because of this, the context changed, hence the use of the self variable.
However, this is wrong because:
define(['foo'], function(Foo) {
describe('context question', function () {
var foo1 = new Foo(1);
var foo2 = new Foo(2);
it('"this" should work', function () {
var call1 = foo1.someCallback.call(this); // 4
var call2 = foo2.someCallback.call(this); // 4
expect(call2).toBe(4); // Only works because it is 'new' last
expect(call1).toBe(2); // Fails because 'self' is taken from foo2
});
});
});
How exactly should I wrap the self variable to make this code work?
You could probably just use the revealing module pattern and declare it as a "global" variable (local to the module):
define(['jquery'], function($) {
var someNumber;
function Foo(number) {
someNumber = number;
}
Foo.prototype = {
someCallback: function () {
return someNumber * 2;
}
};
return Foo;
});
Two ways of calling an object method which stores its own this value include
Define the method as a nested function which references its this value in a closure which stores this value in a variable. The function defined could be anonymous or declared with a name but must be evaluated each time a class instance is created, so as to create a new Function object capturing different values of self in function scope.
Take a statically defined function object and bind its this value using bind. Bind creates a new wrapper function object each time it is called.
The first method looks like (without Jquery or Jasmine):
function Foo(number)
{ var self = this;
this.num = number;
this.someCallback = function() // method with new Foo object stored as self in function scope
{ // something with num:
return self.num * 2;
}
}
and the second method could look like
function Foo(number)
{ this.num = number
this.someCallback = this.someCallback.bind(this); // bind prototypical method as local method.
}
Foo.prototype = {
someCallback: function () {
// this value is bound by constructor;
//Do something with the num
return this.num * 2;
}
};
I am a little bit confused on how this works, let me post you an example code:
someClass = function() {
this.a = 10;
this.Foo = function() {
console.log(this.a); // will output "10"
setTimeout(this.Bar, 1);
}
this.Bar = function() {
console.log(this.a); // undefined
}
}
var instance = new someClass();
instance.Foo();
My understanding is that this.a is not visible in function Bar if it is called from setTimeout (or some other "handler" type of thing.)
What is the common/correct way of solving that?
(I am trying this in Node.js btw)
Thank you.
The problem is that the scope (this) is lost when you pass a function to setTimeout.
Here's the easiest way to fix it, store this as a reference through a closure and use that instead.
// This uses _me_ everywhere for consistency, but the only place that really needs it
// is within the Bar method. But consistency in this case makes your code more change-
// proof, say if someone calls setTimeout(instance.Foo, 1)
someClass = function() {
var me = this;
me.a = 10;
me.Foo = function() {
console.log(me.a); // will output "10"
// setTimeout will cause me.Bar to be called with window as the context
setTimeout(me.Bar, 1);
}
me.Bar = function() {
// so we avoid using _this_ in here
console.log(me.a); // 10
}
}
A slightly more elegant way is to use Function.bind
someClass = function() {
this.a = 10;
this.Foo = function() {
console.log(this.a); // will output "10"
// the bind call will force it to use the first argument as `this`
setTimeout(this.Bar.bind(this), 1);
}
this.Bar = function() {
console.log(this.a); // undefined
}
}
When passing the function this.Bar as an argument to another function, you need to bind this.Bar to the context you'd like it to be executed with.
If you're using a JS library like jQuery or Underscore.js they already come with that functionality:
setTimeout(_.bind(this.Bar, this), 1);
Here's a simple implementation of a bind function:
var bind = function(scope, fn) {
return function() {
return fn.apply(scope, arguments);
};
}
Update:
As #generalhenry pointed out, node.js already comes with a bind function in (Function.prototype.bind), so you can do this without adding a custom bind function nor an external library:
setTimeout(this.Bar.bind(this), 1);
Suppose I have:
var myfunc = function() {
// do stuff
}
myfunc.foo = function() {
//do other stuff
};
Now myfunc has a property foo that is a function, great. Is there a way to create myfunc from the get-go in this state? That is, I want foo to be defined when myfunc is created. The syntax, I would imagine, is something like:
var myfunc = {
:function() {
// do stuff
},
foo: function() {
// do other stuff
}
}
Except that's wrong.
You can place an anonymous function inside an object, however the only plausible way of doing this is to call the anonymous function when the object is initialised, otherwise the function will never be able to be called - it's anonymous!
Here's a JSFiddle: http://jsfiddle.net/g105b/99K5F/
var myfunc = function() {
this.foo = function() {
console.log("myfunc.foo called!");
};
(function() {
console.log("Anonymous function called.");
})();
};
// Initialising "myfunc" will call the anonymous function.
var instance = new myfunc();
// Now the foo method can be called.
instance.foo();
A little confused as to what functionality you are looking to gain here...
If you want some code to execute when the myfunc is defined, you could use the module pattern:
var myfunc = (function() {
var self = {};
// any initialization code can go here
alert("myfunc init code");
self.somePublicMethod = function () {
}
return self;
}());
This can also be called an immediate function, a function that is defined and executed at the same time.
From within the closure, and code that is not defined as part of another function will be executed when the object is defined, so when you do something like this:
myfunc.somePublicMethod()
the alert would have already been fired.
(This answer written before the first half of the question was significantly revised)
Now myfunc has a property foo that is a function
No, it doesn't.
You called it with myfunc() so this is a reference to the global window object, thus you are creating window.foo.
Possibly what you are looking for is:
function myfunc () {
// do stuff when myfunc is called
}
myfunc.foo = function () {
// do stuff when myfunc.foo is called
};
or perhaps:
function myfunc () {
// do stuff when myfunc is instantiated
this.foo = function () {
// Add a foo property to this when myfunc is instantiated
// ... which is only worth while if you are doing pretty
// ... odd stuff with the variables that are passed in
}
}
var instance = new myfunc();
or maybe:
function myfunc () {
// do stuff when myfunc is instantiated
}
myfunc.prototype.foo = function () {
// Have a foo function on every instance of myfunc
}
var instance = new myfunc();
… but you've abstracted the problem you are trying to solve away in your question, so it is hard to tell what you are actually trying to achieve.
You can use jQuery:
var myFunc = jQuery.extend(
function() { ... },
{
bar: "wioll haven be",
foo: function() { alert(myFunc.bar); }
}
);
myFunc();
myFunc.foo();
This is mostly code acrobatics, this is probably the closest you'll get:
var myfunc;
(myfunc = function(){}).foo = function(){};
There is no practical difference in declaring methods later though, since javascript is single-threaded.
I'm trying to maintain state on an object by doing something like this:
obj = function() {
this.foo = undefined;
this.changeState = function () {
(function () { this.foo = "bar" })(); // This is contrived, but same idea.
};
};
I want to set the instance variable foo to "bar" when I call the changeState method.
For instance:
o = new obj();
o.changeState();
alert(o.foo); // This should say "bar"
As far as I can tell, what is happening is that "this" in the inner anonymous function is pointing to window. I'm not sure what's going on.
Am I on the right track? Is there a better approach?
this topic comes up a lot, but it's hard to serach for since "this" is removed from SO searches.
Basically, in JavaScript, this always refers to the calling object, not the context object. Since here we call o.changeState() from the global scope, this refers to window.
You actually don't need the inner function for the closure to work in this case - the changeState function itself is enough to close a lexical scope.
obj = function()
{
var self = this;
this.foo = undefined;
this.changeState = function()
{
self.foo = "bar";
}
}
Unless you specify a this context when calling a function the default will be the global (which in browsers is window).
Alternatives are:-
obj = function() {
this.foo = undefined;
this.changeState = function () {
(function () { this.foo = "bar" }).call(this); // This is contrived, but same idea.
};
};
or:-
obj = function() {
var self = this;
this.foo = undefined;
this.changeState = function () {
(function () { self.foo = "bar" })(); // This is contrived, but same idea.
};
};
function obj() {
this.foo = undefined;
this.changeState = function () { this.foo = "bar" };
};
var o = new obj();
o.changeState();
alert(o.foo);
works for me. I'm not sure why you would want to use a self-invoking function just to assign a function reference, nor why you use a function expression for your constructor rather than a function declaration.
I figured it out. Just needed to save a reference to the current context and use that in the inner anonymous function:
obj = function() {
this.foo = undefined;
var self = this;
this.changeState = function () {
(function () { self.foo = "bar" })();
};
};