JavaScript "this" references wrong object [duplicate] - javascript

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 7 years ago.
Well, this doesn't really refer to the wrong object, but I do not know how to refer to the correct one.
function someObj() {
this.someMethod1 = function() {
var elementBtn = document.getElementById('myBtn');
elementBtn.onclick = function() {
this.someMethod2(); //I want this.someMethod2() to be called
//...but it tries to call elementBtn.someMethod2() i believe.
};
};
this.someMethod2 = function() {
alert('OK');
};
}
So when my myBtn is clicked I want someObj.someMethod2() to run. And I want it to be that someObj, not any other someObj. But how?!

You might need to make a tweak like this:
function someObj() {
var that = this;
this.someMethod1 = function() {
var elementBtn = document.getElementById('myBtn');
elementBtn.onclick = function() {
that.someMethod2();
};
};
this.someMethod2 = function() {
alert('OK');
};
}
"that" captures the scope you are after.

The function keyword changes scope. One solution is to maintain the reference to the "this" that you want to use.
Try the following:
function someObj() {
var self = this;
this.someMethod1 = function() {
var elementBtn = document.getElementById('myBtn');
elementBtn.onclick = function() {
self.someMethod2(); //NOTE self
};
};
this.someMethod2 = function() {
alert('OK');
};
}

You could use coffee script, which has a fat arrow (used for onclick function) to deal with this kind of thing, and compiles to well formed javascript. By using fat arrow, coffee script ensures the same scope as the function is defined in will be used in the callback function.
play with code here
Coffee Script
someObj = () ->
#someMethod1 = () ->
elementBtn = document.getElementById 'myBtn'
elementBtn.onclick = () =>
#someMethod2()
this.someMethod2 = () ->
alert 'OK'
JavaScript
var someObj;
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
someObj = function() {
this.someMethod1 = function() {
var elementBtn;
elementBtn = document.getElementById('myBtn');
return elementBtn.onclick = __bind(function() {
return this.someMethod2();
}, this);
};
return this.someMethod2 = function() {
return alert('OK');
};
};

Related

Javascript Function Self Invoking Inside Object

Instead using setInterval i can use this, to repeatly call an function.
function foo(){
setTimeout(foo, 1000);
}();
The problem is, i want to do the same thing, inside an object, here the snippet.
var evt;
var init;
evt = function() {
return {
cycle:function(str) {
setTimeout(function(str) {
this.cycle(str);
}, 1000);
}
}
}
init = new evt();
init.cycle("Hallo word");
Then the error shows up, it said
this.cycle() is not a function.
I'm trying to make an variable as this at the above line of my codes, here, like this
var evt;
var init;
evt = function() {
var parent;
parent = this;
return {
cycle:function(str) {
setTimeout(function(str) {
parent.cycle(str);
}, 1000);
}
}
}
init = new evt();
init.cycle("Hallo word");
But still getting.
parent.cycle() is not a function
Is there a way to do this, what i want here is, went i call evt.cycle("Hello World") after first attempt showing Hello World it will repeatly showing Hello World in every next seconds.
I need to keep the function inside the object that generated by that function. Thanks for any correction.
When you return a new object a new scope is defined. So you should bind this pointer to the function. Or you can use .bind(this) function in this way:
setTimeout((function(str){
}).bind(this), 1000)
For more info: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
Or you can use call or apply: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
In es6 you could use ()=>{} (arrow) function, when the this pointer is inherited.
Other working solution:
var evt;
var init;
evt = function() {
var parent;
parent = this;
return {
cycle:function(str) {
var me = this;
setTimeout(function(str) {
console.log("cycle");
me.cycle(str);
}, 1000);
}
}
}
init = new evt();
init.cycle("Hallo word");
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
const evt = function() {
return {
i: 0,
cycle: function(str) {
const _this = this;
setTimeout(() => {
console.log(str.substring(0, this.i));
_this.cycle(str, ++this.i);
}, 1000);
}
}
}
init = new evt();
init.cycle("Hello world");
I extended the example a little bit to illustrate the effect of this a little more.

Get "this" context in a JS "class" method function

I am trying to create a "class" in JS, a simplified structure of which is below:
http://codepen.io/Deka87/pen/WpqYRP?editors=0010
function Alert() {
this.message = "Test alert";
this.document = $(document);
this.document.on('click', function() {
this.show();
}.bind(this));
};
Alert.prototype.show = function() {
setTimeout(function() {
console.log(this.message);
}, 50);
};
var alert = new Alert();
When you click on the document it should show you the this.message contents in console. However, it is now shown as undefined. I believe the problem is that this.messsage can't get the original this context because it is wrapper in another function (setTimeout in my case). Any help would be appreciated!
Here's what worked for me, you get your this.message by referencing self, which is the correct context you need.
function Alert() {
this.message = "Test alert";
this.document = $(document);
this.document.on('click', function() {
this.show();
}.bind(this));
};
Alert.prototype.show = function() {
var self = this;
setTimeout(function() {
console.log(self.message);
}, 50);
};
var alert = new Alert();
You can use arrow functions which will preserve your this context.
function Alert() {
this.message = "Test alert";
this.document = $(document);
this.document.on('click', () => {
this.show();
});
};
Alert.prototype.show = function () {
setTimeout(() => {
console.log(this.message);
}, 50);
};
var alert = new Alert();
Read more: https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Functions_and_function_scope/Arrow_functions.

Call a function whose name is stored in a variable [duplicate]

This question already has answers here:
How to execute a JavaScript function when I have its name as a string
(36 answers)
Closed 7 years ago.
I have the following script:
(function () {
var Module = (function () {
var fctToCall = function () {
alert('Foo');
};
return {
fctToCall: fctToCall
};
})();
var Module2 = (function () {
var init = function () {
var str = 'fctToCall';
Module.str(); // here
};
return {
init: init
};
})();
})();
So I want to call this fctToCall method by its name - how can I do that? So far I know 3 methods:
by attaching the function to the window object, but then it wouldn't be local and in closure, and I wouldn't have the access to other local variables
eval, the best options as far as I see it, but it's still eval, so I don't wanna use it
this, but it's another architecture, I don't wanna change it
How can I solve this?
To call function use
Module[str]();
As Module is an object, you can access the dynamic properties and methods of it by using the bracket notation.
(function() {
var Module = (function() {
var fctToCall = function() {
console.log('Foo');
};
return {
fctToCall: fctToCall
};
})();
var Module2 = (function() {
var init = function() {
var str = 'fctToCall';
// Call as
Module[str]();
};
return {
init: init
};
})();
Module2.init();
})();
Replace:
var init = function () {
var str = 'fctToCall';
Module.str(); // here
};
With:
var init = function () {
var str = 'fctToCall';
Module[str](); // here
};
Here, str is used as key to access the fctToCall function on Module.
Then you can call Module2.init(), in your IIFE:
(function() {
var Module = (function() {
var fctToCall = function() {
document.write('Foo'); // (alert is broken in snippets)
};
return {
fctToCall: fctToCall
};
})();
var Module2 = (function() {
var init = function() {
var str = 'fctToCall';
Module[str](); // Access & call `fctToCall`.
};
return {
init: init
};
})();
Module2.init(); // Call `init`.
})();
Since everything in JS is object you can use the object notation.
Module[str]();
You can just invoke the function like this:
Module[str]();

Function is undefined in JS object

I create object var myObj = new functon () {...}.
In that object i add functions like :
var myObj = new function () {
this.func1 = function() {
func2();
}
this.func2 = function() {
...
}
}
As you can see in func1 I try to call func2 but it is always undefined. Why? Cause everything is in one object.
Change your scripts to
var myObj = function () {
var self = this;
this.func1 = function () {
self.func2();
};
this.func2 = function () {
...
};
};
On top of solutions provided by others. If you are going to call a javascript function that is defined like this
var func = function(){}
the function definition needs to come before the function call.
In the other way of defining a function this does not matter.
function func(){}
So Overall Code should be
var myObj = function(){
this.func2 = function(){
...
}
this.func1 = function(){
func2();
}
}
It's undefined because you don't have local variable func2. So correct reference should be this.func2().
However even in this case your code is not ideal construction object like this (mixing constructor and anonymous function) (although correct). In this case it's better to use object literal in the first place rather then create constructor function for just creating one single object instance:
var myObj = {
func1: function () {
this.func2();
},
func2: function () {}
};
You should call func2 like this
var myObj = new function () {
this.func1 = function () {
this.func2();
}
this.func2 = function () {
console.log('func2');
}
}
myObj.func1();
if you want call func2 with this. and without, you can do it like this
var myObj = new function () {
function func2() {
console.log('func2');
}
this.func1 = function() {
this.func2();
func2();
}
this.func2 = func2;
}
myObj.func1();
you can call like this.
Calling func2() directly, searches the function of window object.
var myObj = functon(){
var current = this;
this.func1 = function(){
current.func2();
}
this.func2 = function(){
...
}
};

Public function in Singleton calling itself

I'm trying to use a singleton pattern but I am having trouble with implementing a recursive public function.
var singleton = (function(){
var self = this;
function privateFunc(){
console.log('I can only be accessed from within!');
}
return{
publicFunc: function(){
//More stuff here
setTimeout(self.publicFunc, 1000);
}
}
})();
I am calling it with singleton.publicFunc
I get this error Uncaught TypeError: Cannot call method 'publicFunc' of undefined.
My understanding is var self is actually the Window object in this instance, so I have to pass singleton.publicFunc as the callback for this to work, but it doesn't seem very "DRY" (Don't repeat yourself). Is there
a better way to accomplish this while using a singleton?
With API calls
var wikiAPI = (function(){
var self = this;
return {
getRandomArticle : function() {
return $.getJSON("http://en.wikipedia.org/w/api.php?action=query&generator=random&grnnamespace=0&prop=extracts&exintro=&format=json&callback=?", function (data) {
});
},
fireAPICalls : function() {
self.getRandomArticle().done(function(data) {
for(var id in data.query.pages) {
this.data = data.query.pages[id];
}
console.log(this.data);
setTimeout(self.fireAPICalls, 1000);
});
}
}
})();
You can use a named function expression like so:
var singleton = (function(){
var self = this;
function privateFunc(){
console.log('I can only be accessed from within!');
}
return{
publicFunc: function nameVisibleOnlyInsideThisFunction(){
//^-------------------------------^
//More stuff here
setTimeout(nameVisibleOnlyInsideThisFunction, 1000);
}
}
})();
I just saw your edit. What would help is having a reference to the functions you are trying to call. So how about something like this:
var wikiAPI = (function(){
var self = this;
var randomArticle = function() {
return $.getJSON("http://en.wikipedia.org/w/api.php?action=query&generator=random&grnnamespace=0&prop=extracts&exintro=&format=json&callback=?", function (data) {
});
};
var repeatFunc = function fireApi() {
randomArticle().done(function(data) {
for(var id in data.query.pages) {
this.data = data.query.pages[id];
}
console.log(this.data);
setTimeout(fireApi, 1000);
});
};
return {
getRandomArticle : randomArticle,
fireAPICalls : repeatFunc
}
})();
Use bind in the setTimeout() to bind the function to the right scope:
publicFunc: function() {
setTimeout(this.publicFunc.bind(this), 1000);
}
Demo: http://jsfiddle.net/te3Ru/
You can't use this in a IIFE. If you want to use this properly you need to create an object/instance of a function, like so:
var singleton = (function () {
// allow to omit "new" when declaring an object
if (!(this instanceof singleton)) return new singleton();
var self = this, // self now points to "this"
privateFunc = function () {
console.log('I can only be accessed from within!');
};
this.publicFunc = function() {
console.log(this); // this now points to the correct object
setTimeout(function () {
self.publicFunc.call(self); // call function in the "self" scope
}, 1000);
};
return this;
});
singleton().publicFunc();
it's not much of a singleton now, but you can have the closest thing to private and public that javascript has!

Categories

Resources