Problems with scopes or closures [duplicate] - javascript

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 8 years ago.
Problem:
I have a very simple snippet of code.
I create and object with a member variable "counter" and a member function "start()" which increases the counter variable by 1 every second.
The problem here is that the counter variable does not increase when start() acts on it.
This has been driving my head crazy.
Hypothesis:
I believe this is a problem with the "this" keyword or a scope/closure issue but I'm not sure what's exactly wrong.
Code:
var livePlayer = {
counter : 0,
liveIteration: null,
start: function(){
this.liveIteration = setInterval(this.incCounter, 1000);
},
incCounter: function(){
this.counter++;
alert(this.counter); <-- this should return 0, 1, 2, etc. but returns NAN instead
}
};
livePlayer.start();
JSFiddle:
http://jsfiddle.net/justinwong12337/1wjdr0dh/
Your help is greatly appreciated!
Additional info:
This object and its members are part of an AngularJS service and are to be used by a separate controller file.

The problem is neither with scope or closures. :-) It's with this, which is a slippery concept in JavaScript.
In JavaScript, this during a function call is set almost entirely by how the function is called, not where the function is defined. It's basically a special form of function argument. (This is quite different to its meaning in other languages with similar syntax.) The particular problem in your case is here:
this.liveIteration = setInterval(this.incCounter, 1000);
When the browser's timer code calls your incCounter, it will do so with this set to the global object, not to your object. So this.counter isn't the counter property on your object (because this doesn't refer to your object), and things don't work as expected.
You can solve this several ways, probably the most direct is ES5's Function#bind (which can be shimmed on older browsers):
this.liveIteration = setInterval(this.incCounter.bind(this), 1000);
Function#bind returns a function that, when called, calls the original function with this set to the first argument you give it.
More to explore (on my blog):
Mythical methods
You must remember this

Related

Global variable passed in a function not affected by it on the global scope [duplicate]

This question already has answers here:
Is JavaScript a pass-by-reference or pass-by-value language?
(33 answers)
Closed 6 years ago.
First of all, I'm sorry for asking this which was seemingly asked before, but...
In the questions I found, people talk about scope (and I'm familiar with the concept) or about some "callback" or "asynchronous" things that I don't really understand. The reason why I ask this is because all my global variables so far, were normally affected by the great number of functions.
The code I have is way too big for me to paste it here, but I'll give you an example.
var ContainsSomeNumber = 50;
var AnObjectWithSomeValues ...
var TheFunctionInQuestion = function(nameRepresentingTheObject, nameRepresentingNumberVar){
if(nameRepresentingTheObject.lestSayName ==== "SomeString"){
nameRepresentingNumberVar+=5;
}
}
Now the thing is, it understands both variables and gets the correct result when I pass them into the function, however, the ContainsSomeNumber variable remains unaffected by the function on a global scale. If I place an alert or log to show me how much it is inside the function, it shows 55, as it should. But once I try to access the modified global variable in another place with the modified value after the function has been run successfully (chrome and firefox show no foul play), it returns the same unmodified value of 50.
Is the problem because I didn't use hardcode versions of variables to pass in the function, or what? Because like I said, it sees and modifies it the right way, but only inside the function. Shouldn't scope see the variable as a global one as I didn't write "var" in front of the one I used in the function? I mean, I didn't declare it as a new variable, plus it took it's global value normally. Why doesn't the global variable stay modified by the function?
Javascript is always pass by value, but when a variable refers to an object (including arrays), the "value" is a reference to the object.
So if you want to a function modify an variable outside there scope, you should pass an object and change some attribute inside the object.
var obj = {
ContainsSomeNumber: 50;
}
var AnObjectWithSomeValues ...
var TheFunctionInQuestion = function(nameRepresentingTheObject, obj){
if(nameRepresentingTheObject.lestSayName === "SomeString"){
obj.ContainsSomeNumber+=5;
}
}
Or you can return the value:
var ContainsSomeNumber = 50;
var AnObjectWithSomeValues ...
var TheFunctionInQuestion = function(nameRepresentingTheObject, nameRepresentingNumberVar){
if(nameRepresentingTheObject.lestSayName === "SomeString"){
nameRepresentingNumberVar+5;
}
return nameRepresentingNumberVar
}

Definition of 'closures'

Let me ask one question. It's about closures in JavaScript, but not about how they work.
David Flanagan in his "JavaScript The Definitive Guide 6th Edition" wrote:
...Technically, all JavaScript functions are closures: they are objects, and they have a scope chain associated with them....
Is this correct? Can I call every function (function object + it's scope) a "closure"?
And stacks' tag "closures" says:
A closure is a first-class function that refers to (closes over) variables from the scope in which it was defined. If the closure still exists after its defining scope ends, the variables it closes over will continue to exist as well.
In JavaScript every function refers to variables from the scope in which it was defined. So, It's still valid.
The question is: why do so many developers think otherwise? Is there something wrong with this theory? Can't it be used as general definition?
Technically, all functions are closures. But if the function doesn't reference any free variables, the environment of the closure is empty. The distinction between function and closure is only interesting if there are closed variables that need to be saved along with the function code. So it's common to refer to functions that don't access any free variables as functions, and those that do as closures, so that you know about this distinction.
It's a tricky term to pin down. A function that's simply declared is just a function. What makes a closure is calling the function. By calling a function, space is allocated for the parameters passed and for local variables declared.
If a function simply returns some value, and that value is just something simple (like, nothing at all, or just a number or a string), then the closure goes away and there's really nothing interesting about it. However, if some references to parameters or local variables (which, mostly, are the same) "escape" the function, then the closure — that space allocated for local variables, along with the chain of parent spaces — sticks around.
Here's a way that some references could "escape" from a function:
function escape(x, y) {
return {
x: x,
y: y,
sum: function() { return x + y; }
};
}
var foo = escape(10, 20);
alert(foo.sum()); // 30
That object returned from the function and saved in "foo" will maintain references to those two parameters. Here's a more interesting example:
function counter(start, increment) {
var current = start;
return function() {
var returnValue = current;
current += increment;
return returnValue;
};
}
var evenNumbers = counter(0, 2);
alert(evenNumbers()); // 0
alert(evenNumbers()); // 2
alert(evenNumbers()); // 4
In that one, the returned value is itself a function. That function involves code that makes reference to the parameter "increment" and a local variable, "current".
I would take some issue with conflating the concept of a closure and the concept of functions being first-class objects. Those two things really are separate, though they're synergistic.
As a caveat, I'm not a formalist by basic personality and I'm really awful with terminology so this should probably be showered with downvotes.
I would try to answer your question knowing you were asked about what closures are during the interview (read it from the comments above).
First, I think you should be more specific with "think otherwise". How exactly?
Probably we can say something about this noop function's closure:
function() {}
But it seems it has no sense since there are no variables would bound on it's scope.
I think even this example is also not very good to consider:
function closureDemo() {
var localVar = true;
}
closureDemo();
Since its variable would be freed as there is no possibility to access it after this function call, so there is no difference between JavaScript and let's say C language.
Once again, since you said you have asked about what closures are on the interview, I suppose it would be much better to show the example where you can access some local variables via an external function you get after closureDemo() call, first. Like
function closureDemo() {
var localVar = true;
window.externalFunc = function() {
localVar = !localVar; // this local variable is still alive
console.log(localVar); // despite function has been already run,
// that is it was closed over the scope
}
}
closureDemo();
externalFunc();
externalFunc();
Then to comment about other cases and then derive the most common definition as it more likely to get the interviewer to agree with you rather than to quote Flanagan and instantly try to find the page where you've read it as a better proof of your statement or something.
Probably your interviewer just thought you don't actually know about what closures are and just read the definition from the book. Anyhow I wish you good luck next time.
The definition is correct.
The closure keeps the scope where it was born
Consider this simple code:
getLabelPrinter = function( label) {
var labelPrinter = function( value) {
document.write(label+": "+value);
}
return labelPrinter; // this returns a function
}
priceLabelPrinter = getLabelPrinter('The price is');
quantityLabelPrinter = getLabelPrinter('The quantity is');
priceLabelPrinter(100);
quantityLabelPrinter(200);
//output:
//The price is: 100 The quantity is: 200
https://jsfiddle.net/twqgeyuq/

Why is .call(this) used instead of parenthesis [duplicate]

This question already has answers here:
Reason behind this self invoking anonymous function variant
(5 answers)
Closed 8 years ago.
Is there a particular reason why i often encounter:
(function() {
console.log("Hello");
}).call(this);
instead of:
(function() {
console.log("Hello");
})();
It should have the same effect when passing this to call or not?
There seems to be some performance difference: http://jsperf.com/call-vs-parenthesis.
Presumably the code within that function uses this (where you just have console.log). In the version with call, this within the function is the same as this outside it. Without call, this inside the function is either the global object (loose mode) or undefined (strict mode).
If you're not using this within the function, there's no reason to be doing the call version, and I would lean toward not doing so because it's additional unnecessary complexity (and apparently a very very small performance cost).
The addition of .call(this) is important, it changes the context of the function enclosure, meaning that the this keyword will refer to the same this as the outer function enclosure.
In your particular code it doesn't make any difference because inside your function you do not refer to this at all.
this.a = 123;
(function() {
console.log(this.a); // always 123 regardless of scope
}).call(this);
That is significant assuming that this refers to something other than the window object. If this is already pointing to the window, then adding .call(this) makes no difference, since without it, by default the this will go to the window.

How does "makeAddFunction" in Eloquent JS work?

I'm trying to learn Javascript by reading Eloquent Javacript. I'm on the chapter dealing with functions and I'm stuck trying to figure out how the code below works. I don't see how the add function ever gets called. I see them calling addTwo and addFive but those names are different than add. The result of this code being run is 9. Can someone please explain this to me.
function makeAddFunction(amount) {
function add(number) {
return number + amount;
}
return add;
}
var addTwo = makeAddFunction(2);
var addFive = makeAddFunction(5);
show(addTwo(1) + addFive(1));
In makeAddFunction, a function is created, called add. This function is returned.
makeAddFunction is called twice with 2 different parameters, and stored in two variables, addTwo and addFive.
Calling addTwo() and addFive() is calling the functions created by add(), with the "amounts" 2 and 5 respectively.
addTwo(1) + addFive(1) == (1 + 2) + (1 + 5) == 9
Sometimes these types of 'closures' are called Builders, or Factories. The makeAddFunction 'builds' a special version of add based on the parameter you pass to makeAddFunction.
The addTwo function would look like:
function addTwo(number) {
return number + 2;
}
The makeAddFunction create a closure that sets amount as whatever number you pass in and returns a function that will add that amount to whatever number you pass to the new function and return it.
My best advice is you try to learn a bit about Javascript closures. Really. I might not be the answer you are looking for, but it is the best you can do if you want to understand what's happening there.
Get yourself a copy of any good javascript book. Let me suggest 'Javascript - The Good Parts' by Douglas Crockford.
For some of us, Javascript closures were not something we grokked. I hope it's easier for you.
Anyway, makeAddFunctionis a function creator. It creates new functions which are tied to the parameter you passed to makeAddFunction. Therefore, the addTwo variable receives and stores a new function, which you can invoke later by appending parentheses to it, i.e. addTwo().
The parameter you pass to addTwo, i.e. 1on invokation addTwo(1) is passed to the add function, because addTwo is nothing more than an add function where the amount var has a fix value of 2.
var addTwo = makeAddFunction(2);
When you call makeAddFunction(2) initially, the amount var is within its function scope where add can see it. addTwo now is set to the add function that makeAddFunction(2) returned.
addTwo(1)
Remember addTwo is now set to what makeAddFunction(2) returned, which is the function add, and amount is set to 2 within makeAddFunction(2)'s scope. add just returns its argument (1), plus the amount (2) in makeAddFunction(2)'s scope.
The same goes for addFive(5).
Javascript Ninja or The Good Parts are good reads that explain closures in detail. I'd highly suggest picking up those.
Follow the SO Linked/Related Questions on the right. Anyway ..
This is explained the article, albeit with a lot of fluff. Anyway, with a bit of fluff-cutting here is a "annotated" version:
.. functions [do] not just package up [some code to run], but also an environment. [..] a function defined inside another function retains access [to lexical variables (like "amount")] that existed in [the outer function] at the point when [the inner function] was defined.
Thus, the [inner] add function in the above example, which is created when makeAddFunction is called, captures an environment [including the "amount" variable of the outer function]. It packages this environment, together with [the code to run], into a value [(which is a fancy way to say functions are just objects)], which is then returned from the outer function.
When this returned function ([which has been assigned to] addTwo and addFive) is called, [the called function has access to] the captured environment ([and the "amount" variable which still contains the value initially passed to makeAddFunction]). These two values ([which are currently named by] "amount" and "number") are then added, and the result is returned.
I am not found of the original usage of "value" and have edit those parts a good bit - in JavaScript, variables (not values) are bound in closures.
Javascript relies pretty heavily on higher-order functions. Functions can be returned, assigned to variables, and passed around as values. This comes in handy in a lot of situations, especially when dealing with evented programming (JS's direct lineage from the its most prolific implementation in the browser.)
http://en.wikipedia.org/wiki/Higher-order_function
What you are seeing is a function that creates a function. It could be considered a "factory" for a function with one preset argument.

Should one re-declare parameters as variables inside a function? [duplicate]

This question already has answers here:
function arguments
(5 answers)
Closed 9 years ago.
Consider:
var success = function(data){
data = process_data(data);
console.log(data);
};
vs.
var success = function(data){
var data = process_data(data);
console.log(data);
};
What are the pros/cons of each?
There is no difference for your ECMAscript interpreter.
Both, formal paramters aswell as local variables are stored in the such called Activation Object (ES3) respectively lexical Environment Record (ES5+).
Those are, special data containers on implementation level which store data belonging to a context, like a function.
While there won't be any differences at runtime, most linting tools will complain about the second piece of code. JSHint gives this error:
'data' is already defined.
If you don't need the original data parameter it's safe to redeclare the variable, but usually it isn't necessary.
On entering function code, the identifiers in the formal parameter list are effectively treated as variable declarations, therefore including them in a var statement inside the function body has no effect.
However, there was an ancient version of Safari that threw an error in cases like:
function (foo) {
foo = foo || {};
...
}
where no value was passed. However, that was a long time ago and certainly not a reason to include var statements for formal parameters.
If you have:
function foo(bar) {
var bar = otherFunc(bar);
...
}
Although this is technically correct, I consider it poor form because you're implying that there are two distinct "bar" variables. That seems like it could cause more confusion later down the line than the version where you don't use "var".
If you want to declare a variable inside then probabley you should declare it with some other name(not similar to the argument).
This way you will be able to reuse the original argument.
If you don't want to use the original argument then you can directly use it. But remember declaring a new variable inside will restrict the scope of the variable.

Categories

Resources