TESTING AREA for teachers - real service at plus.tuni.fi
- COMP.CS.200
- 15. ワークショップ (WORKSHOP) 12.06.2025
- 15.3 Functional JavaScript
Functional JavaScript¶
What is functional programming?¶
Functional Programming (FP) is a programming paradigm that models computation as the evaluation of mathematical functions. It avoids changing state and mutable data. At its core, FP relies on functions as the fundamental building blocks of your code, rather than imperative sequences of commands.
Functions are essential to both functional programming and algorithms. In algorithm design, one often decomposes complex tasks into smaller, reusable functions. Alongside functions, data structures,the way data is organized and stored,play a vital role. FP typically handles data differently by enforcing immutability: once data is created, it doesn’t change. If modifications are needed, a new copy of the data is produced.
This makes programs more predictable and easier to debug.
The connection to math¶
Functions are central to mathematics as well. This concept carries over to computing, where computational thinking builds on mathematical foundations. The transition from solving mathematical problems to solving computational ones is natural and often seamless.
See the figure “The learning trajectory of CT” for more:
Functional programming in JavaScript¶
There exist some “pure” FP languages like Haskell and Elm. JavaScript is not pure FP language but it can be used like one. We can write JavaScript code that follows the principles of functional programming, and we can use libraries that help us to write functional code. By now, you have learned a little about JavaScript functions. Next, we will go through JavaScript code samples that concentrate on these functional features in particular.
Key characteristics of functional programming¶
1. Immutable data: You do not ever change a value of a variable. Let’s say that you have a chair object. This chair defines a property of its current location. If you want to move the chair object, you create a copy of the old chair and replace the old location with a new one. Sounds like a lot of work, but it makes tracking bugs way simpler, therefore the total amount of work may decrease.
Tips:
Prefer const over let
Use Object.freeze
Consider libraries like Immutable.js for larger applications
2. Pure functions:
cause no side-effects such as
console.log()
, API calls, or global data modifications,return always the same output for the same input
In which situations can a function return a different value for the same parameters?
For example, if some conditions depend on global variables that can be muted in an outer scope.
If you are using
Math.random
Although pure sounds better than impure, impurity is necessary for interacting with an impure world, for example, with a user. You cannot build a functional web site with only pure functions. If you were to use only pure functions you could not:
manipulate the DOM,
fetch data from a server, or
send data to a server.
Thus, both function types play an important role in web development. Yet separating functionality to pure business logic and impure functionality (data fetching, DOM manipulation etc.) might be a good idea. This way you could ensure that your business logic is easily testable and re-factorable. Business logic mixed with side-effects make modifying applications much more demanding.
Tips:
Once a function is tested, remove
console.log
debug printsDo not directly mutate data passed to your function. Create a copy, modify it and return the modified copy.
Do not access any values outside of your function
Always
return
what was modified inside functionSeparate side-effects to their own functions
3. Higher-order functions: Functions
in JavaScript are objects
.
What this means in practice is that you can assign a function to
a variable, to array elements, or to an object. In addition, as an object,
function has its own prototype property with a value Function.prototype
.
Function.prototype defines three functions: call()
, bind()
, apply()
.
const greet = (name) => console.log(`Greetings, ${name}`);
greet("Snow White"); // Greetings, Snow White
In the example above, we pass a string as a parameter to the function greet
.
Instead of a string, we could also pass a function as a parameter.
const sayHi = () => console.log("Hi!");
const sayHello = () => console.log("Hello");
const greet = (type, sayHi, sayHello) => type === "Hi" ? sayHi() : sayHello();
greet("Hi", sayHi, sayHello); // Hi!
greet("Hello", sayHi, sayHello); // Hello
[The syntax ? :
used in the previous example is called
ternary operator.
It’s basically a shorter version of if-else
.]
Here, we could say that the function greet()
is a higher-order function,
because it takes a function as a parameter. Passing functions as parameters implies
also that functions are first-class citizens
in the language.
Attention
When passing a function as a parameter, you are not calling the function and therefore you omit the parentheses (and possible arguments) and only pass the name of the function. Calling the function actually returns what the function returns and then passes that return value to the higher-order function.
const sayHi = () => console.log("Hi!");
const sayHello = () => console.log("Hello");
const greet = (type, sayHi, sayHello) => type === "Hi" ? sayHi() : sayHello();
greet("Hi", sayHi, sayHello); // pass in functions
greet("Hello", sayHi(), sayHello()); // pass in results of the functions "Hi!" and "Hello"
4. Function composition: Function composition is used in combining multiple simple functions into a more complex one. Function composition is an example of using higher-order functions. The result of each function is passed as a parameter to the next one. We define two functions: the first function adds 2 to the parameter, and the other one multiplies by it 2.
const add2 = n => n + 2;
const times2 = n => n * 2;
Now these functions can be used and re-used in multiple places and one could even apply the functions in different order or multiple times to produce different end results.
console.log(add2(times2(5))); // 12
console.log(times2(add2(5))); // 14
console.log(add2(times2(add2(5)))); // 16
console.log(times2(add2(times2(5)))); // 24
What if we had to write something like this?
const accessRights = a(b(c(d(e(f(g("Snow White")))))));
Pure functions enable function compositions to be as long as we wish, provided that output of the previous function is the anticipated input of the next function in a chain.
Tips:
In real scenario you would rather a separate compose function by using libraries like Lodash.
Exercises¶
In the following short exercises, the goal is to differentiate pure functions from impure.