Function is undefined in JS object - javascript

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(){
...
}
};

Related

How to call a function from `setInterval`?

function Obj() {
this.func1 = function() {
this.func2();
},
this.func2 = function() {
setInterval(function() {
this.func2();
}, 200);
}
}
function main() {
var obj = new Obj();
obj.func1();
}
main();
I have the following exception:
this.func2(); ^ TypeError: this.func2 is not a function
at Timeout._onTimeout(C: \Users\ Admin\ Desktop\ CANVAS\ test.js: 15: 12)
at ontimeout(timers.js: 365: 14)
at tryOnTimeout(timers.js: 237: 5)
at Timer.listOnTimeout(timers.js: 207: 5)
Why this.func2 is function when I call without setInterval and is not a function when I call from setInterval?
Cause this is not referring to Obj in your case. That context has been changed and this is referring to setInterval context.
NOte the line var self = this;, which storing this for later usage.
This should work
function Obj() {
this.func1 = function() {
this.func2();
},
this.func2 = function() {
setInterval(function(){
self.func2();
}, 200);
}
}
function main() {
var obj = new Obj();
obj.func1();
}
main();
Maybe you wanted to do something like this:
function Obj() {
this.func1 = function() {
this.func2();
},
this.func2 = function() {
setInterval(function(){
this.func2();
}.bind(this), 200);
}
}
But this will soon lead to an overflow, because you create a new interval on each execution. Maybe you wanted to use setTimeout?
You can bind this
this.func2 = function() {
setInterval(function() {
this.func2();
}.bind(this), 200);
}
DEMO
The problem is the context inside of setTimeout is the top-level, not the context of your object, so this will point to window (in a browser) instead of your object. There are a couple of ways to solve the problem.
The most recent version is to use the bind method to bind the context of your function.
function Obj() {
this.func1 = function() {
this.func2();
},
this.func2 = function() {
console.log('hi');
setTimeout(this.func2.bind(this), 1000);
}
}
function main() {
var obj = new Obj();
obj.func1();
}
main();
Notice that I use this.func2.bind(this) as the callback for setTimeout (same for setInterval, just your example would be quite spammy if I left it with that). That means that no matter where it's called, it's this will always be your object.
The slightly older way to do it is to wrap it up in self-calling function that'll isolate it to a scope that has this set to your object.
function Obj() {
this.func1 = function() {
this.func2();
},
this.func2 = function() {
console.log('hi');
setTimeout((function(self){
return function () {
self.func2();
}
})(this), 1000);
}
}
function main() {
var obj = new Obj();
obj.func1();
}
main();
This way is a bit more involved, but basically I just wrapped what you originally had in a self-calling function that passes in this as a parameter for self, then I use self.func2() inside of it.
this is not passed to your setInterval callback because it is always called in the global context, just like when you use setTimeout.
this is either undefined (in 'use strict' mode) or the window object (in regular/loose mode). You can pass extra arguments to setInterval, though, and these are passed on to your callback:
this.func2 = function() {
setInterval(function(self) {
self.func2()
}, 200, this)
}
Demo Snippet
function Obj() {
this.func1 = function() {
this.func2()
}
this.func2 = function() {
setInterval(function(self) {
console.log(typeof self.func2) //=> 'function'
}, 200, this)
}
}
function main() {
var obj = new Obj()
obj.func1()
}
main()
Use arrow function:
this.func2 = function() {
setInterval(() => { this.func2(); }, 200);
}

JavaScript function after object is created

I have a context function type that is defined as below:
var Context = function () {
this.run = function () {
method1();
method2();
}
var method1 = function () {
}
}
As it is clear in the definition, method2 is not defined in the context. I need every instance of Context passes its implementation of this method.
var c = new Context();
// This does not work! because the call in run() function
// is not this.method2();
c.method2 = function () {
alert("injected method2");
};
c.run();
I need to keep method2() in run without use of this object i.e. this.method2();
Any solution?
If you can define method2 before creating Context it will work no problem:
function method2() {
alert(2);
}
var c = new Context();
c.run();
You can add method2 to the window object instead of the c object, in which case it will work.
Note that this is a clear indicator of poor design. You should probably look into doing this differently.
Callback approach:
var Context = function (callback) {
this.run = function () {
method1();
if(callback) callback();
}
var method1 = function () {
}
}
var c = new Context(function () {
alert("injected method2");
});
c.run();
If you change your run method to the following it should work as expected
this.run = function () {
method1();
this.method2();
}
UPDATE: I just realized it looks like you want to be able to do this on all instances of Context objects. In that case you would also need to define method2 on Context.prototype and not just on c
Context.prototype.method2 = function () {
console.log("injected method2dfd");
};

Retrieve origina context from callback

I have a JavaScript class with two methods like this.
var MyObject = function () {};
MyObject.prototype = {
open: function () {
var self = this;
console.log(self);
$('#a').click('', self.other);
},
other: function () {
console.log(this);
}
};
var myobject = new MyObject;
myobject.open();
In the console.log in the other function, this is the HTML node that the event listens to and not the MyObject object as in the open function.
How can I retrieve the MyObject object from the function other when used as a callback?
You can use $.proxy passing the this context as 2nd parameter:
var MyObject = function () {};
MyObject.prototype = {
open: function () {
$('#a').click($.proxy(this.other, this));
},
other: function () {
console.log(this);
}
};
var myobject = new MyObject;
myobject.open();
When clicking on #a the MyObject.other() function will be called with a this instance referring to MyObject.
JSFIddle with code in action
You could pass this into the eventData parameter of .click.
MyObject.prototype = {
open: function () {
var self = this;
console.log(self);
$('#a').click(self, self.other);
},
other: function (event) {
console.log(event.data); // should output your object
}
};
The reason you're seeing your html object went logging this in other is because other is being run under the context of the .click callback and this is referring to it's caller --> the html object.

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!

avoid needing to declare 'var me = this' for javascript prototype functions

Currently, I create objects in javascript by declaring a construction (regular function) then add methods to the prototype like so
function Test(){
}
Test.prototype.test1 = function(){
var me = this;
}
However, I would like to avoid having to declare var me = this at the top of every function. The following seems to work, but seems like it would be very inefficient:
$(document).ready(function(){
var n = 0;
(function(){
function createTest(){
var me;
function Test(){
this.n = n;
this.testArr = [1, 2, 3, 4];
n++;
}
Test.prototype.test1 = function(){
me.test2();
};
Test.prototype.test2 = function(){
alert(me.n);
$.getJSON('test.php', {}, function(reply)
//want to be able to use 'me' here
me.newField = reply;
});
};
var t = new Test();
me = t;
return t;
}
window['createTest'] = createTest;
})();
var t = createTest();
t.test1();
var t2 = createTest();
t2.test1();
t.test1();
});
This code outputs the expected, but is it actually as inefficient as it looks (the Test object being re-declared every time you call createTest())?
Anyhoo, this would seem a bit hacky... is there a completely different way to do this that is better?
EDIT: The real reason I would like to do this is so that callbacks like the one in test2 will have references to the correct this.
What you can do is bind the current this value to a function and store a copy somewhere. (For the sake of efficiency.)
if (!Function.prototype.bind) {
// Most modern browsers will have this built-in but just in case.
Function.prototype.bind = function (obj) {
var slice = [].slice,
args = slice.call(arguments, 1),
self = this,
nop = function () { },
bound = function () {
return self.apply(this instanceof nop ? this : (obj || {}),
args.concat(slice.call(arguments)));
};
nop.prototype = self.prototype;
bound.prototype = new nop();
return bound;
};
}
function Test(n) {
this.n = n;
this.callback = (function () {
alert(this.n);
}).bind(this)
}
Test.prototype.test1 = function () {
this.test2();
}
Test.prototype.test2 = function () {
doSomething(this.callback);
}
function doSomething(callback) {
callback();
}
var t = new Test(2);
t.test1();
I realize your question was not tagged with jQuery, but you are using it in your example, so my solution also utilizes jQuery.
I sometimes use the $.proxy function to avoid callback context. Look at this simple jsfiddle example. Source below.
function Test(){
this.bind();
}
Test.prototype.bind = function(){
$('input').bind('change', $.proxy(this.change, this));
// you could use $.proxy on anonymous functions also (as in your $.getJSON example)
}
Test.prototype.change = function(event){
// currentField must be set from e.target
// because this is `Test` instance
console.log(this instanceof Test); // true
console.log(event.target == $('input')[0]); // true
this.currentField = event.target; // set new field
};
function createTest(){
return new Test();
}
$(function(){ // ready callback calls test factory
var t1 = createTest();
});
Most of the time, I just declare a local variable that references this, wherever I need a reference to this in a callback:
function Foo() {
}
Foo.prototype.bar = function() {
var that=this;
setTimeout(function() {
that.something="This goes to the right object";
}, 5000);
}
Alternatively, you can use bind() like this:
Function Foo() {
this.bar = this.bar.bind(this);
// ... repeated for each function ...
}
Foo.prototype.bar = function() {
}
What this gives you is that every time you create a new Foo instance, the methods are bound to the current instance, so you can use them as callback functions for setTimeout() et al.

Categories

Resources