I have actually no idea how the output of this code is a number. Someone kindly help understanding with what logic is JS running in this example?
<script>
var f = (
function f(){ return "1"; },
function g(){ return 2; }
)();
console.log(typeof f);
</script>
You're using the comma operator. You're basically executing g here
The comma operator evaluates each of its operands (from left to right) and returns the value of the last operand.
var f = (
function f(){ return "1"; },
function g(){ return 2; }
)()
is similar to:
var temp = function g(){ return 2; }
f = temp() // returns 2
Because of the comma operator.
x = a, b;
This evaluates a, then it evaluates b, and the result of b is used. That is, a is only evaluated for its side effects, otherwise its result is discarded.
That means that
var f = (
function f(){ return "1"; },
function g(){ return 2; }
)();
is a fancy way of writing
var f = (function g(){ return 2; })();
which is a fancy way of writing
var f = 2;
and 2 is a number.
Here f is not a function.
Instead contains the value returned by g function.
f currently holds to the value returned in IIFE
var f = (
function f(){ return "1"; },
function g(){ return 2; }
)();
console.log(f);
</script>
So, right, the comma operator. But more important is the change of the context of the functions. They are not anymore accessable from the global scope.
Some expanations may be in this answer of Does the comma operator influence the execution context in Javascript?:
var f = (
function f() { return "1"; },
function g() { return 2; }
)();
console.log(f);
console.log(typeof f);
console.log(g()); // throws error: 'g' is not defined
Related
var d = 1;
(function(){
d = '2'
console.log(typeof d)
function d() {
}
})()
console.log(typeof d)
Could you explain why the second log prints out "number"?
var d = 1;
(function(){
d = '2'
console.log(typeof d)
})()
console.log(typeof d)
I tried to remove the function from the IIFE, and the result of second log becomes "string". I am very confused about it.
The first code:
var d = 1;
(function(){
d = '2'
function d() {
}
})()
because of function hoisting (function definitions are hoisted to the top of the containing scope - I think I worded that right), it's identical to
var d = 1;
(function(){
function d() {
}
d = '2'
})()
Now, d inside the IIFE is declared locally, so the "global" d is irrelevant and untouched by d='2'
I don't understand how all those f() function work, can someone explain why it prints two '1', I know it prints '1' for every '()' after f(f), but I don't know why.
function f(y) {
let x = y;
var i = 0;
return () => {
console.log(++i);
return x(y);
};
}
f(f)()();
And why does the 'i' doesn't increase?
Thank you.
function f(y) {
let x = y;
var i = 0;
return () => {
console.log(++i);
return x(y);
};
}
f(f)()();
is equivalent to
function f() {
var i = 0;
return () => {
console.log(++i);
return f();
};
}
const t1 = f();
const t2 = t1();
t2();
is equivalent to
function f() {
var i = 0;
return () => {
console.log(++i);
};
}
const t1 = f();
t1();
const t2 = f();
t2();
If you did call each of t1 or t2 multiple times instead of just once, you'd increment the i from the respective closure some more. But if you instead just chain them, they call f again and initialise a new var i = 0 for a different closure.
First, the f(y) function essentially calling y onto itself. Executing f(y) would return a new function, which when executed, would execute x(y) and return the results.
To reduce the confusion, it's just calling f(f) for each f() you executed in this example, as x === y and y === f. The important part of why i never seems to increase, is that every execution creates a new i.
What happens in behind are:
f(f)()();
// is same as
const f1 = f(f);
const f2 = f1();
const f3 = f2();
// f(f) would execute first, and returns () => {
// console.log(++i);
// return x(y); // which is same as returning f(f) in this example
// }
Notice that executing f(f) returns x(y) which x(y) seems to be equal to f(f). Seems as it is similar in code, but different instance. Another point is that i was never carried to this new function, nor are shared to the other instances. Each f(f) creates a new i, never passed to the next function.
Let's name the function at line 4 , function A.
return result of function f() is function A.(at line 4 you define a function, you don't call it.)
the body of A is gonna be this and since you use those variables in an inner function, they are not gonna be exposed(i = 0, x = y = f ):
function A(){
console.log(++i);
return x(y);
so what you have now is: A()().
First parenthesis: A() prints a '1' and returns result of f(f) which is function A.(the first i is exposed and a new i is created)
Second parenthesis : A is executed like I said and return another A, since there are no any parenthesis left, there is no more call.
You declare in f always a new i.
Instead, you could store the count into a property of the function itself.
function f(y) {
let x = y;
f.i = f.i || 0;
return () => {
console.log(++f.i);
return x(y);
};
}
f(f)()()();
Coming from Java background trying to make sense out of the following code.
From:
https://medium.freecodecamp.com/lets-learn-javascript-closures-66feb44f6a44#.cbk6c4e9g
For function bar(c), which line passes argument c into bar(c) as I don't see it here.
Thanks.
var x = 10;
function foo(a) {
var b = 20;
function bar(c) {
var d = 30;
return boop(x + a + b + c + d);
}
function boop(e) {
return e * -1;
}
return bar;
}
var moar = foo(5); // Closure
/*
The function below executes the function bar which was returned
when we executed the function foo in the line above. The function bar
invokes boop, at which point bar gets suspended and boop gets push
onto the top of the call stack (see the screenshot below)
*/
moar(15);
When your first statement of function call var moar = foo(5) is executed
moar variable will be function bar(c){var d=30;return boop(x+a+b+c+d);
check the snippet for understanding
var x = 10;
function foo(a) {
var b = 20;
function bar(c) {
var d = 30;
return boop(x + a + b + c + d);
}
return bar;
}
var moor=foo(10);
console.log(moor);
2.After this statement moar(15),your are actually passing 15 to the bar method
It will execute bar method with c as 15. Now this function would return boop(80) which would just be -80
var x = 10;
function foo(a) {
var b = 20;
function bar(c) {
var d = 30;
return boop(x + a + b + c + d);
}
function boop(e) {
return e * -1;
}
return bar;
}
var moar = foo(5)
console.log(moar(15));
Hope it helps
moar(15) passes 15 into bar which gets copied into parameter c.
The // Closure comment is misleading because it is more useful to think of the closure being configured at the point of declaration of a function.
The reality is that the pointer to the outer lexical environment is configured when a function object is instantiated, and then this pointer is then copied to the execution context associated with any invocations of said function object.
factory(n) returns objects with functions.
func1 function definition creates its own scope, and x inside this function references x = n + ''.
But func2 is a reference and the scope is wrong.
Is there a way to return an object from create so its functions were references (not separate definitions)?
Actually, I'm fine with func1 approach while function definition footprint is small. If it is a complex function it would be better not to clone this function into every object comming from factory(n). inner_func may not use this, it is simple function. Also I want to avoid new and this.
var factory = (function(){
var x = '!';
return function create(n){
var x = n + '';
return {
func1: function(y){return inner_func(x, y); },
/* vs */
func2: inner_func_api
}
}
function inner_func_api(y){ return inner_func(x, y); }
function inner_func(a, b){ return a + b; }
}());
var f1 = factory(2);
var f2 = factory(3);
var f1_func1 = f1.func1(4);
var f2_func1 = f2.func1(5);
var f1_func2 = f1.func2(4);
var f2_func2 = f2.func2(5);
console.log(f1_func1, f2_func1); //24 35
console.log(f1_func2, f2_func2); //!4 !5
You could define that function separately from the object initializer on the return statement:
var factory = (function(){
var x = '!';
return function create(n){
var x = n + '';
function func1(y) {
return inner_func(x, y);
}
return {
func1: func1,
/* vs */
func2: inner_func_api
}
}
function inner_func_api(y){ return inner_func(x, y); }
function inner_func(a, b){ return a + b; }
}());
However, it makes no practical difference, and it doesn't matter how big or complicated that function is. Function instances do take up space, but the code for the function is constant (immutable) and doesn't need to be part of every Function object created from the same piece of source code.
I need function change to change variables and return back to Tst1. I expect to get in console:
5
aaa
but have unchanged ones:
6
bbb
My functions:
function change ( aa,bb )
{
aa=5;
bb="aaa";
}
function Tst1()
{
aa=6;
bb="bbb";
change(aa,bb);
console.log (aa);
console.log (bb);
}
One way is to move change() into the function test(). Then it shares the same variables as the calling scope.
'use strict';
function test() {
function change() {
aa = 6;
bb = 76;
}
var aa = 5,
bb = 6;
change();
document.write(aa + " " + bb);
}
test();
JavaScript is like java in that primitives are never passed by reference but objects are always passed by reference. You need to wrap your data in an object and pass that instead:
function change (aa, bb)
{
aa.value = 5;
bb.value = "aaa";
}
function Tst1()
{
aa = { value: 6 };
bb = { value: "bbb" };
change(aa, bb);
console.log (aa.value); // outputs 5
console.log (bb.value); // outputs aaa
}
or you can play with global variable, but it is not a good practice.
var aa,bb;
function change(){
aa=6;
bb=76;
}
function test(){
aa = 5;
bb = 6;
change();
console.log(aa + " " + bb);
}
test();
Short answer: NO, you can't pass primitive parameters by reference in JS.
One alternative solution to the presented here is to return the result values as array of items:
function change ( aa,bb )
{
aa=5;
bb="aaa";
return [aa, bb];
}
function Tst1()
{
aa=6;
bb="bbb";
result = change(aa,bb);
aa = result[0];
bb = result[1];
document.writeln(aa);
document.writeln(bb);
}
Tst1();