I am confused regarding how to work with this in combination with bind. I know the problem stems from this being the global object. Could somebody explain how I could circumvent?
In the constructor I have done this:
var BoundedStartTimer = this.StartTimer.bind(this);
var BoundedStopTimer = this.StopTimer.bind(this);
var BoundedClearTimeString = this.ClearTimeString.bind(this);
BoundedClearTimeString();
The last one works, but the timer does not start when I call BoundedStartTimer();.
I am not sure what I am doing. Below are my declarations:
MemoryGame.prototype.StartTimer = function(){
var playTimeInMilliseconds = 0;
this.timeString = "";
this.timer = window.setInterval(function(){
if(playTimeInMilliseconds >= 1000)
this.timeString = .....
this.handleToTimerText.textContent = this.timeString;
}, 10);
}
MemoryGame.prototype.StopTimer = function(){
clearInterval(this.timer);
}
MemoryGame.prototype.ClearTimeString = function(){
this.handleToTimerText.textContent = "00:000";
}
The issue here is with your setInterval call. setInterval executes functions in the global scope, meaning that this === window which is not ideal. You were right that bind can work here though, just bind the interval callback to this:
window.setInterval(function(){
if(playTimeInMilliseconds >= 1000)
this.timeString = .....
this.handleToTimerText.textContent = this.timeString;
}.bind(this), 10);
// ^ bind this from your MemoryGame instance to the interval callback
So here's the deal.
Every time you see the keyword function, you should think two things.
First is, "oh, this creates a new scope for variables!" Lots of people from Java think this happens with each curly brace { that is not used as an object literal; that's false, it's only a function context (or, now with ES6, there is let and => that do it too.)
The second thing you should think is, "oh, probably this and arguments are going to be different in the new variable scope." That's because these two keywords are especially "magical" in JavaScript.
So when you write:
this.timer = window.setInterval(function () {
if (playTimeInMilliseconds >= 1000) {
this.timeString = .....
}
this.handleToTimerText.textContent = this.timeString;
}, 10);
...you have to see that function as a new variable scope with its own this and arguments.
Now, playTimeInMilliseconds is going to be fine if you don't at any point in this function write var playTimeInMilliseconds, which will get "hoisted" to the top of the function declaration and declare a new variable local to that scope. As long as you never do this, playTimeInMilliseconds will peek at the parent variable scope and find the variable you defined in the outer scope.
However, this.timeString and this.handleToTimerText are not fine because the value of this was declared to be window.
There are two remedial approaches:
In the outer function, capture this into your own variable. Common variable names for this purpose are are me and self. Just write var self = this; in the outer function, then do not write var self in the inner function, then write self.timeString and self.handleToTimerText.
Take the function and explicitly .bind() it. So pull out the function like so:
function updateTimerText() {
if (playTimeInMilliseconds >= 1000) {
this.timeString = .....
}
this.handleToTimerText.textContent = this.timeString;
}
this.timer = setInterval(updateTimerText.bind(this), 10);
Obviously, bind has a lot of power! So don't do crap like this:
var BoundedStartTimer = this.StartTimer.bind(this);
var BoundedStopTimer = this.StopTimer.bind(this);
var BoundedClearTimeString = this.ClearTimeString.bind(this);
BoundedClearTimeString();
I have no idea what scope this stuff is occurring in, but it's probably not in the right scope. Because whatever you're binding as this has to be the instance of new MemoryGame() that you created -- maybe let's say you called it var myMemoryGame = new MemoryGame(); or so; just use myMemoryGame.startTimer() (or whatever) and let the this come naturally. Whenever you write a.b.c.d.e() the this in the context of function e() is magically set to a.b.c.d. Don't reassign it to this unless you know what the heck you're doing and that you have to preserve this in some new context. At the very least be nice to readers and .bind(myMemoryGame) so that it's 100% clear.
Related
I have a library which has defined a class as this. I would like to call getMe() function outside class A with my own me.
var me;
var A = function(_me){
me = _me;
}
A.prototype.getMe = function(){
me();
}
I have class B where I call it like
A.prototype.getMe.call(this) but this would throw an error as me is not defined. How can I pass me into this ? I would like to make minimum changes to getMe function.
The only way to do this is, I guess to use an if .
A.prototype.getMe = function(){
if(!me){
me = this.myMe
}
me();
}
So I did A.prototype.getMe.call({myMe: myMe}, args) but would it define the variable in global space ?
You can't reasonably do this, not least because A is fundamentally broken (see below).
Whether you can do it at all depends entirely on where the A code is: If it's at global scope, you can do what you want but shouldn't. If it isn't at global scope, you can only do it from code within the scope where me is declared (or a scope within it).
If it's at global scope, you'd do it like this (but don't :-) ):
// The "A" Code
var me;
var A = function(_me){
me = _me;
}
A.prototype.getMe = function(){
me();
}
// Your code using it
new A(); // Create `A.prototype.getMe`, because unless
// `A` is called at least once, it doesn't exist
var myMe = function() {
console.log("myMe called");
};
me = myMe; // Set the global `me`
A.prototype.getMe(); "myMe called"
The only way to do this is, I guess to use an if .
if(!me){
me = this.myMe
}
So I did A.prototype.getMe.call({myMe: myMe}, args) but would it define the variable in global space ?
Yes, it would. That's what me = this.myMe does.
From that observation, it sounds like you can modify A's code. If so, fix it so that it doesn't define a prototype function in terms of a global variable. Perhaps isolate the code from the function into a function that doesn't expect to be called on an instance and pass in me as a parameter.
I am working on an existing library to make a small change. So I can only change inside getMe function definition. And I cant change var me definition.
In that case, you can add a new optional parameter at the end, and use that if provided and me if not provide:
A.prototype.getMe = function(myMe){
var meToCall = myMe || me;
meToCall();
};
Live Example:
// The "A" Code
var me;
var A = function(_me){
me = _me;
}
A.prototype.getMe = function(myMe){
var meToCall = myMe || me;
meToCall();
}
// Your code using it
A.prototype.getMe(function() {
console.log("My me!");
});
And, separately, A is fundamentally broken if it's really as shown (barring an extremely specific use-case). Having constructor code set a global (global at least to A's code) that's then used by a prototype function is a huge design and maintenance red flag.
Consider the cross-talk horror:
// The "A" Code
var me;
var A = function(_me){
me = _me;
}
A.prototype.getMe = function(){
me();
}
// Using it
var a1 = new A(function() {
console.log("me1");
});
a1.getMe(); // "me1" -- so far so good
var a2 = new A(function() {
console.log("me2");
});
a2.getMe(); // "me2" -- yup, still fine
a1.getMe(); // "me2" -- what the...?!?!?!!
Recently while I was trying to learn more about IIFE and modules in JavaScript
a question came to my mind that how is IIFE making a Module while not Immediately
Invoking the function doesn't make it a module..
can anyone share with me the Difference between this code
var MODULE = (function () {
var my = {},
privateVariable = 1;
function privateMethod() {
// ...
}
my.moduleProperty = 1;
my.moduleMethod = function () {
// ...
};
return my;
}());
and this code where the function is not Immediately Invoked..
var MODULE = function () {
var my = {},
privateVariable = 1;
function privateMethod() {
// ...
}
my.moduleProperty = 1;
my.moduleMethod = function () {
// ...
};
return my;
};
Does the second block of code means that Module is just a function that itself returns an object?
IF I use the second variable like this
var ModuleObj = Module();
Will this work the same as the first Code block that I shared like IIFE.. Kind of confused...
Yeah you pretty much got the idea of the difference between the two, let's look at why you might want one over the other.
An IIFE is useful to isolate the scope. It lets you keep the variables you define private inside the IIFE without polluting the global space around it. It's a nice way to compose a function that has some variables you don't need lurking around. Let's minimize this example a bit.
var Counter = (function () {
var count = 0;
var counter = {
add: function () {
count++;
},
subtract: function () {
count--;
},
getCount: function () {
return count;
}
}
return counter;
})();
Counter.add();
Counter.add();
Counter.getCount(); // 2
Counter.subtract();
Counter.getCount(); // 1
What happens above is that we're able to compose this "counter" functionality without leaking the private information, like count. It'd be bad if other things could override it by accident. Also what happens is that right away we can assign Counter to the result of the IFFE -- the counter set of functions. Counter is now equal to that, and counter is able to retain access to count since it was defined in the same scope.
The benefit here is that we're able to assign a variable to this composition of functionality. The IIFE basically allows us to immediately return what we return inside of it. Since we assign Counter to the IIFE, and the IIFE returns the functionality inside of it, Counter is now a fully functional component.
We don't always have to use IIFE. It's really handy when you want to "tuck away" the implementation details and return an API.
So, what if we had the same thing, but it wasn't an IIFE -- just a function?
Just like your example, we'd have to call it in order to get the "instance".
var CounterFactory = function () {
var count = 0;
var counter = {
add: //...
subtract: //...
getCount: //...
};
return counter;
};
var CounterA = CounterFactory();
var CounterB = CounterFactory();
CounterA.add();
CounterA.add();
CounterA.getCount(); // 2
CounterB.add();
CounterB.getCount(); // 1
See the difference? It's all about what the function is returning. In the first example we only get a single Counter instance, which may be perfectly fine. In the second example, it's more of a "factory" -- it generates an instance of counter and we can call that multiple times and get multiple instances of it.
Ok an IIFE runs the functions within it and defines the variable MODULE to the return of that function. The other declares the MODULE variable to the function itself.
Think of it this way (also try it in your console to see the results).
This code does not run the console.log method.
(function(){
console.log('ran')
});
This code does
(function(){
console.log('ran')
})();
So the whole point of the IIFE is to run the function before doing anything and the (); at the end does this.
If we take the code that did not run and assign it to a value what happens?
var foo = (function(){
console.log('ran')
});
foo();
We have a function foo that we can execute.
So what is the point of an IIFE if we can just assign it and run it later? The answer to that is local variables which you can use for closure later.
console.log(num); //get undefined
(function(){
var num = 'ran';
console.log(num) //get 'ran'
})();
console.log(num); //get undefined
We get undefined ran then undefined so the values we declare in the function stay in the function and nothing else can get to them. This is the lexical scoping that JavaScript runs off of.
Just for fun lets do a closure with it.
var add = (function(){
var num = 0;
return function(){
console.log(num++);
}
})();
console.log(num) //get undefined
add() //get 1
add() //get 2
console.log(num) //still undefined
I am trying to understand better the use of that and this in JavaScript. I am following Douglas Crockford's tutorial here: http://javascript.crockford.com/private.html
but I am confused regarding a couple of things. I have given an example below, and I would like to know if I am making a correct use of them:
function ObjectC()
{
//...
}
function ObjectA(givenB)
{
ObjectC.call(this); //is the use of this correct here or do we need that?
var aa = givenB;
var that = this;
function myA ()
{
that.getA(); //is the use of that correct or do we need this?
}
this.getA = function() //is the use of this correct?
{
console.log("ObjectA");
};
}
function ObjectB()
{
var that = this;
var bb = new ObjectA(that); //is the use of that correct or do we need this?
this.getB = function()
{
return bb;
};
that.getB(); //is the use of that correct or do we need this?
}
Note this is just an example.
this in JavaScript always refers to current object, method of which was called. But sometimes you need to access this of your object in deeper. For example, in callbacks. Like so:
function MyClass() {
this.a = 10;
this.do = function() {
http.get('blablabla', function(data) {
this.a = data.new_a;
});
};
}
It will not work, because this in callback may refer to http, to some dom element or just window(which is really common). So, it is common solution to define self or that, an alias for this or your object, so you can refer it anywhere inside.
function MyClass() {
var self = this;
this.a = 10;
this.do = function() {
http.get('blablabla', function(data) {
self.a = data.new_a;
});
};
}
This should give you vision why it is used and how it should be used.
There is no other reasons(currect me if I'm wrong) to create special variable, you can use this to send your object to other objects and do things, many assignments, such logic, wow...
ObjectC.call(this); //is the use of this correct here or do we need that?
The first thing you need to understand is how the this keyword works. It's value depends on how the function/method/constructor is called.
In this case, function ObjectA is a constructor, so you can just use this inside the code of it. In fact, with var that = this; you declare them to be absolutely identical (unless you use that before assigning to it).
function myA() {
that.getA(); //is the use of that correct or do we need this?
}
Again, it depends on how the function is called - which you unfortunately have not show us. If if was a method of the instance, this would have been fine; but but it seems you will need to use that.
this.getA = function() //is the use of this correct?
As stated above, using that would not make any difference.
var bb = new ObjectA(that) //is the use of that correct or do we need this?
var that = this;
that is undefined when it is used here. And it would be supposed to have the same value as this anyway. Better use this.
that.getB(); //is the use of that correct or do we need this?
Again, both have the same effect. But since you don't need that, you should just use this.
Everything is correct except for :
function ObjectB()
{
var bb = new ObjectA(that) //this is wrong
var that = this;
this.getB = function()
{
return bb;
};
that.getB();
}
You are missing ; and that isn't declare.
You need that (in your case, this is the variable name you use) when you want to use this in another scope :
function ObjectB()
{
var that = this;
// here 'this' is good
function()
{
// Here 'this' doesn't refer to the 'this' you use in function ObjectB()
// It's not the same scope
// You'll need to use 'that' (any variable from the ObjectB function that refers to 'this')
};
// Here 'that' = 'this', so there is no difference in using one or another
}
What "that" is in this context is simply a variable that is equal to "this". That means saying "that" is exactly the same as saying "this", which makes in unnecessarily complicating.
This code:
var that=this;
that.getA();
Will yield the same result as this code:
this.getA();
Having a variable to represent "this" just complicates things when you can just say "this".
Is there any way to refer to the function object that you're currently executing in? If it's not a method of any object or not called with .call() or .apply(), the this pointer is likely just window, not the function object.
I often use a design pattern like this for global variables that I want scoped to a particular function as this keeps them out of the top level namespace:
function generateRandom() {
if (!generateRandom.prevNums) {
generateRandom.prevNums = {}; // generateRandom.prevNums is a global variable
}
var random;
do {
random = Math.floor((Math.random() * (99999999 - 10000000 + 1)) + 10000000);
} while (generateRandom.prevNums[random])
generateRandom.prevNums[random] = true;
return(random.toString());
}
But, I'd rather not have to spell out the function name every time I want to use a variable scoped to that object. If the name of the function ever changes, there are then a lot of places to change the name.
Is there any way to get the currently executing function object?
Well, you could use arguments.callee()...
https://developer.mozilla.org/en/JavaScript/Reference/Functions_and_function_scope/arguments/callee
From MDN:
Description
callee is a property of the arguments object. It can be used to refer
to the currently executing function inside the function body of that
function. This is for example useful when you don't know the name of
this function, which is for example the case with anonymous functions.
Note: You should avoid using arguments.callee() and just give every
function (expression) a name.
BUT...
What you really want are Javascript Prototypes.
function RandomSomethingGenerator()
{
this.prevNums = {};
}
RandomSomethingGenerator.prototype.generate = function() {
var random;
do {
random = Math.floor((Math.random() * (99999999 - 10000000 + 1)) + 10000000);
} while (this.prevNums[random])
this.prevNums[random] = true;
return(random.toString());
};
Why do I say this?
1.) You're dirtying the global space with all those functions.
2.) Even if you like Jani's suggestion, and you want a "static" function like you have now, my suggestion would be the same, but with a twist: Create your global function, and wrap an instance of an object (built from a prototype) inside the closure and make the call to it (so, basically, make yourself a singleton).
As in this (adapted from Jani's answer):
var randomSomething = (function() {
var randomSomethingGenerator = new RandomSomethingGenerator();
return function() {
randomSomethingGenerator.generate();
};
})();
I don't think there's any way to do exactly what you ask, but you could use a closure for your function-local static variables instead.
You can easily achieve this using an IIFE:
var generateRandom = (function() {
//any function's static variables go here
var prevNums = {};
return function() {
//function code goes here
var random;
do {
random = Math....
}
prevNums[random] = true;
return random.toString();
};
})();
You want arguments.callee. From MDN - callee:
callee is a property of the arguments object. It can be used to refer to the currently executing function inside the function body of that function. This is for example useful when you don't know the name of this function, which is for example the case with anonymous functions.
For example:
> foo = function() { console.log(arguments.callee); };
> bar = function() { foo() };
> bar();
function () { console.log(arguments.callee) }
However, I think this is being deprecated. The above link says, "The 5th edition of ECMAScript forbids use of arguments.callee() in strict mode."
Is there any way to break a closure easily in JavaScript? The closest I have gotten is this:
var src = 3;
function foo () {
return function () {
return src; }
}
function bar (func) {
var src = 9;
return eval('('+func.toString()+')')(); // This line
}
alert(bar(foo()));
This prints '9', instead of '3', as a closure would dictate. However, this approach seems kind of ugly to me, are there any better ways?
Your code is not breaking the closure, you're just taking the code the makes up a function and evaluating it in a different context (where the identifier src has a different value). It has nothing at all to do with the closure that you've created over the original src.
It is impossible to inspect data that has been captured in a closure. In a sense, such data are even more "private" than private members in Java, C++, C# etc where you can always use reflection or pointer magic to access them anyway.
This could be useful if you are trying to create multiple similar methods in a loop. For example, if you're creating a click handler in a loop that relies on a loop variable to do something a little different in each handler. (I've removed the "eval" because it is unnecessary, and should generally never be used).
// Assign initial value
var src = 3;
// This is the regular js closure. Variables are saved by reference. So, changing the later will
// change the internal value.
var byref = function() {
return src;
}
// To "break" the closure or freeze the external value the external function is create and executed
// immidiatly. It is used like a constructor function which freezes the value of "src".
var byval = function(s) {
return function() { return s };
}(src);
src = 9;
alert("byref: " + byref()); // output: 9
alert("byval: " + byval()); // output: 3
As others said this doesn't seem to be the right thing to do. You should explain why you want this and what you want to achieve.
Anyway, one possible approach could be to access properties of an object inside your function. Example:
var src = 3;
function foo (context) {
context = context || window; // Fall back to the global namespace as default context
return function () {
return context.src;
}
}
function bar (func) {
var context = {src: 9};
return func(context);
}
alert(bar(foo));
If you want to access a variable in a wider scope, just don't reuse the variable name in a narrower scope.
That's how it is supposed to work. Work with it instead of trying to fight it.
Here is the code see if you can understand , closures defined within a loop .
var clicked = false;
for(var i=0;i<temp.length;i++){
(function(index){
if(clicked) return false;
$(temp[index]).on('click',function(){
if($(temp[index]).text()=="" && !$(".cell1").val()){
$(this).text(player1Val);
$(".cell1").val(true);
console.log("first player clicked ");
clicked = true;
$(this).off();
for(var j=0;j<temp.length;j++){
$(temp[j]).off('click');
}
return false;
}
else return false;
});
})(i);
}