Hello fellow good devs,
I am writing a node app and I encountered a counter problem, but this is probably a pure JS problem.
I wrote this test code (instead of my complicated problem) in order to present the issue more clearly.
var func2 = function(i,counter,arrcounter)
{
counter++;
console.log('counter is ' + counter);
arrcounter.push(i);
console.log('arrcounter ' + arrcounter);
}
var looptest = function(){
var counter = 0;
var arrcounter = [];
for (var i = 0 ; i<10 ; i++)
func2(i,counter,arrcounter);
}();
As you can see, I declared var counter = 0 before the for loop, as well an array called arrcounter, and I passed it to func2, func2 is being called at every iteration.
And I got this output:
counter is 1
arrcounter 0
counter is 1
arrcounter 0,1
counter is 1
arrcounter 0,1,2
counter is 1
arrcounter 0,1,2,3
counter is 1
arrcounter 0,1,2,3,4
counter is 1
arrcounter 0,1,2,3,4,5
counter is 1
arrcounter 0,1,2,3,4,5,6
counter is 1
arrcounter 0,1,2,3,4,5,6,7
counter is 1
arrcounter 0,1,2,3,4,5,6,7,8
counter is 1
arrcounter 0,1,2,3,4,5,6,7,8,9
As you can see above, the arrcounter was "incremented" corrected (not exactly the right term for array.push i know), yet the integer counter seems to being passed as 0 at every func2 call.
My question is, both the counter and arrcounter were declared before the for loop,
why then the arrcounter "keeps track" correctly while the counter doesn't? And what's the right way to do for the counter in this case?
In Javascript, primitive types are passed by value. In your case counter is also passed by value and changes made to it will not be reflected back. You push i in arrCounter array which is getting incemented that is why arrCounter array shows correct data. Your counter variable is not a global variable and is passed by value to func2() , so changes made to it in func2() will not be reflected back, that is why it is always passed as 0 only.
If you will increment your counter variable and send its value to Func2(), it will start showing correct results, try the following:
var func2 = function(i,counter,arrcounter)
{
console.log('counter is ' + counter);
arrcounter.push(i);
console.log('arrcounter ' + arrcounter);
}
var looptest = function(){
var arrcounter = [];
var counter = 0;
for (var i = 0 ; i<10 ; i++)
func2(i,counter++,arrcounter);
}();
In javascript variable point to objects. This is what assignments do — they point the lefthand to reference the righthand.
When you pass the variable counter into func2 the argument points to object, in this case a number. When func2 then reassigned the variable counter to a new object it takes the local counter variable and points it at a different number object. This has no effect on the variable counter in looptest. So every iteration of your for loop passes 0 to func2.
When you pass an array, it passes a reference to the array, so the array in func2 is the same object as the array in loopiest'. In 'func2' you don't reassign the variablearr, but rather alter the original object, so the changes are seen in thelooptest. So you see the changes reflected inlooptest`
You can see this clearly in this example:
function test(number, arr) {
// reassign number
number = 10;
// change arr
arr.push(1)
/* try reassigning arr instead for a comparison */
// arr = [1]
}
function start(){
var number = 1
var arr = []
test(number, arr)
// only arr has been changed
console.log(number)
console.log(arr)
}
start()
For a better understanding of which parameters are passed by value and which by reference.
The paramters of a function...
Primitives type are passed by value.
Objects (and Arrays) are passed by reference.
var butImGlobal = 1;
var integerVar = 1;
var stringVar = 'change or not ?';
var array = [0,1];
var obj = {fruit: 'apple'};
function test(byvalInt, byvalTest, byrefArr, byrefObj){
byvalInt = 99999;
byvalTest = 'not change';
byrefArr.push('I\'m new!');
byrefObj.fruit = 'pineapple';
butImGlobal = 'my value is changed, and I can change my type too!';
}
document.getElementById('test').innerHTML = '<b>BEFORE</b><br/>integerVar = ' + integerVar + '<br/>stringVar = ' + stringVar + '<br/>array = ' + array.join(', ') + '<br/>obj.fruit = ' + obj.fruit + '</br>butImGlobal = ' + butImGlobal;
test(integerVar, stringVar, array, obj);
document.getElementById('test').innerHTML = document.getElementById('test').innerHTML +'<br/><br/><b>AFTER</b><br/>integerVar = ' + integerVar + '<br/>stringVar = ' + stringVar + '<br/>array = ' + array.join(', ') + '<br/>obj.fruit = ' + obj.fruit + '</br>butImGlobal = ' + butImGlobal;
<div id="test"></div>
var func2 = function(i,counter,arrcounter)
{
counter++;
console.log('counter is ' + counter);
arrcounter.push(i);
console.log('arrcounter ' + arrcounter);
}
here counter parameter has been passed 0 at first. In javascript primitive type variables are passed by value , not by reference. Here variable counter is of type number and it's a primitive . So when it is passed to func2, a local variable counter will be created for func2. So, it will will increment the local counter parameter of func2 function, not the counter variable you have declared in looptest function
local counter parameter of func2 will be incremented to 1 but the variable counter you have declared in looptest function will remain unchanged.So, every time you wiil be feeding it with 0.
you can try the following :
var looptest = function(){
var counter = 0;
var arrcounter = [];
for (var i = 0 ; i<10 ; i++)
{
counter++;
func2(i,counter,arrcounter);
}
}();
Related
var sum = 2;
function addFive() {
var sum = sum + 5;
console.log(sum); //why not 7
}
addFive();
Why is it returning NaN instead of 7?
To make things clearer, your code is essentially being read like so:
var sum = 2;
function addFive() {
var sum; // implicitly equal to undefined
sum = sum + 5; // sum = undefined + 5 = NaN
console.log(sum); // NaN
}
addFive();
As you can see, you're redeclaring sum and it is set to undefined. So, when you try and add 2 to undefined you're going to get NaN (Not a Number).
Instead, you can reference your outer sum variable by not redefining it within your function and instead just reassign its value:
var sum = 2;
function addFive() {
sum = sum + 5; // sum = 2 + 5 = 7
console.log(sum); // 7
}
addFive();
You're declaring the variable sum again in the function. This has all to do with scoping in JavaScript.
Take a look at the following article to learn more.
In this case, the local variable (the one that's declared inside the function) gets priority by the JavaScript parser. This behavior's called 'shadowing'. It starts at the innermost scope being executed at the time, and continues until the first match is found, no matter whether there are other variables with the same name in the outer levels or not.
Because you are declared a local variable sum inside the function.
You have to use this.
var sum = 2;
function addFive(){
var sum = this.sum + 5;
console.log(sum);
}
addFive();
In this context, this will refer to the global object (in a browser, window), so the above code is equal to:
var sum = 2;
function addFive(){
var sum = window.sum + 5;
console.log(sum);
}
addFive();
You can read more about this in this SO post or on MDN
function Counter()
{ this.sum = 0;
this.count = 0;
}
Counter.prototype.add = function(array){
array.forEach(function(entry){
this.sum+= entry;
++this.count;
},this);
};
var obj = new Counter();
obj.add([2,5,9]);
console.log(obj.count);
// 3
console.log(obj.sum);
//16
What does the ++ sign does here?
I know this is a contrived example,and it is an array.forEach(function())
application. But I don't seem to understand this.arg very well. Please walk me through this code. And why it is the outputs are 3 and 16
this[arg] refers to a property of the "class" Counter. this.count is some counter that's saying how many times this.sum has been increased. ++ just increments something by 1.
In other words, if some variable foo is 0, foo++ is the same as foo = foo + 1.
Basically it goes like this...
You passed in [2, 5, 9], and forEach loops over each value.
First iteration:
this.sum = this.sum + 2 // => 2
this.count = this.count + 1 // => 1
Second iteration:
this.sum = this.sum + 5 // => 2 + 5 = 7
this.count = this.count + 1 // => 1 + 1 = 2
Last iteration:
this.sum = this.sum + 7 // => 7 + 9 = 16
this.count = this.count + 1 // => 2 + 1 = 3
And thus, you get 16 and 3.
You create a Counter object :
var obj = new Counter();
You call the add() function of the Counter Object with as parameter an array with the number 2, 5 and 9:
obj.add([2,5,9]);
About the add() function :
Counter.prototype.add = function(array){
function(array){
array.forEach(function(entry){
this.sum+= entry;
++this.count;
},this);
};
For each element of the array, the forEach() function makes two things :
increment the sum number variable by summing each element of the array :
this.sum+= entry;
increment the count number variable as soon as a forEach() invocation is done:
++this.count;
++this.count; is a pre increment operator. It means that count is increment during this statement.
In this context, it changes nothing as you don't use the result of the incrementation in the same statement.
You could use this.count++;.
If for example, you would increment and output this new value in the console in the same statement, it would make sense :
var count = 0;
console.log(++this.count); // display 1
With pre increment, the new value would be reflected only in the next statement:
var count = 0;
console.log(this.count++); // display 0
console.log(this.count); // display 1
Why am i getting two different results from the below code. The only change i am doing is passing the value to a function, in first code i am getting the value of global variable "count" as 10 and in the second code the global variables("count") value changes to 30.
function addTen(count) {
count = count + 20;
return count;
}
var count = 10
var result = addTen(count);
console.log(count); //10
console.log(result); //30
function addTen(num) {
count = num + 20;
return count;
}
var count = 10
var result = addTen(count);
console.log(count); //30
console.log(result); //30
In your second function, the statement
count = num + 20;
assigns to the global variable (it's the only count in scope). To make it a local variable for the function scope only, and not affect the global, use
var count = num + 20;
In your first function, the parameter count implicitly declares such a local variable, shadowing the global variable of the same name.
I've read through the following code for Example 7 posted on the following answer for How do JavaScript Closures work?
function newClosure(someNum, someRef) {
// Local variables that end up within closure
var num = someNum;
var anArray = [1,2,3];
var ref = someRef;
return function(x) {
num += x;
anArray.push(num);
alert('num: ' + num +
'\nanArray ' + anArray.toString() +
'\nref.someVar ' + ref.someVar);
}
}
obj = {someVar: 4};
fn1 = newClosure(4, obj);
fn2 = newClosure(5, obj);
fn1(1); // num: 5; anArray: 1,2,3,5; ref.someVar: 4;
fn2(1); // num: 6; anArray: 1,2,3,6; ref.someVar: 4;
obj.someVar++;
fn1(2); // num: 7; anArray: 1,2,3,5,7; ref.someVar: 5;
fn2(2); // num: 8; anArray: 1,2,3,6,8; ref.someVar: 5;
I used the same logic for my example
function increment() {
var id = 0;
return function(number) {
id += number;
alert('Unique ID: ' + id);
}
}
six = increment();
fourteen = increment();
six(6);
fourteen(8);
In the example I took inspiration from,
fn1(2); //num 7
The num outputs 7 because according to my understanding, it has been set to 5 from the previous call first time around. So using the same reasoning, I expected the fourteen(8) call to return the number 14 because I believed ID would have been updated to 6 rather than stay at 0. Why is the variable not static? How would I account for it to be static?
I also tried to have the function set a parameter of number and set the ID equal to the parameter but that did not update it either.
http://jsfiddle.net/de9syawe/4/ to show.
newClosure's closure will capture the num initialized to someNum each time it is called. Thus, f1 has its own num, which starts at 4, is incremented by one to 5, then is incremented by two to 7. Meanwhile, f2 has its own num, which starts at 5, is incremented by one to 6, and again by two to 8. The interleaving of f1 and f2 calls might confuse you, but they are completely separate, and share no variables.
In the same vein, the closure that increment constructs will capture id at value 0. six has id starting at 0, incrementing by six to 6. fourteen independently starts at its own 0, and is incremented by eight to 8.
Compare:
var globalCounter = 0;
function incrementWithGlobalCounter() {
var counter = 0;
return function(number) {
counter += number;
globalCounter += number;
alert('Counter: ' + counter + '; Global Counter: ' + globalCounter);
}
}
var one = incrementWithGlobalCounter();
var two = incrementWithGlobalCounter();
one(1); // 1, 1
one(1); // 2, 2
two(1); // 1, 3
two(2); // 3, 5
one(5); // 7, 10
Here, globalCounter is captured by the outer closure, so it is shared by all inner closures; the counter is captured by the inner closure and local to outer closure, so it will be independent for each inner closure.
var a = null;
function b() {return "B";}
(a || b)();
when i alert((a || b)());.it shows B. why? the return of a || b is true or false. why the above return B.
2:Local Variables
function power(base, exponent) {
var result = 1;
for (var count = 0; count < exponent; count++)
result *= base;
return result;
}
power(2, 10);
a book says
if power were to call itself, that
call would cause a new, distinct
result variable to be created and used
by the inner call and would leave the
variable in the outer call untouched.
i can't follow it well, expect someone can explain it to me. many thanks
1.
The return value of || is not boolean.
It is the first argument if it is truthy or the second argument if it is not.
So a || b is equivalent to a ? a : b and a && b is equivalent to a ? b : a.
2.
When power is called, a new frame is pushed onto the call stack to hold the paramaters and local variables like other languages. But JavaScript is a bit different from many languages in that when a function call results in a new function instance being created, the new function instance holds a reference to the stack frames on the stack when it is created. Since these stack frames hold locals, there is a different place in memory for functions created by different calls to the same function.
For example, in
function makeCounter() {
var counter = 0;
return function () { return counter++; };
}
var c1 = makeCounter();
var c2 = makeCounter();
c1(); c1(); c1();
c2(); c2();
alert(c1() + ", " + c2()); // -> 3, 2
alert(c1() + ", " + c2()); // -> 4, 3
makeCounter is first called to initialize c1. This creates a stack frame like { counter: 0 } which the first counter function points to.
The second call to makeCounter used to initialize c2 creates a different stack frame.
So the code above is equivalent to
var c1SFrame = { counter: 0 };
var c2SFrame = { counter: 0 };
c1SFrame.counter++; c1SFrame.counter++; c1SFrame.counter++;
c2SFrame.counter++; c2SFrame.counter++; c2SFrame.counter++;
alert(c1SFrame++ + ", " + c2SFrame++);
alert(c1SFrame++ + ", " + c2SFrame++);
which should make it obvious why it alerts what it does.