%%script nodefunction outside(x) { function inside(y) {return x + y; }return inside; } const myfunction = outside(3);// Think of it like: give me a function that adds 3 to whatever you give it console.log(myfunction(5));//8// the above is the same as running this: console.log(outside(3)(5));//8
8
8
Line by line explanation & notes
const myfunction = outside(3) > Here we define myfunction variable with outside(3), doing so created a new scope with x = 3. This x is preserved in this scope, ie x inside myfunction scope will always be 3, because we initialized it as myfunction = outside(3).
Each time we initialize outside, a new scope is created. This is similar to how class object works – x here is like an attribute of a class object and myfunction is an object instance – except using nested functions, we can not directly inspect or access x.
myfunction(5) > Here we call the variable containing the outside(3) function we initialized. The argument we passed 5 will be passed as y. Since we have initialized x = 3 previously, the inside function will return x + y which is 3 + 5.
inside function can access variable defined in outside function. However outside function can not access anything defined in inside function. > This is different from python –> when we defined nested functions, the outer function can access anything that is defined within itself since whatever defined within it is its local scope.
Example 2
%%script nodefunction outside() { const x =5; function inside(x) {return x *2; }return inside;}console.log(outside()(10));//20 (instead of 10)
20
Line by line explanation & notes
outside()(10) > outside() created a new scope. (10) is where we call inside(10) inside the outside() scope. Therefore x=10 in the inside() function.
In nested function, the innermost function takes more precedence than the outside function. > When we call outside()(10), we initialized x=10 within inside() function. Since inside() scope is of higher precedence than outside(), const x = 5 we defined in outside() function scope is overrode.
The scope of chain here is inside() ==> outside() ==> global object.
Example 3
%%script nodeconst getCode = (// outer function (anonymous function) function () { const apiCode ="some-api-code";// A code we do not want outsiders to be able to modify…// nested inner function (anonymous function)return function () {return apiCode +'--some-other-code-added-in-inner-function'; }; })();console.log(getCode());
function () {
const apiCode = "some-api-code";
...
}
On line 9 - line 11, we define another function within the outer function.
return function () {
return apiCode + '--some-other-code-added-in-inner-function';
};
(); on line 13 immediately invoke the outer function. The outer function then assign its return value (the inner function) to getCode.
Example 4
%%script nodeconst getCode = (// outer function (anonymous function) function () { const apiCode ="some-api-code";// A code we do not want outsiders to be able to modify…// nested inner function (anonymous function)return function () {return apiCode +'--some-other-code-added-in-inner-function'; }; })();console.log(getCode);// here we just save the outer function in `getCode` variable but did not call it
[Function (anonymous)]
Example 5
%%script nodeconst getCode = function () { const apiCode ="some-api-code"; console.log("this is from outer function");return function () { console.log("this is from inner function");return apiCode +'--some-other-code-added-in-inner-function'; };};const myfunct = getCode();// calls the outer functionconsole.log('-------')console.log(myfunct);// we saved the outer function in this variable - outer function contains the inner functionconsole.log('-------')console.log(myfunct());// explicitly call the inner function
this is from outer function
-------
[Function (anonymous)]
-------
this is from inner function
some-api-code--some-other-code-added-in-inner-function
If we don’t directly invoke the outer function at end of outer function definition, we would have to explicitly call the outer function. See example above.
Example 6: Multiple Arguments
%%script nodefunction myConcat(separator) { let result ="";// initialize list// iterate through argumentsfor (let i =1; i < arguments.length; i++) { result += arguments[i] + separator; }return result;}console.log(myConcat(". ", "sage", "basil", "oregano", "pepper", "parsley"));//"sage. basil. oregano. pepper. parsley. "
sage. basil. oregano. pepper. parsley.
Line by line explanation & notes
Within the function, arguments are maintained like an array and can be accessed like so arguments[i];. Where i is the index of the arguments, starting at 0.
This means, you can pass any number of arguments when you call the function. Eg above myConcat(". ", "sage", "basil", "oregano", "pepper", "parsley");. Note that in the function definition we only specify 1 parameter myConcat(separator). This is different than python where we need to have to pass the same number of arguments as we defined in the function definition.
Example 1 --------------
14
9
Example 2 --------------
7
2
At a glance, the above looks like a function containing a dictionary of functions (using python terminology). In Javascript, this is called object with methods.
calc1 = myCalc(10); Here we initialized calc1 with outer function scope of val1 = 10.
Notice we can directly call the inner functions using dot notation, similar to how we would do to class object. This is possible because we returned the object return {add: function() {...}, subtract: function() {...} }.
In the example above, we use anonymous function. The syntax is:
%%script nodeconst myCalc = function(val1) {// named function here function add(val2) {return val1 + val2 } function subtract(val2) {return val1 - val2 }return {add, subtract};};console.log('Example 1 -------------- ')calc1 = myCalc(10);console.log(calc1.add(4));//10+4=14console.log(calc1.subtract(1));//10-1=9console.log('Example 2 -------------- ')calc2 = myCalc(5);console.log(calc2.add(2));//5+2=7console.log(calc2.subtract(3));//5-3=2
Example 1 --------------
14
9
Example 2 --------------
7
2
Above is another way to return the same methods. Here we use named functions. The syntax is:
function outer_func() {
function inner_func1() {
return ...;
}
function inner_func2() {
return ...;
}
return {inner_func1, inner_func2}; // main difference is here
}
Notice that we directly define the named functions, then return {inner_func1, inner_funct2}. This is different than the previous example where we directly define the inner functions in the return statement return {inner_func1: ... , inner_func2: ... }
Example 8
%%script nodevar createCounter = function(init) { let cur = init;return { increment: function() {return++cur;// increment cur then return }, decrement: function() {return--cur ;// decrement cur then return }, reset: function() {return (cur = init);// reassign cur then return } }};const counter = createCounter(5);// init =5console.log(counter.increment());//6console.log(counter.reset());//5console.log(counter.decrement());//4
6
5
4
init value never change after initialization. On line 21, we initialized counter = createCounter(5), this means init = 5.
On line 4, we created another variable cur, which we store the initial init value.
In each inner functions, we perform ++cur (increment cur then return cur); --cur (decrement cur then return cur);
On line 16, return (cur = init). Here we are essentially doing 2 steps, reassigning cur = init, then return cur. We can explicitly write it in 2 steps like below:
reset: function() {
cur = init;
return cur;
}
Likewise, we can also expand return ++cur where we increment cur, then returns it into 2 separate lines, like below:
increment: function() {
++cur; // or cur++, it does not matter here. See below example for details
return cur;
}
Postfix vs Prefix
%%script nodelet cur =5;let result =++cur;// `cur` is incremented first, then `result` gets the new value of `cur`console.log(result);//6 (value of `cur` after increment)console.log(cur);//6 (value of `cur` after increment)
6
6
%%script nodelet cur =5;let result = cur++;// result gets the current value of `cur`, then `cur` is incrementedconsole.log(result);//5 (value of `cur` before increment)console.log(cur);//6 (value of `cur` after increment)