Section 15: Functions - Advanced Concepts - That's More
The goals
๐ช๐ปPure Functions & Side Effects
โ๐ปFactory Functions
๐๐ปClosures (& Scope Revisited)
๐๐ปRecursion
Pure vs Impure functions
Pure functions
In simple terms, pure functions do not have an internal state. Therefore, all operations performed in pure functions are not affected by their state. As a result, the same input parameters will give the same deterministic output regardless of how many times you run the function.
function add(a,b) {
return a + b
}
console.log(add(4,5))
This example contains a simple add() function, which gives 9 as the output. It is a very predictable output, and it does not depend on any external code. This makes the add() function a pure function.
If a function is declared pure and does not have a state, it can share many instances inside a class. Also, it is advised to avoid mutations inside pure functions.
Advantages of pure functions
- A pure function works as an independent function that gives the same output for the same inputs.
- Pure functions are readable because of independent behavior. Moreover, they are straightforward to debug.
- You can clone an external state into a pure function, but it does not change the purity of the function.
Impure Functions
An impure function is a function that contains one or more side effects. It mutates data outside of its lexical scope and does not predictably produce the same output for the same input.
For example, consider the following code snippet:
var addNew = 0;
function add(a,b){
addNew =1;
return a + b + addNew
}
console.log(add(4,5))
In the above example, there is a variable named addNew, and it is declared outside of the add() function. But the state of that variable is changed inside the add() function. So, the add() function has a side effect on a variable outside of its scope and is therefore considered an impure function.
JavaScript doesn’t adhere to rigorous notions of function purity and immutability. Any program you develop will need impure functions to modify the state of JavaScript variables (named memory locations).
In general, it’s ideal to keep the impure elements of your programs distinct from the data processing, which is usually pure. Also, updating and maintaining your applications will be much easier if you confine impure elements to their particular functions.
The following JavaScript functions are inherently impure:
- Math.random()
Math.random() is an impure function since it modifies the internal state of the Math object and provides different results with each call. So Math.random() can contain side effects.
In the above code snippet, no arguments pass into any of the Math.random() function calls, but still they all produce a different result.Math.random(); (Output: 0.4450692005082965) Math.random(); (Output: 0.7533405303023756) Math.random(); (Output: 0.4011148700956255)
- Date.now()
- arr.splice()
- arr.push()
- arr.sort()
- console.log() and alert() are also impure functions (although they generate the same behavior and always return the same value for identical calls).
- JavaScript is synchronous by its nature. Therefore, asynchronous functions such as fetch and promise are impure.
Advantages of impure functions
- Impure functions can use an in-place solution to reduce the space complexity.
- In impure functions, the state can be modified to use the parent variable and call for the function compiling.
As mentioned, the main difference between pure and impure functions in JavaScript is side effects. So, let’s discuss some specifics about the side effects.
Side effects
Side effects can occur in your program when it uses an external code block inside a function. As a result, there can be performance issues in your application.
Let’s consider the following example and discuss the side effects in detail.
var preNumber =2;
function addValue(newNumber){
return preNumber += newNumber;
}
In the above example, the variable preNumber is used inside the addValue() function. This behavior can result in the following side effects.
Side effect 1: Dependency issue
The addValue() method depends on the preNumber variable. If preNumber is not defined or not available, the method will throw an error.
Side effects 2: External code modification
When the addValue() function executes, it changes the state of the preNumber variable. It shows that the addValue() method has a side effect of modifying external code.
Side effects 3: Non-deterministic function
The addValue() function uses external code. It makes the function non-deterministic, which means you cannot determine the output by looking.
Factory functions
A factory function can be defined as a function that creates an object and returns it. It is similar to constructor functions/class functions.
The factory function is a very useful tool in JavaScript since it returns the object of any class directly. We can also populate some fixed static values in these factory functions.
These functions do not require the use of the ‘this’ keyword for inner values. Also, they do not need the ‘new’ keyword when initiating new objects.
Factory functions can contain inner values, methods, and many more. They are just like normal functions but with a specific target i.e. to create objects. The only difference between a factory function and a normal function is that it returns an object with the assigned values.
<script>
// Function creating new objects
// without use of 'new' keyword
function createRobot(name) {
return {
name: name,
talk: function () {
console.log('My name is '
+ name + ', the robot.');
}
};
}
//Create a robot with name Chitti
const robo1 = createRobot('Chitti');
robo1.talk();
// Create a robot with name Chitti 2.O Upgraded
const robo2 = createRobot('Chitti 2.O Upgraded');
robo2.talk();
</script>
Closure
Most of the JavaScript Developers use closure consciously or unconsciously. Even if they do unconsciously it works fine in most of the cases. But knowing closure will provide better control over the code when using them. And another reason for learning closure is that it is the most frequently asked question in the interview for the JavaScript developers.
// Explanation of closure
/* 1 */ function foo()
/* 2 */ {
/* 3 */ var b = 1;
/* 4 */ function inner(){
/* 5 */ return b;
/* 6 */ }
/* 7 */ return inner;
/* 8 */ }
/* 9 */ var get_func_inner = foo();
/* 10 */ console.log(get_func_inner());
/* 11 */ console.log(get_func_inner());
/* 12 */ console.log(get_func_inner());
Explanation:Interesting thing to note here is from line number 9 to line number 12. At line number 9 we are done with the execution of function foo() and the entire body of function inner() is returned and stored in var get_func_inner, due to the line 7 return inner.
๋ชจ๋์๋ฐ์คํฌ๋ฆฝํธ deep dive - 24์ฅ closure
ํด๋ก์ ๋ ์๋ฐ์คํฌ๋ฆฝํธ ๊ณ ์ ์ ๊ฐ๋ ์ด ์๋๋ค. ํจ์๋ฅผ ์ผ๊ธ ๊ฐ์ฒด๋ก ์ทจ๊ธํ๋ ํจ์ํ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด(e.g. Haskell, Lisp, Erlnag, Scala)๋ฑ์์ ์ฌ์ฉ๋๋ ์ค์ํ ํน์ฑ์ด๋ค.
ํต์ฌ ํค์๋๋ "ํจ์๊ฐ ์ ์ธ๋ ๋ ์์ปฌ ํ๊ฒฝ"์ด๋ค.
์๋ฐ์คํฌ๋ฆฝํธ ์์ง์ ํจ์๋ฅผ ์ด๋์ ํธ์ถํ๋์ง๊ฐ ์๋๋ผ ํจ์๋ฅผ ์ด๋์ ์ ์ํ๋์ง์ ๋ฐ๋ผ ์์ ์ค์ฝํ๋ฅผ ๊ฒฐ์ ํ๋ค. ์ด๋ฅผ ๋ ์์ปฌ ์ค์ฝํ(์ ์ ์ค์ฝํ)๋ผ ํ๋ค. (lexical scope)
๋ ์์ปฌ ํ๊ฒฝ์ "์ธ๋ถ ๋ ์์ปฌ ํ๊ฒฝ์ ๋ํ ์ฐธ์กฐ"์ ์ ์ฅํ ์ฐธ์กฐ๊ฐ, ์ฆ ์์ ์ค์ฝํ์ ๋ํ ์ฐธ์กฐ๋ ํจ์ ์ ์๊ฐ ํ๊ฐ๋๋ ์์ ์ ํจ์๊ฐ ์ ์๋ ํ๊ฒฝ(์์น)์ ์ํด ๊ฒฐ์ ๋๋ค. ์ด๊ฒ์ด ๋ฐ๋ก ๋ ์์ปฌ ์ค์ฝํ์ด๋ค.
JavaScript, ํนํ ์ด์ ์คํฌ๋ฆฝํธ์์ "IIFE"๋ผ๋ ํจํด์ ์ฐพ์ ์ ์์ต๋๋ค. IIFE๋ "์ฆ์ ์คํ ํจ์ ํํ(Immediately Invoked Function Expression)"์ ๋ปํ๊ณ (์คํฌ๋ฆฝํธ ํ์ผ์์ ์ง์ ) ํ์ธํ ์ ์๋ ํจํด์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
(function() {
var age = 30;
console.log(age); // 30
})()
console.log(age); // Error: "age is not defined"
์ด๊ฒ์ ๋ฌด์์ผ๊น์?
์๊ธฐ ์์ ์ ํธ์ถํ๋ ํจ์ ํํ์์ ๋ณผ ์ ์์ต๋๋ค(ํจ์ ๋ฐ๋ก ๋ค์ () ๋ฅผ ์ฃผ๋ชฉํด ์ฃผ์ธ์).
() ๋ก ์ธ์ฌ์๊ธฐ ๋๋ฌธ์ ํจ์ ์ ์ธ์ ์๋๋๋ค - ์ด๋ ํจ์ ์ ์ธ์ ์ฆ์ ์คํํ ์ ์๊ธฐ ๋๋ฌธ์ ์๋์ ์ผ๋ก ์์ฑํ๋ ๊ฒ๋๋ค.
ํ์ง๋ง ์ด๋ฐ ์ฝ๋๋ฅผ ์ ์ฐ๋ ๊ฑธ๊น์?
์์ ์ค๋ํซ์ let ๋๋ const๊ฐ ์๋ var๋ฅผ ์ด ์ ์ ์ฃผ๋ชฉํด ์ฃผ์ธ์. var ๋ ๋ธ๋ก ์ค์ฝํ๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ์ ์ญ ์ค์ฝํ์ ํจ์ ์ค์ฝํ์์๋ง ๋ค๋ฅด๋ค๋ ์ ์ ๊ธฐ์ตํ์ธ์.
๊ฒฐ๊ณผ์ ์ผ๋ก ๋ณ์๋ฅผ ์ธ ์ ์๋ ์์น๋ฅผ ์ ์ดํ๊ธฐ๊ฐ ์ด๋ ค์ ์ต๋๋ค - ํจ์ ์ธ๋ถ์ ๋ณ์๋ ํญ์ ์ ์ญ์ ์ผ๋ก ์ฌ์ฉํ ์ ์์์ต๋๋ค. IIFE๋ ์คํฌ๋ฆฝํธ(๋๋ ๊ทธ ์ผ๋ถ)๊ฐ ํจ์๋ก ์ธ์ฌ์๊ธฐ ๋๋ฌธ์ ๊ทธ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํฉ๋๋ค => ํจ์ ์ค์ฝํ๊ฐ ์ฌ์ฉ๋ฉ๋๋ค.
์์ฆ์๋ ์ฌ์ฉ์ด ํ์์ ์ด์ง ์์ต๋๋ค. let ๊ณผ const ๋ฅผ ์ฌ์ฉํ๋ฉด ๋ธ๋ก ์ค์ฝํ๊ฐ ์๊ณ ๋ณ์๋ฅผ ์ฌ์ฉํ ์ ์๋ ์์น๋ฅผ ์ ํํ๋ ค๋ ๊ฒฝ์ฐ(ํจ์, if ๋ฌธ, for ๋ฃจํ ๋ฑ์ ์ธ๋ถ - ์ด๋ฌํ ๊ตฌ์กฐ๊ฐ ๋ธ๋ก์ ์์ฑํ๋ฏ๋ก ์๋์ผ๋ก ์ค์ฝํ๋ ๋ณ์๊ฐ ์์ต๋๋ค), ์ค์ฝํ๋ ๋ณ์๊ฐ ์์ด์ผ ํ๋ ์ฝ๋๋ฅผ {}๋ก ๊ฐ๋จํ ๊ฐ์ ์ ์์ต๋๋ค.
{
const age = 30;
console.log(age); // 30
}
console.log(age);// ์๋ฌ: "age๊ฐ ์ ์๋์ง ์์"
์์ฃผ ๋ณด์ด์ง ์๊ฒ ์ง๋ง ๋ฐ์ํ ์๋ ์์ต๋๋ค.
Recursion
A recursive function is a function that calls itself until it doesn’t. And this technique is called recursion.
Suppose that you have a function called recurse(). The recurse() is a recursive function if it calls itself inside its body, like this:
Code language: JavaScript (javascript)
A recursive function always has a condition to stop calling itself. Otherwise, it will call itself indefinitely. So a recursive function typically looks like the following:
Code language: JavaScript (javascript)
Generally, you use recursive functions to break down a big problem into smaller ones. Typically, you will find the recursive functions in data structures like binary trees and graphs and algorithms such as binary search and quicksort.
JavaScript recursive function examples
Let’s take some examples of using recursive functions.
A simple JavaScript recursive function example
Suppose that you need to develop a function that counts down from a specified number to 1. For example, to count down from 3 to 1:
3
2
1
The following shows the countDown() function:
function countDown(fromNumber) {
console.log(fromNumber);
}
countDown(3);
This countDown(3) shows only the number 3.
To count down from the number 3 to 1, you can:
- show the number 3.
- and call the countDown(2) that shows the number 2.
- and call the countDown(1) that shows the number 1.
The following changes the countDown() to a recursive function:
function countDown(fromNumber) {
console.log(fromNumber);
countDown(fromNumber-1);
}
countDown(3);
This countDown(3) will run until the call stack size is exceeded, like this:
Uncaught RangeError: Maximum call stack size exceeded.
… because it doesn’t have the condition to stop calling itself.
The count down will stop when the next number is zero. Therefore, you add an if condition as follows:
function countDown(fromNumber) {
console.log(fromNumber);
let nextNumber = fromNumber - 1;
if (nextNumber > 0) {
countDown(nextNumber);
}
}
countDown(3);
Output:
3
2
1
The countDown() seems to work as expected.
๋ค์ ํจ์๋ ์์ ํจ์์ผ๊น์?
let defaultValue = 10;
function addNumber(num) {
return num + defaultValue;
}
-
defaultValue๊ฐ ๋ณ๊ฒฝ๋์ง ์๋ ํ ๊ทธ๋ ์ต๋๋ค.
-
๋ค, ํญ์ ๊ทธ๋ ์ต๋๋ค.
-
์๋์ค - ๋์ผํ ์ถ๋ ฅ์ ์์ ์ ์ผ๋ก ์ฐ์ถํ์ง ์์ต๋๋ค.
defaultValue๋ ์ธ๋ถ ๋ณ์์ด๋ฏ๋ก ํจ์๊ฐ ํญ์ ๋์ผํ ๊ฒฐ๊ณผ๋ฅผ ์ฐ์ถํ๋ค๊ณ ๋ณด์ฅํ ์๋ ์์ต๋๋ค.
ํจ์์ "๋ถ์์ฉ"์ด ์๋ ๊ฒฝ์ฐ๋ ์ด๋ค ๊ฒฝ์ฐ์ผ๊น์?
-
ํจ์๋ ๋์ผํ ์ ๋ ฅ์ผ๋ก ํธ์ถ๋ ๋ ๋ค๋ฅธ ๊ฒฐ๊ณผ๋ฅผ ์์ฑํฉ๋๋ค - ์ ๋ ฅ์ด ์๋ ๋ค๋ฅธ ๊ฒ์ ์์กดํ๋ ๊ฒ ๊ฐ์ต๋๋ค.
-
ํจ์๋ ํจ์ ์ธ๋ถ์ ๋ฌด์ธ๊ฐ์ ์ํธ์์ฉํ๊ฑฐ๋ ๋ด๋ถ ๊ณ์ฐ๊ณผ ์ง์ ๊ด๋ จ์ด ์๋ ์์ ์ ์ํํฉ๋๋ค.
-
์์ํ์ง ์์ ํจ์๋ ๋ถ์์ฉ์ด ์๋ ํจ์์ ๋๋ค.
๋ชจ๋ ํจ์์ "ํด๋ก์ "๋ ๋ฌด์์ผ๊น์?
-
์ ๋ ฅ๋ ๋งค๊ฐ๋ณ์๋ฅผ ๊ธฐ์ตํ๊ณ ์ ์ฒด ์คํ ๋์ ์ ์งํ๊ธฐ ๋๋ฌธ์ ๋๋ค.
-
์ฃผ๋ณ ํ๊ฒฝ๊ณผ ๊ทธ ํ๊ฒฝ์ ๋ณ์๋ฅผ ๊ธฐ์ตํ๊ธฐ ๋๋ฌธ์ ๋๋ค.
-
๋ชจ๋ ํจ์๋ ๋ด๋ถ("์ค์ฒฉ") ํจ์๋ฅผ ํฌํจํ ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค.
ํจ์๊ฐ ์ฌ๊ท ํจ์์ธ ๊ฒฝ์ฐ๋ ์ด๋ค ๊ฒฝ์ฐ์ผ๊น์?
-
์ด๋ค ํจ์๋ฅผ ํธ์ถํ๋ ๊ฒฝ์ฐ.
-
์๊ธฐ ์์ ์ ํธ์ถํ์ง ์๋ ๊ฒฝ์ฐ.
-
์๊ธฐ ์์ ์ ํธ์ถํ๋ ๊ฒฝ์ฐ.
Sources
https://www.syncfusion.com/blogs/post/pure-and-impure-functions-in-javascript-a-complete-guide.aspx
Pure and Impure Functions in JavaScript: A Complete Guide
In this article, I will discuss pure and impure JavaScript functions in-depth and highlight their uses, advantages, and differences.
www.syncfusion.com
https://www.geeksforgeeks.org/what-are-factory-functions-in-javascript/
What are factory functions in JavaScript ? - GeeksforGeeks
A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.
www.geeksforgeeks.org
https://www.geeksforgeeks.org/closure-in-javascript/
Closure in JavaScript - GeeksforGeeks
A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.
www.geeksforgeeks.org
๋ชจ๋ ์๋ฐ์คํฌ๋ฆฝํธ Deep Dive
์ด์ ๋ชจ ์ผ๋ณธ์์ ์ปดํจํฐ๊ณตํ์ ์ ๊ณตํ ํ ์ผ๋ณธ์ ์๋์ฐจ ์ฐ๊ตฌ์ ๊ณต์ฉ ์น ํ๋ ์์ํฌ ๊ฐ๋ฐ ํ๋ก์ ํธ๋ฅผ ์์์ผ๋ก ํ๋ก๊ทธ๋๋ฐ ์ธ๊ณ์ ๋ฐ์ ๋ค์ฌ ๋์๋ค. ์ดํ ์ธ๊ตญ๊ณ IT ๊ธฐ์ ์์ ์ํํธ์จ์ด ์ปจ์ค
books.google.co.jp