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" })();
};
};
Related
I have created an object and am attaching a bunch of functions to the object. I am concerned about how the ordering of the functions effects when I can call my functions. In my example below, I must define my functions first before I can use them. My problem with this is that I cannot call init() immediately until I have defined it. Init() will contain a bunch of other functions that it will need to call, which will have to be placed above init(). So in the end, init() will have to be the very last function defined in my object. I believe this is related to Hoisting.
My question is if there is a way for me to call a function before defining it? Is there some sort of way to create a 'placeholder' function like in C?
https://jsfiddle.net/13hdbysh/1/
(function() {
foo = window.foo || {};
//this will not error
foo.helloWorld = function() {
console.log('helloWorld()');
};
foo.helloWorld();
//this will error
foo.init();
foo.init = function() {
console.log('init()');
};
})();
What you're asking deals with how objects store member data. This can be seen in a weird light because of prototypal inheritance. Javascript by default will parse naked functions before they execute.
Example:
(function() {
init();
function init()
{
console.log("Init");
}
)};
This gets muddied when storing behavior as a member to an object. Because prototypal inheritances dynamic functionality you need to declare your members before accessing them. This is Javascript's main difference from traditional OOP languages.
You mentioned, "is there a way to create a 'placeholder' function like in C." You can, but not in the same way. You can assign it to a naked function and assign that to your object. Look in my example, the hello function.
Alternatively you can store the behavior on the prototype of your object and override it when necessary.
Example:
function hello()
{
console.log("Hello my name is "+this.name);
}
(function() {
var something = function(name) {
this.name = name;
};
something.prototype.initTwo = function() {
console.log("My Name is: "+this.name);
};
var thingOne = new something("Thing One");
thingOne.init = "SomeThing";
var thingTwo = new something("Thing Two");
thingTwo.init = function() {
console.log(this.name);
};
thingTwo.initTwo = function() {
console.log("SomethingTwo is Named: "+this.name);
};
thingTwo.hello = hello;
console.log(thingOne.init);
thingTwo.init();
thingOne.initTwo();
thingTwo.initTwo();
thingTwo.hello();
}) ();
Demo: Fiddle
Documentation on objects in javascript.
Try using similar IIFE pattern
(function() {
foo = window.foo || {};
//this will not error
foo.helloWorld = function() {
console.log('helloWorld()');
};
foo.helloWorld();
//this will error
// foo.init();
foo.init = (function _foo() {
console.log('init()');
this.init = _foo;
return this.init
}).call(foo);
foo.init()
})();
jsfiddle https://jsfiddle.net/13hdbysh/2/
I am not sure why would you wanna call it before it is defined but here is how to do it:
foo = window.foo || { init: function() { } };
How about declaring it as a local variable first.
(function() {
foo = window.foo || {};
//this will not error
foo.helloWorld = function() {
console.log('helloWorld()');
};
foo.helloWorld();
var initFunction = function() {
console.log('init()');
};
//this will no longer error
initFunction();
foo.init = initFunction;
})();
Init() will contain a bunch of other functions that it will need to call, which will have to be placed above init().
You are operating under a misapprehension.
A function must be defined before you call it, not before you define another function which will call it later.
Just define all your functions and then start calling them.
(function() {
foo = window.foo || {};
foo.helloWorld = function() {
console.log('helloWorld()');
};
foo.init = function() {
console.log('init()');
};
foo.init();
foo.helloWorld();
})();
As far as hoisting is concerned, function declarations (you only have function expressions) are hoisted, but they create locally scoped variables, not object properties. You would have to assign them to object properties before you could call them as such, and that assignment wouldn't be hoisted.
It's throwing an error because you're calling the method init() before it's declared.
This way will works
foo.init = function() {
console.log('init()');
};
foo.init();
Since foo is an object, you can put those functions into an object so that will be assigned to foo once window.foo is null
(function() {
foo = window.foo || {
helloWorld: function() {
console.log('helloWorld()');
},
init: function() {
console.log('init()');
}
};
//this will not error
foo.helloWorld();
foo.init()
})();
If you have to use var self=this for methods on the prototype object. Will you write var self=this inside each method?
Is there any way to avoid writing var self =this inside all methods?
function Test () {
}
Test.prototype.method1 = function () {
var self = this;
};
Test.prototype.method2 = function () {
var self = this;
};
You only need to create an alias for the this context if you are going to be introducing new contexts with function literals that still need to access the class's this context.
function Test () {}
Test.prototype.method1 = function () {
// This is fine.
this.someProperty = 123;
this.doSomething();
};
Test.prototype.method2 = function () {
var self = this;
var callback = function() {
// The `this` here is no longer the same `this` as outside the function.
self.someProperty = 456;
};
var anotherCallback = function() {
// No reference to the class's `this` needed here.
alert('Boo');
};
this.doAsyncThing(callback);
};
Alternatively, you can use Function.prototype.bind to force a this context:
var callback = function() {
this.someProperty = 456;
}.bind(this);
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)
}
I'm having some trouble in a pretty big body of code I've been writing, and I've boiled it down to this:
var Thing = function(argument){
this.property = argument;
this.obj = {
func: function(){
return this;
}
};
this.func = function(){
return this;
};
};
I need to access this.property inside obj.func(). However, the value of this isn't what I expect it to be:
> var thing = new Thing("value")
> thing.func()
Thing {property: "value", obj: Object, func: function}
> thing.obj.func()
Object {func: function}
When I instantiate an instance called "thing" and call thing.func(), this holds the current instance of Thing, as it should. But when I call thing.obj.func(), it holds the value of thing.obj. What's going on? How do I access that value?
var thing = new Thing('value')
thing.obj.func() // this inside func will be the object before .func, which is thing.obj
One solution is to bind the function to your object:
var Thing = function(argument){
this.property = argument;
this.obj = {
func: function(){
return this;
}.bind(this); // bind it to the current object
};
this.func = function(){
return this;
};
};
Alternatively you could use a closure with a private copy of this:
var Thing = function(argument){
var that = this;
this.property = argument;
this.obj = {
func: function(){
return that;
}
};
this.func = function(){
return this;
};
};
Declare a local variable in the constructor, and assign it the value of this:
var Thing = function(argument){
var theThing = this;
You can then use "theThing" to refer to the constructed object in those functions.
In your existing code, when you call thing.obj.func(), the value of this in the function will indeed be this.obj. That's because the value of this is determined based on the circumstances of the function call. In that case, the reference to the function ("func") is obtained by traversing its property name on the "obj" object. Therefore, the "obj" object is what this references.
That's the way the this context works in Javascript. You'd need to store an intermediate reference to Thing:
var Thing = function(argument){
var self = this;
this.property = argument;
this.obj = {
func: function(){
return self;
}
};
this.func = function(){
return self;
};
};
this refers to the object which owns the function by default, in this case obj. Here is a workaround :
thing.obj.func.call(thing);
var Foo = (function () {
var foo = function() { };
var privateMethod = function(){ };
foo.prototype = {
init: function() {
console.log(this.privateMethod); //undefined
}
};
return foo;
})();
I know that I can access privateMethod directly without using the this pointer. But since I come from the c# world, I would like to use it for readability purposes.
Is there any way to reference my "private methods" using a pointer?
You can't. You can only use this to refer to "public" methods. If you really want to use a something.method notation, you could use:
var Foo = (function () {
var foo = function() { };
var private = {
privateMethod : function(){ };
}
foo.prototype = {
init: function() {
console.log(private.privateMethod);
}
};
return foo;
})();
privateMethod is not specific to each instance of foo. Just reference it without the this. qualifier—although you probably want to log the results of a function call, not the function itself:
console.log(privateMethod());