I was reading the following topic How do JavaScript closures work? and found this code:
function foo(x) {
var tmp = 3;
return function (y) {
alert(x + y + tmp);
x.memb = x.memb ? x.memb + 1 : 1;
alert(x.memb);
}
}
var age = new Number(2);
var bar = foo(age); // bar is now a closure referencing age.
bar(10);
The author commented:
As expected, each call to bar(10) will increment x.memb. What might
not be expected, is that x is simply referring to the same object as
the age variable! After a couple of calls to bar, age.memb will be 2!
I am confused why it will return 2 always. Can you explain me how it will come 2 always?
What's happening here is that: foo returns a function that, when called, increments the memb property of the object originally passed in to foo.
It would be clearer for that parameter object, age, to be a simple object; but the original author is perhaps having fun here, so passes in a new Number - which, as far a Javascript is concerned, is as valid an object as any.
So when bar is called, the memb property on that Number object is created/incremented.
The "internal value" of that number remains unchanged; it's always 2. But age.memb gets incremented by one each time. That's what the author means by:
After a couple of calls to bar, age.memb will be 2!
The 2 here refers to the value of memb after being incremented a couple of times (ie twice), it's not related to the value of the Number that age just happened to be at the start. Call bar again, and age.memb will be 3.
It will not "always" be 2.
Author says: "After a couple of calls to bar, age.memb will be 2" - and after 2 calls it will be "2".
After 4 calls it will be 4.
Just paste this to firebug console:
function foo(x) {
var tmp = 3;
return function (y) {
//console.log(x + y + tmp);
x.memb = x.memb ? x.memb + 1 : 1;
console.log(x.memb);
}
}
var age = new Number(2);
var bar = foo(age); // bar is now a closure referencing age.
bar(10);
bar(10);
bar(10);
bar(10);
console.log('result: ', age.memb) // result: 4
bar(10) has a reference to foo(2)
So each time you call bar(10). It will execute the inner function(closure) of foo which
is having parameter y as 10 and since bar has age reference as 2. So age will be 2 always if you call bar(10) and y will be 10 or so depending on value provide. Closure basically saves the reference to inner function even if the outer function is not there.
If I understand correctly you obtain some like a function pointer in bar. This points to the nameless function. This nameless function always receives the same input because foo is only called once i.e. x never changes. As a result there is no memory in the nameless function giving you the input value of x as a result always.
Related
Can I confirm that the reason code snippet 2 (&3) work is because something like: when variableA is fully, or partly, assigned to variableB, variableB always gets what variableA is at the time variableB is (last) initialised?
The aim: to make a function that continually prints "red0", "red1" "red2" etc.
In the first snippet, when we come to log out colorNum, colorNum doesn't dynamically update its num value. It's as if colorNum captures what num at the last moment colorNum was initialised.
num = 0;
colorNum = "red" + num;
function printObject() {
console.log(colorNum);
num++;
}
setInterval(printObject, 2000);
Here colorNum is continually reinitialised. So the updated value of num is captured in colorNum because colorNum is reinitialised after num is updated.
let num = 0;
let colorNum = "red" + num;
function printObject() {
colorNum = "red" + num;
console.log(colorNum);
num++;
}
setInterval(printObject, 2000);
Similarly the return expression of fun is a new expression every-time fun is called. The return expression captures the value of num at the point in time the return expression is created.
num = 0;
fun = function(){
return "red" + num;
}
function printObject() {
console.log(fun());
num++;
}
setInterval(printObject, 2000);
In languages like JavaScript (which is to say, most common programming languages), assigning a primitive value from one variable to another establishes absolutely no permanent relationship between them. The assignment operator is an immediate imperative, after which the two variables sail off into the night.
Also, note that the assignment
colorNum = "red" + num;
is evaluated by first computing the value of the right-hand side. The string constant "red" and the value of num are concatenated. After that has happened, before that result value is assigned, there is no remaining trace of num. All the runtime has is the result value from the concatenation, and that value has nothing whatsoever to do with the variable num.
Now, reference assignment is a different story, to some extent, or at least superficially, but as far as the language actually works it's the same story. So in
let x = { a: "hello" };
let y = x;
y.a = "goodbye";
console.log(x.a);
the value of property "a" in the only object involved will change. However, if subsequently:
let x = { a: "zebra" };
y.a = "giraffe";
console.log(x.a);
it'll still be "zebra" because assigning a new object reference to x has absolutely no effect on y.
From older languages like C, from which JavaScript syntax is at least loosely derived, an assignment expression is literally a request to copy a value stored in memory from one place to another. It looks like algebra but it does not work like pencil-and-paper algebra. JavaScript is conceptually a higher level language, but the semantics are still the same.
You're right in your assumption. In code snippet 2 and 3 num gets added every time. In 1 it is only added 1 time. At the moment of assignment the variable's value is taken. Whether it changes later doesn't matter.
Note that if you study Javascript a bit longer, you'll notice a different behaviour for Object and other types where assignment doesn't mean later changes to the original are disregarded, but this is a more advanced topic.
There is nothing like partial assignment; either you assign or don't assign.
In the first example, where you write colorNum = "red" + num;, you are not partially assigning num to colorNum. Rather you are using num in creating a new string, and then you are assigning that new string to the colorNum variable. So, as long as you don't update the colorNum with new value, it continues to hold the old value (As long as we are dealing with primitive values like numbers, strings, boolean, etc. This changes when we are dealing with objects which are usually passed around as references).
In example 2 & 3, you are updating the value of colorNum variable every time and hence they are working fine.
In your code examples there is no "magic" behind the variables assignment. The only difference is the order of commands.
Normally, all commands run synchronously, so one-by-one (we are not looking into parallel now). Of course, there are some differences between programming languages, for example in JavaScript all variable and function definitions (var) goes to the start of the code.
Let's return to your code.
Your first example:
num = 0;
colorNum = "red" + num;
function printObject() {
console.log(colorNum);
num++;
}
setInterval(printObject, 2000);
Actually it has var before variable creation. Also I will add line numbers, so it will be easier to understand the order of commands:
/* 1 */ var num = 0;
/* 2 */ var colorNum = "red" + num;
/* 3 */
/* 4 */ function printObject() {
/* 5 */ console.log(colorNum);
/* 6 */ num++;
/* 7 */ }
/* 8 */
/* 9 */ setInterval(printObject, 2000); // 9
First of all, functions and variables created, so first commands will be in line 1, 2, 4 (we create function, but do not run it, just create).
After command in line 1 we will have num equal to 0.
After command in line 2 we will have colorNum equal to "red" + num that is "red" + 0 that is "red0"
Now we come to line 9. Here we calling function printObject every 2 seconds, so...
...when 2 seconds passed we call function printObject, so:
we run command in line 5 and print to console our colorNum that is still equal to "red0"`
line 6 increase num by 1, so now we have num equal to 1
... another 2 seconds passed and we call function again, so:
we run command in line 5 and print to console our colorNum that is still equal to "red0"(because we did not change the value insidecolorNumafter it was set in line2`)
line 6 increase num by 1, so now we have num equal to 2
and so on... We print always the same colorNum as it was created on line 2 and we never change it again, so console.log will use its original value
Ok, now I will be quicker. Your second example has one additional line inside the function: colorNum = "red" + num;. That is very good, because now we change the value of colorNum before we print it to console.
Your third example has different idea of getting the value that we will print to console. You have added another function, that calculates the value. So your code:
num = 0;
fun = function(){
return "red" + num;
}
function printObject() {
console.log(fun());
num++;
}
setInterval(printObject, 2000);
Is equal to:
num = 0;
function printObject() {
console.log("red" + num);
num++;
}
setInterval(printObject, 2000);
This is because your function fun has only one line of code: "red" + num, so I can replace this function call with this line.
Actually, you even do not need to have a separate line for num++, or even the printObject can be "inlined":
var num = 0;
setInterval(() => console.log("red" + num++), 2000);
I am new to Javascript, and sturdying about the concept of higher order function, and using function as parameters.
I got two examples of code from online, and I do not understand what is going to happen.
First one, output will be 0, and I could not print the time of t1 and t2 ( I tried console.log(t1), but it became reference error). I wonder why it became 0.
Also, I don't get how funcParameter() that is inside of functionbody is working for the function, though I know funcparameter() is callback function, and which is addOneToOne().
Second one, output will be 3. but how can it be 3 even though, I haven't put parameter into addTwo()? If I have not put anything in parameter, num will be automatically 0 or undefined?
I am sorry for many questions, but I really appreciate if you could help me out.
//1st code
const timeFuncRuntime = funcParameter => {
let t1 = Date.now();//
funcParameter();
let t2 = Date.now();//
return t2 - t1;
}
const addOneToOne = () => 1 + 1;
timeFuncRuntime(addOneToOne);
console.log(timeFuncRuntime(addOneToOne))//0
//2nd code
const addTwo = num => num + 2;
const checkConsistentOutput = (func, val) => {
let firsttry = func(val);
let secondtry = func(val);
if(firsttry === secondtry){
return firsttry;
} else {
return 'This function returned inconsistent results';
}
};
checkConsistentOutput(addTwo,1)
console.log(checkConsistentOutput(addTwo,1))//3
1: The scope of the t1 variable is limited to the function block. You can read more about variables scope here
2: You are using val as function parameter, and the value of val is 1.
1 + 2 = 3
The 1 is in this line:
checkConsistentOutput(addTwo,1)
First one, output will be 0, and I could not print the time of t1 and t2 ( I tried console.log(t1), but it became reference error). I wonder why it became 0.
Because zero milliseconds passed between the first call to the callback and the second. Date.now() works in milliseconds. The call probably took microseconds at most.
You couldn't access t1 or t2 because they're local variables in the timeFuncRuntime function, so you can't access those variables outside the timeFuncRuntime function, only inside it.
Also, I don't get how funcParameter() that is inside of functionbody is working for the function, though I know funcparameter() is callback function, and which is addOneToOne().
Functions are objects in JavaScript. When you do timeFuncRuntime(addOneToOne), you're passing a reference to the function into timeFuncRuntime which it receives as the value of the funcParameter parameter. So when that code does funcParameter(), it's calling addOneToOne.
Second one, output will be 3. but how can it be 3 even though, I haven't put parameter into addTwo()?
Because checkConsistentOutput did it. When you do console.log(checkConsistentOutput(addTwo,1)), you're passing a reference to addTwo and the number 1 into checkConsistentOutput. It receives them as its func and val parameters. So when it does func(val), it's calling addTwo with the value 1. It gets the result in the firsttry variable, then does the call again and gets the result in secondtry, and since they match, it returns the value of firsttry, which is 3.
Second one, output will be 3. but how can it be 3 even though, I haven't put parameter into addTwo()?
You copy the function stored in addTwo as the first argument to checkConsistentOutput where it gets assigned to func. Then you call the function here — let firsttry = func(val); — and here — let secondtry = func(val);
It is said in w3cschool that "If a function changes an argument's value, it does not change the parameter's original value."
However, i don't quite understand that with the following example:
function bar(a){
arguments[0] = 10;
console.log("a",a);//10
return a;
}
function foo(cc){
cc = 10;
return arguments[0];
}
console.log(bar(333));//10
console.log(foo(333));//10
I have tested them in both chrome and firefox.
From my understanding , if argument value changes can not lead to parameter value change, why 'bar' fail to return 333?
Given a function:
function bar(a) {
arguments[0] = 10;
return a;
}
Calling it like bar(50) will return 10, because the value inside bar's scope was replaced by 10.
What "If a function changes an argument's value, it does not change the parameter's original value." means is that doing:
var x = 90;
var y = bar(x);
console.log(y);
console.log(x);
// y is 10
// x is still 90
... won't change the value of x outside of bar.
For more info see:
W3Schools tutorial on function parameters
MDN's guide to functions (in particular the section on function scope)
As Rudolfs stated the rule is related to the variable in the outer scope. But it is not always true. For arrays & objects the rule is not applied
function modify(obj) {
obj.value = 'modified';
}
var objOuter = {value: 'original'};
console.log('The original value is ' + objOuter.value); //original
modify(objOuter);
console.log('The modified value is ' + objOuter.value); //modified
I am looking at this function
function foo(x) {
var tmp = 3;
return function (y) {
alert(x + y + (++tmp));
}
}
var bar = foo(2); // bar is now a closure.
bar(10);
when I run it, the variables get the following values
x = 2,
y = 10
tmp = 3.
Now I see that in foo(2) x is passed as 2. So its understandable that x is getting the value of 2. But then bar(10) is assigning a value of 0 to y. Hows that? I am confused on how does the receiving function know that 10 is the value for y assigned by bar(10)
foo(2) returns an anonymous function which accepts one parameter (y). As you're setting bar to be the return value of foo(2), bar becomes a reference to that anonymous function.
So, when you call bar(10) you're calling the anonymous function foo returns, and so 10 is being set to the parameter y.
This is a closure.
When you write:
var bar = foo(2);
it's actually calling foo, so the net result is:
var bar = function (y) {
alert(2 + y + (++tmp));
}
where tmp is the value bound in scope by the closure.
So, subsequently calling:
bar(10);
is passing 10 into that function, with the result being:
alert(2 + 10 + (++tmp));
tmp will increase each time you call any function created with foo
I was reviewing some today, when I encountered the following convention :
TestParam(1);
function TestParam(p){
var p = p + 1;
alert(p); // alerts '2'
}
Now, obviously, the developer didn't mean to delcare 'p' within the function, instead maybe meaning:
p = p + 1;
But the code still worked, i.e. the value alerted was "2". So it got me to thinking. What would happen in the following scenario:
var a = 1;
TestParam(a);
alert(a); // alerts "1"
function TestParam(p){
var p = p + 1;
alert(p); // alerts '2'
}
Again the alerts were as I suspected (as intimated in the comments above). So then I was curious as to what would happen if I used an object:
var a = { b: 1 };
TestParam(a);
alert(a.b); //alerts 1
function TestParam(p) {
var p = {b:p.b + 1};
alert(p.b); //alerts 2
}
So, in this instance, JavaScript has 'remembered' the variable a, even though when it is passed to TestParam as p, p is redeclared.
Now if I were to have done the following within the function, then both alerts would have been "2"
p.b++;
//var p = {b:p.b + 1};
I.e. it would have modified the member b of the original object. I get this. Its the previous scenario that baffles me!
I realise this is quite a hypothetical question that is unlikely to carry much real-world usefulness, but it still made me quite curious, as to what is going on in the background, and how exactly JavaScript is scoping and referencing these variables.
Any thoughts?
Variables are scoped to the enclosing function in JavaScript. And you can declare them as many times as you like.
Objects are not tied to variables; many variables can refer to the same object. (This is sometimes called aliasing.) This is what's happening in your last example. JavaScript has not "remembered" the variable a at all; rather, p and a refer to the same object, so when it is changed via p, you can see those changes via a.
Here's an example that might make more sense to you. Sometimes a person has more than one identity.
var Clark = new Person;
var Superman = Clark; // Maybe not everybody needs to know these two are
// the same person, but they are.
Clark.eyes = "brown";
alert(Superman.eyes); // should be brown, right?
Knowing the rules of the language you're using has tremendous "real-world usefulness". Not understanding these two rules is the source of a lot of confusion and bugs.
Javascript generally passes all arguments to functions by reference except when the argument is a number or a string. Javascript passes numbers and strings by value which is why your first example works the way it does.
I believe there's a typo in your code. I think you mean:
function TestParam(p) {
var p = {b:p.b + 1}; // p.b, not p.a (p.a == undefined)
alert(p.b);
}
In your example:
var a = { b: 1 }; // "a" is defined in the global scope
TestParam(a);
alert(a.b); // alerts 1
function TestParam(p) {
var p = {b:p.a + 1}; // "p" is defined in TestParam()'s scope
/* But not until after the expression on the right side of the assignment
has completed--that's why you can use p.a
alert(p.a); //alerts 2
}
At first, "p" is passed as a reference to the global variable "a", but then you redefine it in the first line. So, for example:
var a = { b: 1 };
alert(a.b); // Alerts 1
TestParam(a);
alert(a.b); // Alerts 2
TestParam(a);
alert(a.b); // Alerts 3
function TestParam(p) {
p.b++;
}