For other translations of this series, see [JS Working Mechanism – Xiaobai 1991 column – Nuggets (juejin.cn)] (juejin.cn/column/6988…
There is a market for functional programming, but so far there has been much talk and little action. This article helps you understand some of the basic concepts of functional programming.
An overview of the
Functional programming, in simple terms, is a function, the input parameters are data, the output parameters are functions.
The great thing about functional programming is that it doesn’t change our input parameters or cause any side effects. State values are expressed as functions.
In this chapter we’ll discuss how functional programming works in JS and some of the important concepts associated with it.
Object oriented JS
First, we know that JS is a prototype-based language, not a class-based language, and this model often confuses developers. Class-based languages, such as JAVA,C#, etc., have two main concepts: classes and instances. A class defines all the properties of an object, and an instance instantiates the class.
The object oriented style of JS just looks like it, but it’s not. It looks like you’re using a class syntax, but it’s actually a prototype
Such as:
let Person = class {
constructor(name, age) {
this.name = name;
this.age = age;
}
speak() {
return `Hello, my name is ${this.name} and I am ${this.age}`
}
}
Copy the code
Notice that the Person class constructor takes two arguments. The keyword this points to our prototype, Person. Our method speak() can be used like this:
let victor = new Person('Victor', 23);
console.log(victor.speak());
Copy the code
The new Person will call the constructor, and the arguments passed in will be set to the Victor object. The speak() function is added to the prototype of the constructor.
We can also create a new class outside of the Person class that extends its properties and methods
let Work = class extends Person {
constructor(name, age, work) {
super(name, age);
this.work = work
}
getInfo() {
return `Hey! It's ${this.name}, I am age ${this.age} and work for ${this.work}.`
}
}
let alex = new Work('Alex', 30, 'SessionStack');
console.log(alex.getInfo());
Copy the code
We’ve created a class that inherits from Person and defines more properties. In class-based languages, it is called a subclass.
What do I do if I’m using an older version of JS? Remember that the class syntax in JS is actually still prototype-based. Let’s see what happens:
let Person = function(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.speak = function() {
return `Hello, my name is ${this.name} and I am ${this.age}`
}
let victor = new Person(`Victor`, 23)
console.log(victor.speak())
Copy the code
In the above code, we’re calling the Person() function, with the keyword new before it. New changes the context of the function, so it is called a constructor. It generates an instance of the Person object and assigns it to Victor. To implement inheritance from Person as above, we can do this:
let Work = function(name, age, work) {
Person.call(this, name, age);
this.work = work;
}
Copy the code
Note that we didn’t use the super() keyword because it doesn’t exist in JS. Call () takes this and other parameters, and then adds the properties of Person to the Workshang. The.call() method, which connects the Person constructor to the Work class. In other words, we borrowed the property from Person and added it to Work.
In archetypes, there is no such syntax as extend. But you can connect Work and Person this way
Object.setPropertyOf(Work.prototype, Person.prototype);
Copy the code
This allows Work to use the Person property. To add a method to work, do this:
Work.prototype.getInfo = function() {
return `Hey! It's ${this.name}, I am age ${this.age} and work for ${this.work}.`
}
let alex = new Work("Alex", 40, 'SessionStack');
console.log(alex.getInfo());
Copy the code
We need to know that JS is an object language implemented based on a prototype, and we use the class syntax in ES6, which is just a syntax sugar.
With that in mind, let’s take a look at functional programming in JS:
What is functional programming
Using functional programming in JS is easier, but not for all developers. Since JS itself is a prototype-based language, its’ run inheritance ‘, ‘this’,’ setPropertyOf ‘are already confusing.
However, the functional approach in JS makes things a little easier and a little more maintainable than using the wrong ‘this’ banding. There are a lot of community members who use functional programming, and you can get a lot of help by turning to StackOverflow when you have a problem.
Look at a simple functional code:
const sayHello = function(name) {
return `Hello ${name}`;
}
sayHello('Victor');
# => Hello Victor
Copy the code
We declare a function that takes a name. Very simple and clear.
But functional programming is a little more complicated, and we need to understand some concepts: pure functions, higher-order functions, immutability, first class functions, etc.,
Functional programming concepts in JS
Pure functions
One of the main goals of functional programming is to use pure functions and avoid side effects. No side effects means that the logic of your function depends only on the parameters passed in. Let’s start with an impure function that has side effects,
let surname = 'Jonah';
const sayHi = function() {
return `Hi ${surname}`;
}
Copy the code
In the above code, there are no input arguments, but a global variable outside of the function is used. This can cause side effects.
To transform it into a pure function:
const sayHi = function(surname) {
return `Hi ${surname}`;
}
Copy the code
Now the function only cares about the input parameter and handles it. This is a pure function. This is the most important concept of functional programming. There are some other little concepts to know
Higher-order functions
A higher order function is a function, is it a function, is it a function, is it a function, is it a function, remember functions are values, they can be passed around. Such as:
const getSum = function(num) {
return num + num;
}
getSum(9);
Copy the code
We create a function and assign it to getSum. We can also pass it to another variable, such as:
const addNum = getSum;
addNum(9);
Copy the code
As you can see, functions can be passed as variables. Therefore, they can also be passed as arguments to higher-order functions.
We can keep passing functions into other functions, so let’s take a bunch of small functions and combine them into one big function. This is called a combination.
function a(x) {
return x * 2;
}
function b(x) {
return x + 1;
}
function c(x) {
return x * 3;
}
const d = c(b(a(2)));
console.log(d) // 15
Copy the code
We can pass the return value of each function into the next function. That’s why we use higher-order functions, because they use combinations and make our code cleaner
A common example of a higher-order function is the filter() method. Filter () needs to be passed in a function that returns a new array. Such as:
function isLarge(value) { return value > 10; } const dataArray = [10, 11, 12, 3, 4]; const filteredArray = dataArray.filter(isLarge); console.log(filteredArray); / / [11, 12]Copy the code
The callback function must return a Boolean value; if true, the value currently traversed is added to the new array. Similar examples include the map() and Reduce () methods. Before starting the next section, let’s look at the map() method:
function squareRoot(value) { return Math.sqrt(value) } const dataArray = [4, 9, 16]; const mappedArray = dataArray.map(squareRoot); console.log(mappedArray); / / [2, 3, 4]Copy the code
immutability
Another important overview of functional programming is the rejection of variance. A variation is a change in state or data. Immutable means that the original data cannot be changed, and when a change occurs, a new object needs to be set. Look at a variant code:
let data = [1, 2, 3, 4, 4];
data[4] = 5;
console.log(data); // [1, 2, 3, 4, 5]
Copy the code
Notice we changed 1, 2, 3, 4, 4 to 1, 2, 3, 4, 5. This code may cause some bugs. Let’s say this array is being used somewhere, but it’s actually changed. So how do you deal with immutability in JS?
const names = ["Alex", "Victor", "John", "Linda"]
const newNamesArray = names.slice(1, 3) // ["Victor", "John"]
Copy the code
The source array NAMES is not changed, and a new piece of data is generated.
Use object.freeze () to make objects immutable as well. This method freezes the object and does not allow properties to be added or removed from the object.
Such as:
const employee = {
name: "Victor",
designation: "Writer",
address: {
city: "Lagos"
}
};
Object.freeze(employee);
employee.name = "Max"
//Outputs: Cannot assign to read-only property 'name'
//Checks if our object is immutable or not
Object.isFrozen(employee); // === true
Copy the code
Here, our object is immutable and cannot interact with it. The problem with this is that we have to discard the old array over and over again if we want to change it. If there are thousands of pieces of data in the array, the memory consumption and problems can be huge. There are libraries to help us with these problems, such as immutable. Js and Mori.
With these concepts in mind, we already know the concepts and benefits of functional programming in JS. You can see that our code is much easier to read,
Declarative and imperative
There are two approaches to functional programming: declarative and imperative. An imperative is a statement of what you are going to do. For example, if you want to make steamed buns, then the command would look like this
- and
- Chop the stuffing
- The package steamed stuffed bun
- steamed
Declarative is just saying what you want to do. For example, if you want to make baozi, that’s it. We don’t need to describe every step. But these are just brief descriptions to tell you the difference.
Command:
Here we’re going to tell the computer what are we going to do
// Function to filter an array; return greater than 5 numbers
const filterArray = (array) => {
let filteredArray = [];
for(let i = 0; i < array.length; i++) {
if(array[i] > 5) {
filteredArray.push(array[i]);
}
}
return filteredArray;
}
const array = [1, 2, 3, 4, 5, 6, 7, 8]
filterArray(array)
Copy the code
We don’t tell the computer what we want, we just tell us what to do every step of the way. Our steps include:
- Declare an empty array
- Iterating over a given array
- If the current entry is greater than 5
- If it is greater than 5, the matching item is added to the previously declared empty array
- Display our new array
Declarative:
// Filter method to give us a new array const filterArray = array => array.filter(x => x > 5); const array = [1, 2, 3, 4, 5, 6, 7, 8]; console.log(filterArray(array)); / / [6, 7, 8]Copy the code
Declarative is simple, we declare a function, and we let it do what we want it to do.
Why do most people recommend functional programming
Developers choose to use functional programming for several common reasons. At the same time, functional programming can be tricky to learn at first, but once you fully understand the concept, it becomes easy. Here are some of the main reasons:
- Making the code more modular; A function can be combined with another completely unrelated function. Because functions are composable, like the React component, they can be reused well.
- Debugging is easier: fewer bugs, better maintainability. Higher-order functions are easier to debug, and with less code, our code is safer.
- It’s easier for developers to read your code. Because you’re writing code in a human way, not a procedural way.
- In functional programming, developers tend to write cleaner, faster code. Instead of iterating through code, like a for loop.
conclusion
In this chapter, we take an overview of how OBJECT-ORIENTED JS works, the class syntax and the traditional prototype-based differences.
Introduces some functional programming concepts to help you understand why you use functional programming.
There is no better or worse programming model. This chapter is just to help you understand the concepts of functional programming.