I've been reading Game Design with HTML5 and JavaScript and it introduced me to objects. So after reading the book and working on the projects I decided to take this new found knowledge and integrate objects in my own projects. So here's my question can or should objects call their own functions? For example:
var someObject = {
start: function() {
check();
},
check: function() {
console.log("Check!");
}
};
someObject.start();
The book did show an example with a timer that does this:
var timer = {
start: function() {
var self = this;
window.setInterval(function(){self.tick();}, 1000);
},
tick: function() {
console.log('tick!');
}
};
In the example with timer object it makes a reference to self in order to call the internal function, so does this mean I should use self to call internal functions or is this the proper way to do this with objects? Or best practices? Thanks in advance.
var someObject = {
start: function() {
var self = this;
self.check();
},
check: function() {
console.log("Check!");
}
};
someObject.start();
JavaScript names are lexically scoped, so whenever a name (variable) is encountered in a script, the JavaScript runtime must search up the scopes from where the function was defined.
At the point of definition, this function:
start: function() {
check();
}
doesn't have access to any check function in its outer scope. Declaring self and binding it to this is a technique used to deal with the (somewhat interesting) intricacies of referring to the current object in JavaScript (because the example code uses window.setInterval).
To reference a function within the current object, it is enough to use this.
var someObject = {
start: function() {
this.check();
},
check: function() {
console.log("Check!");
}
};
It's javascript function context, each time you create a function, you create a new context (scope).
In setInterval() function you create a new scope, so this no longer refer as the same this above:
var self = this;
setInterval(function() {
self.tick();
}, 1000);
You can also manually bind the proper context of your function with bind() (so you don't need self anymore):
setInterval(function() {
this.tick();
}.bind(this), 1000);
More informations:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
http://joshuakehn.com/2011/10/20/Understanding-JavaScript-Context.html
The point of declaring and initializing a variable like "self" is to deal with the fact that the value of this is determined anew upon each function call. When you've got a function nested inside another function, and that inner function needs access to the value of this from the outer context, then this must be preserved in another variable — "self" in your case. (The name of that variable is unimportant of course.)
In your sample code:
var timer = {
start: function() {
var self = this;
window.setInterval(function(){self.tick();}, 1000);
},
tick: function() {
console.log('tick!');
}
};
that function passed in to setInterval() needs to use the value of this from the "start" function. When that interval timer function is called, however, this is set to something else (either the global context or null in "strict" mode). Thus, by saving the value of this in the context where that interval timer function is instantiated, its code can use it to access the timer object.
In your second example, declaring and initializing a "self" variable doesn't hurt anything, but it's unnecessary. Sometimes it's handy however, just to clarify the code, though of course a more meaningful name than "self" would be a good idea.
of course an object can and should call it's own functions, this is the only way to emulate OOP in javascript. I would say that the practice that the book is using, self = this is bad since this can just be used by itself, however in the first example it is used to preserve the value of this which would otherwise be the this of the function itself not the outer class
Related
I have a Javascript class like below:
var MYCLASS = function(elem, data, op) {
var options = {};
var loopForEver = function() {
console.log('I cant stop me');
setTimeout(function() {
loopForEver();
}, 1000);
}
this.init = function() {
loopForEver();
}
}
when I instantiate the class and call init function, then the loop starts and I get the text in my console every 1 second :
var ins = new MYCLASS();
ins.init();
Why when I set the instance to null, the thread does not stop? or any time I create a new instance and assign it to the previous instance name, it increases the calls.
in my production code, I do not have infinite loop, but I do have some business logic. do I need to be worried about performance when I create a new instance?
When you call setTimeout it is not bound by the function that called it. You need to add a property to object called something like timeOutID. As long as the function is still required being used by something like setTimeout it will remain in scope.
var MYCLASS = function(elem, data, op) {
var options = {};
var timeOutID = null;
var loopForEver = function() {
console.log('I cant stop me');
timeOutID = setTimeout(function() {
loopForEver();
}, 1000);
}
this.init = function() {
loopForEver();
}
this.stop = function () {
clearTimeout(timeOutID);
}
}
You have a memory leak.
In other words, memory leaks may occur when objects, which are now unreachable, are still kept in memory because they are being referenced somewhere else in the call stack.
Nullifying the instance doesn't clear from memory other references to that object. See this answer to "Can an object automatically delete itself in javascript once it has achieved its purpose?"
In fact, your setTimeout call is repeatedly creating a new execution context each with its own untouchable Activation object, which are unaffected by assigning the original instance to null.
An excerpt from "Understanding delete" (Perfection Kills by kangax) explains it this way:
When a function is executed, it is said that control enters
execution context…; that code might call a function, with its own execution context; that function could call another function, and so
on and so forth.
Even if function is calling itself recursively, a new execution
context is being entered with every invocation.
…when in Function code, a Variable object is … a so-called Activation
object. Activation object is created every time execution context for
Function code is entered.
Note that Activation object is an internal mechanism and is never
really accessible by program code.
If you want to nullify the instance, you should clean it up first by clearing the timed recursive call using .clearTimeout().
How can a property be assigned during object construction with a value generated asynchronously?
I'm trying to assign a property to an object during construction that needs to be retrieved via AJAX:
//define module prototype
Library.Module = function () {
this.resources = {};
for (var i = 0; i < arguments.length; i++) {
// assume that Library.require makes a request and
// then executes this callback
Library.require(arguments[i], function (resource) {
// ! the problem seems to be that 'this' is undefined
// in the scope of the callback
this.resources[resource.location] = resource;
});
}
};
I think the intention of this code is rather clear - The problem is that this appears to be undefined in the scope of the callback function.
As seen in the following article https://blog.engineyard.com/2015/mastering-this-in-javascript and following discussion in comments, a possible solution would be to store this in a variable higher in the scope to use it in the callback.
Therefore a possible solution could be :
Library.Module = function () {
var _this = this;
_this.resources = {};
for (var i = 0; i < arguments.length; i++) {
// assume that Library.require makes a request and
// then executes this callback
Library.require(arguments[i], function (resource) {
_this.resources[resource.location] = resource;
});
}
};
Useful snippet from the article cited:
Managing this in a callback
And that’s it: those are the four ways to set a function’s this value.
Those four rules are not too hard to remember, but there is a common
pitfall you should know about. I’m talking about callbacks. It’s easy
to be writing a callback and not even know it, like in setTimeout:
setTimeout(function() {
$(‘button’).addClass(‘red’);
}, 1000);
The setTimeout function accepts a callback, but since it’s not using
one of the four rules for setting context, this defaults to the global
window object. That’s fine in the example above, but becomes a bug in
code like this:
$('button').on('click', function() {
setTimeout(function() {
// Uh oh! `this` is the global object!
$(this).addClass('clicked');
}, 1000);
});
We’re expecting $(this) to refer to the button that was clicked, but
it doesn’t, since this defaults to the global window object. One way
to solve this issue is to store our desired value of this in a local
variable and then simply use that variable in a child scope:
$('button').on('click', function() {
var _this = this;
setTimeout(function() {
$(_this).addClass('clicked'); // All better
}, 1000);
});
Of course there are many ways to accomplish the same thing. You could
use .bind(), .call(), or a number of other options. Choose what works
best for each individual situation.
Being new to JavaScript, I came across a feature in JavaScript where we can write function inside a function which looks cool, but I didn't understand any practical use of it and also how to call the child function?
var parent = "global";
function Parent() {
alert(parent);
function child() {
alert("i am child");
}
}
So, in the above example function parent embeds child function, but I'm not sure on the following 2 questions:
What's the practical use of such syntax / functionality?
How to call child function?
I'm not sure anyone actually gave you the simple answer for what you asked. Defining the child() function inside the Parent() function is just defining a "local" function whose scope is limited to only within the Parent() function's code. It's analogous to a local variable that only exists inside a function.
So, when you have this:
function Parent() {
function child() {
alert("i am child");
}
}
You've created a new function named child which can be called from the code inside of the Parent() function like this:
function Parent() {
function child() {
alert("i am child");
}
child();
}
This function is truly local to within the Parent() function and cannot be called from anywhere else. So, this will not work:
function Parent() {
function child() {
alert("i am child");
}
}
child(); // this function will be undefined
The simplest reason for defining a function this way is just to contain where it can be used and to reduce potential name conflicts. If you couldn't define local functions like this, then all functions would have to be global (or methods on some object) and you'd potentially have a giant set of possible name collisions. This way, you can define functions within a scope that they apply to and they don't potentially collide with any other functions defined similarly within their own scope.
When you get into more advanced uses of javascript, the child() function also has access to all of the variables of its parent. So, you can do this:
function Parent() {
var msg = "Hello!";
function child() {
alert(msg);
}
child(); // will put up an alert that says "Hello!"
}
This allows those local functions to share all the variables from the parent context without having to pass them all to the function. This can be particularly useful when using callbacks because it allows the callbacks to have access to a whole context even though the callback was called by some other code. Here's a simple example of a callback having access to some useful state.
function blink(elem, numTimes, duration) {
var timer, visible = true;
// callback function that is called
function handleInterval() {
// toggle visible state
var val = visible ? "hidden" : "visible";
elem.style.visibility = val;
visible = !visible;
--numTimes;
if (numTimes <= 0) {
clearInterval(timer);
}
}
timer = setInterval(handleInterval, duration);
}
Here you notice that the handleInterval() function has access to not only the local variables from the blink() function, but also the arguments passed to it. This allows us to keep some state going for the setInterval() without using global variables. There's also a more advanced thing going on here called a closure. Closure's can be a bit complicated of a concept, but understanding a couple uses is generally fairly simple.
In this case, the blink() function gets called. It's job is to create an interval timer that, when called will toggle the visibility state of the passed in element. After a certain number of blinks, it will stop the interval timer. But, all the blink function does is call the setInterval() function to schedule the interval timer. It then immediately finishes and is done executing. But, because the setInterval() function has been schedule and it has been passed a reference to the handleInterval() function and that function is in the scope of the blink() function, then all the local variables of the blink() function are "kept alive" and operating even though the blink() function has already finished executing. In fact, these variables will be uniquely kept alive until the timer is stopped and nothing can call handleInterval() any more. If javascript didn't have this capability, then a number of variables in this simple solution would have to be declared as global variables or properties of some object that persists for the duration of this activity. This technique allows the code to much cleaner and self-contained.
Local functions don't have to be named. They can also be anonymous. A more typical way to implement blink() would be like this using an inline anonymous function callback instead of giving it a name:
function blink(elem, numTimes, duration) {
var timer, visible = true;
timer = setInterval(function() {
// toggle visible state
var val = visible ? "hidden" : "visible";
elem.style.visibility = val;
visible = !visible;
--numTimes;
if (numTimes <= 0) {
clearInterval(timer);
}
}, duration);
}
If you're only ever calling this function in one place, then it doesn't really need to be declared separately and given a name. It can, instead be defined inline like this as an anonymous function.
This concept is mainly used in OOJS (Object Oriented JavaScript). Consider the example below:
var Employee=function(ename,eage){
var _name=ename;
var _age=eage;
this.getName=function(){return _name;};
this.getAge=function(){return _age;};
};
var e1=new Employee("Xyz",45);
var e2=new Employee("Abc",23);
e1.getName(); //output=Xyz
e1.getAge(); // output=45
and so on ...
It's a closure which is a way to control scope in JavaScript. Anything defined inside the closure is not visible outside the closure. With a small modification to your function you can call it like so:
var parent = "global";
function Parent(a) {
alert(parent);
function child(b) {
alert(a + b); //child can see both a and b
}
return child;
}
parent(1)(2);
This can be used to implement currying which is explained here Javascript curry - what are the practical applications?
I'm currently trying to implement some common JS concepts
in little projects to understand better how to use them.
I've been working on a simple game, trying to
understand and use the module pattern and closures.
I'm using the module pattern from Stoyan Stefanov's 'patterns'
book.
I'm struggling to understand how best to mix modules and
closures.
I'd like to know if I'm organising the following code in a
sensible way? If so, my question is: what's the best way
to modify the code so that in the $(function(){}) I have
access to the update() function?
MYAPP.utilities = (function() {
return {
fn1: function(lives) {
//do stuff
}
}
})();
MYAPP.game = (function() {
//dependencies
utils = MYAPP.utilities
return {
startGame: function() {
//initialisation code
//game state, stored in closure
var lives = 3;
var victoryPoints = 0;
function update(){
utils.fn1(lives);
//do other stuff
}
}
}
})();
$(function(){
MYAPP.game.startGame();
//Want to do this, but it won't work
//because I don't have access to update
$('#button').on('click',MYAPP.game.update)
});
I've come up with a couple of options which would work, but
I'd like to know if they're good practice, and what the best
option is.
Options:
(1) Bind $('#button').on('click', ...) as part of the
startGame initialisation code.
(2) Assign the update() function to a variable, and
return this variable from the startGame function, So in
$(function(){}) we could have
updatefn = MYAPP.game.startGame(); and then
$('#button').on('click',MYAPP.game.update)
(3)? Is there a better way?
Thank you very much for any help,
Robin
First off, to access the update function in that fashion it will have to exposed in the returned object.
return {
update: function() {
[...]
},
startGame: function() {
[...]
this.update();
}
}
Calling obj.method() automatically sets the this reference inside this method call to obj. That is, calling MYAPP.game.startGame() sets this to MYAPP.game inside this startGame method call. More details about this behavior here.
You will also want to move the lives variable to a common scope which is accessible by both startGame and update methods, which is exactly what the closure is for:
MYAPP.game = (function() {
[...]
var lives; //private/privileged var inside the closure, only accessible by
//the returned object's function properties
return {
update: function() {
utils.fn1(lives);
},
startGame: function() {
[...]
lives = 3; //sets the closure scope's lives variable
[...]
this.update();
}
}
})();
Fiddle
In this case you will need some method to set the lives variable when you want to change it. Another way would be to make the lives variable public as well by making it a property of the returned object and accessing it through this.lives inside of the methods.
NOTE: If you simply pass a reference to the function object stored as property of the returned object as in:
$('#button').on('click', MYAPP.game.update);
The this reference inside the click handler will not point to MYAPP.game as the function reference that has been passed will be called directly from the jQuery core instead of as an object's member function call - in this case, this would point to the #button element as jQuery event handlers set the this reference to the element that triggered the handler, as you can see here.
To remedy that you can use Function.bind():
$('#button').on('click', MYAPP.game.update.bind(MYAPP.game));
Or the old function wrapper trick:
$('#button').on('click', function() {
MYAPP.game.update(); //called as method of an obj, sets `this` to MYAPP.game
});
This is important when the this keyword is used inside the update method.
There are a few issues in your code. First, update() function is not visible outside the object your creating on the fly. To make it part of game object it has to be on the same level as startGame.
Also, if you declare var lives = 3 it will be a local variable and it won't be visible outside startGame() function, as well as victoryPoints. These two variable have to be visible in some way (via closure or as object fields).
Finally, attaching MYAPP.game.update as an event listener will attach just that function, preventing you from using all other object methods/functions. Depending on what you want to do you might prefer to pass a closure like function() { MYAPP.game.update() } instead.
Your code should look something like:
MYAPP.utilities = (function() {
return {
fn1: function(lives) {
console.log(lives);
}
}
})();
MYAPP.game = (function() {
//dependencies
utils = MYAPP.utilities
var lives;
var victoryPoints;
return {
startGame: function() {
//initialisation code
//game state, stored in closure
lives = 3;
victoryPoints = 0;
},
update: function() {
utils.fn1(lives);
//do other stuff
}
}
})();
$(function(){
MYAPP.game.startGame();
//Want to do this, but it won't work
//because I don't have access to update
$('#button').on('click', MYAPP.game.update)
});
(DEMO on jsfiddle)
I have some javascript code (within an object) :
toggle: function() {
var me = this;
var handler = function() { me.progress() };
me.intervalId = setInterval(handler, me.intervalTime);
//...More code
}
I'm kind of new to javascript, so doing the above as far as I can tell actually passes the me variable into anonymous the function. I was wanting to see if there is a more declarative way to do so? I wanted something along the line of:
var handler = (function(o) { o.progress();})(this));
but that doesn't seem to be working... Am I missing something? Is this a case where "this is the way the language works so just declare a local variable and deal with it"?
UPDATE:
The source to my problem was/is my unclear understanding of scope and closures in javascript. I found this article to help me understand a little more.
You can use ".bind()":
var handler = function() { this.progress(); }.bind(this);
New browsers have "bind()", and the Mozilla docs have a solid implementation you can use to patch older browsers.
The reason
var handler = (function(o) { o.progress();})(this));
doesn't work because it just immediately calls the anon function, therefore immediately calling o.progress() and assigns the return value of the anon function (undefined) to handler. You need to return an actual function from the outer function:
handler = (function(me){
return function(){
return me.progress();
}
}(this));
On the flip side this is equivalent and just as bad looking as bad looking as the variable assignment (but can still be useful, particularly if this needs to be done in a loop, with the changing i rather than the fixed this).
BTW, if the progress function doesn't have any calls to this inside it , just doing handler = this.progress (without the parens) might suffice.
The anonymous function has access to me because it is declared inside of the outer function (the toggle function); it is closed over by the outer function.
Your handler function will be called by setInterval, which passes exactly zero arguments. This means you can't use parameters in the handler function itself.
I you really want to pass me explicitly, you could write a function accepting an parameter, and have that function return an anonymous function without parameters, but which could access the creator function's parameter:
toggle: function() {
var me = this;
var handler = (function (o) { return function() { o.progress() }; })(me);
me.intervalId = setInterval(handler, me.intervalTime);
//...More code
}
But this basically adds a layer of redirection without really making it more legible. Unless you pull that creating function outside:
function createProgressHandler(o) {
return function() {
o.progress();
};
}
// ...
toggle: function() {
var me = this;
var handler = createProgressHandler(me);
me.intervalId = setInterval(handler, me.intervalTime);
//...More code
}
What you have there is a closure. The function that is created and assigned to handler keeps a reference to the me object. This is normal, everyday JavaScript, and that's the way that closures work generally.
Have you tried to return the function like this?
var handler = function(o){
return function(){
o.progress();
}
}(me);
Now you can call:
handler();