Passing variable as argument in closure - javascript

I'm studying closures and found the following example code for incrementing a "private" variable named count:
function setup() {
var count = 0;
return function() {
count += 1;
console.log(count);
}
};
var next = setup();
next();
This makes sense to me. However, when I experimented with passing the variable as an argument to the nested function, next() logs 'NaN' to the console. Eg:
function setup() {
var count = 0;
return function(count) {
count += 1;
console.log(count);
}
};
var next = setup();
next();
Can someone explain why this happens?

Can someone explain why this happens?
Inside the closure, count now refers to the parameter, function(count) {. Since you are not passing any argument when you call the function, count is undefined and adding a number to undefined results in NaN.
when I experimented with passing the variable as an argument to the nested function
To be clear: The count parameter has nothing to do with the count variable defined in the outer function. You are not passing the variable as argument, because you are not calling the function, you are defining it.

It's because the inner function now has access to a more local variable, so it doesn't look at any closures it has access to for the "count" variable. And nothing is passed, so count is undefined.
This answer may be useful: Scope Chain in Javascript

Related

Javascript: Are callback functions the only ones allowed to refer to outside variables in a forward-looking way?

I have the following code, note that in the callback function for the close event, the reference to the variable ConnectingLine, which comes after the callback itself:
$('.tabs').tabs({
close: function(event, ui) {
ConnectingLine.show();
}
});
var ConnectingLine = MyHelpers.connectingLine({options here...});
I was assuming that this kind of referencing would work for any kind of closure, but it turns out to be not true. For example:
var add = (function () {
return function () {return counter += 1;}
var counter = 7;
})();
function myFunction(){
document.getElementById("demo").innerHTML = add();
}
The above code would break, causing a NaN error. Apparently, the definition needs to be before the closure function referring to it.
My question is, what allows the callback function to refer to outside variables in a forward-looking manner? Is this really unique to callback functions only? Thanks.
Control never reaches
var counter = 7;
Therefore your maths uses an undefined value (counter is declared and available for use because it is hoisted). The += operator coerces undefined to NaN and NaN is toxic.
Hence the result.

Why cannot use function name to retrieve property in JavaScript?

The following is the code
function add() {
var counter = 0;
this.num = 0;
function plus (){ return counter +=1;}
plus();
return counter;
}
console.log(add.num); //outputs :undefined
Function name can be treated as reference of a function object, so the num is the property of add function object, the outputs could have been 0. But the result is not like so, why?
If i change the code to:
function add() {
var counter = 0;
this.num = 0;
function plus (){ return counter +=1;}
plus();
return counter;
}
var obj = new add();
console.log(obj.num); //outputs : 0
it works correctly. Can anyone explain this? Many many many thanks.
this refers to current instance of your function. until you create a new instance using new add() this will refer to window object.
add.num will check if add has a property named num. Which is false because add refers to a function definition not an instance/object of function.
function add() {
var counter = 0;
this.num = 0;
function plus (){ return counter +=1;}
plus();
return counter;
}
console.log(add.num); //outputs :undefined because add=function(){};
while in another case, when you create object using new it returns you a javascript object having all the public properties.
///obj=Object{ num : 0};
function add() {
var counter = 0;
this.num = 0;
function plus (){ return counter +=1;}
plus();
return counter;
}
var obj = new add();
console.log(obj.num); //outputs : 0 because obj is {num:0}
Fiddle to play: http://jsfiddle.net/ZpVt9/76/
It will help to read-up on this in JavaScript: MDN
When you do new add(), the interpreter creates a new JavaScript Object/Hash and binds it to this variable in the function. So this is valid inside the scope of the function.
When you don't do a new you are calling the function without a context, so this is undefined in such cases (in 'use strict' mode).
You can explicitly pass a context to Functions using Function.apply/Function.call/Function.bind
this inside a function points to different object depending on how the function is called:
If the function is called in the global context (outside any function) this points to global object (which is window if the script is executed within a browser).
console.log(this === window) will output true.
If this is referred inside a function, then it depends if we have set strict mode.
If the code is in strict mode then this will be undefined unless we explicitly assign it to something.
If the code is not in strict mode then this will point to global object. (Which is again window if script is executed in a browser).
If function is used as constructor to make new objects then this points to the new object being made.
If function is used as object method then this points to the object method is called on.
More explanation with examples here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
Every function is an object in JavaScript. But as you can see from above explanation none of the ways this points to function object itself from the same function body. Thus the only way you can set function's property is by directly assigning it to the function without using this.
There is another way of adding a property to functions. This is a very bad idea of doing so as adding any property this way will reflect in all functions used. Every function is linked to Function.prototype object. Thus adding any property in this object will get reflected in all functions.
Function.prototype.someProperty = 1;
//now try accessing it via any function object
console.log(add.someProperty); //should print 1 to console.
"num" is not a property of the "add" function is a property of the object created and returned by that function if you want to add num to your add function you need to do
add.prototype.num=0;
and remove it from your objects definition

Closures: How does this specific piece work? [duplicate]

This question already has answers here:
How do JavaScript closures work?
(86 answers)
Closed 8 years ago.
I'm struggling with this concept. By looking at below, I don't understand when I type on the console that "counter" is equal to the following below. How does it know just to pick up this piece of the code? How does this work?
function(val) {
count += val;
return console.log(count);
};
The Code
var incrementer = function(initialValue) {
var count = initialValue;
return function(val) {
count += val;
return console.log(count);
};
};
var counter = incrementer(5);
counter(3);
counter(1);
Because incrementer returns a function, this effectively means that once counter is filled with incrementer(5) it then becomes a reference to the function that is returned by incrementer this means that the counter variable looks something like this at that time:
counter = function(val) {
count += val;
return console.log(count);
};
To verify this:
console.log(counter);
Therefore subsequent calls to counter will increment the value of count
Note: the variable count exists within the scope of incrementer and can be accessed only because the function that counter refers to was created within that scope.
Incrementer is a function that returns a function. counter is equal to the return of the incrementer function which is a function that takes in a value and increments the value you initially passed in incrementer(5).
Calling incrementer(5) sets the initial state intrinsically, but returns the function that you can invoke with the counter pointer (variable) you created.
Does that explanation make sense?
var counter = incrementer(5); //initializes the "initial value" and returns a function, thus setting "counter" equal to a function.. aka function pointer
counter(3); //invokes the function that increments the value by 3 - hence 8
In javascript , a function remembers the context in which it has been declared.
That the quickest way to explain closures.
So if you create a function that returns a function, the returned functions will "close" on the variables of the outer function, thus the returned function having states.
Since count has been declared in the "parent" scope of the returned function, the returned function will remember that its internal variable count refers to the variable count of incrementer .

Javascript variable scope in "for...in..." loops?

Say I have a code-snippet:
dict = {"key":"elem"}
for (var elem in dict){
someFunction(function(){
anotherFunction(dict[elem]);
})
}
Is elem still that temporary variable created in the for...in... statement when it is referenced at that third level, i.e. at anotherFunction(dict[elem])?
When it gets called in my code, I get an error saying that it returns undefined.
EDIT: could I somehow fix this with a this keyword somewhere?
You are creating a closure over the anonymous function so it depends on what you do with the variable between setting it and using it.
var dict = {
"a": "aaaaaaaaa",
"b": "bbbbbbbbb",
"c": "ccccccccc"
};
for (var elem in dict) {
someFunction(function() {
anotherFunction(dict[elem]);
})
}
function anotherFunction(a) {
console.log(a);
}
Async: The loop runs through before actually executing the code so elem winds up being the last key in the set. The last key gets used several times.
function someFunction(f) {
setTimeout(f, 500);
}
Synchronous: Each function runs in order, so each value gets printed out
function someFunction(f) {
f();
}
elem is defined your problem is that:
dict[elem]
returns undefind
If you create a variable inside any statement the variable will still be scoped to the closest parent function, that's how JavaScript works. Scopes are functions. You should be able to use elem there though so your problem must be somewhere else as gdoron said.
Edit:
It seems that you're calling a function that takes another function as a parameter. Is that really what you want to do?
To use the dict variable as the scope of anotherFunction, you need to reference dict as the scope of that function. Example:
for (var elem in dict) {
someFunction(function(dict, elem) {
return anotherFunction.call(dict, elem);
}
}
In your anotherFunction structure, the usage of the this keyword would reference the dict object.
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/call

Do, inner and outer functions get their own copy of same variable?

just a bit confused by this code
var counter = function() {
//...
var count = 0;
return function () {
return count = count + 1;
}
}
var nextValue = counter();
console.log(nextValue());
nextValue.count = 7;
console.log(nextValue());
console.log(nextValue.count);
console.log(nextValue());
Output is
1
2
7
3
It's counter intuitive. There are two representations of count. One on the outerfunction nextValue and one that only the inner anonymous function can see.
Correct, or are my missing something?
The expression nextValue.count does not refer to the local variable "count" declared inside the function. It is not possible, in fact, to create a reference to a variable local to a function from code outside the function. What you're referencing there is simply a property of the function object.
So, yes, the "count" variable that the returned function has access to is effectively completely private to that function, and it is persisted in the closure formed by the call to the "counter" function.
If you did want that to work, you could do this:
function counter() {
function actual() {
return actual.count = actual.count + 1;
}
actual.count = 0;
return actual;
}
edit — (fixed bogus code) the name "actual" inside gives the returned function safe access to the function object itself; originally I typed "this" there, and that would not work unless the external code set it up explicitly.
The way you describe it, count is effectively a private variable. When you're assign to nextValue.count, you're creating a separate property--not accessing the internal count being incremented by your counter.

Categories

Resources