JavaScript Functions
Last updated:
A function is a group of instructions that together perform a task; it is defined once and can be used (i.e. called) as many times as needed.
Declaring a function
function sayHello(firstname) {
return "Hello " + firstname;
}
Using a function:
sayHello("Paul"); // returns: "Hello Paul"
Returned value
Always returns a value; if nothing is specified, undefined
is returned:
function sayHello(firstname) {
console.log("Hello " + firstname);
}
console.log(sayHello("Paul")); // Outputs: undefined
Default arguments
function sayHello1(firstname) {
return "Hello " + firstname;
}
console.log(sayHello1()); // Outputs: "Hello undefined"
function sayHello2(firstname = "World") {
return "Hello " + firstname;
}
console.log(sayHello2()); // Outputs: "Hello World"
arguments
object
A special arguments
object holds a list of all arguments passed to a JavaScript function even if none are specified in its definition.</p>
function sayHello(firstname, site) {
console.log(`Hello ${firstname} from ${site}!`);
}
sayHello("Paul", "pardel.dev"); // returns: "Hello Paul from pardel.dev!"
function sayHello() {
console.log(arguments);
}
sayHello("Paul", "pardel.dev"); // returns: [Arguments] { '0': 'Paul', '1': 'pardel.dev' }
console.log(typeof arguments); // Outputs: object
We can check how many were passed and even list all arguments:
function sayHello() {
console.log(arguments.length);
for(let arg of arguments) {
console.log(arg);
}
}
sayHello("Paul", "pardel.dev");
// Outputs:
// 2
// Paul
// pardel.dev
Using arguments
function sayHello() {
console.log(`Hello ${arguments[0]} from ${arguments[1]}!`);
}
sayHello("Paul", "pardel.dev"); // returns: "Hello Paul from pardel.dev!"
Can be modified on the fly:
function sayHello() {
arguments[0] = "World";
console.log(`Hello ${arguments[0]} from ${arguments[1]}!`);
}
sayHello("Paul", "pardel.dev"); // Outputs: "Hello World from pardel.dev!"
Anonymous functions
A function without a name:
let sayHello = function(firstname) {
return "Hello " + firstname;
}
console.log(sayHello("Paul")); // Outputs: "Hello Paul"
Functions as parameters
setTimeout(function sayHello() {
console.log("Hello World");
}, 1000);
sayHello(); // returns: "ReferenceError: sayHello is not defined"
setTimeout(function() {
console.log("Hello World");
}, 1000);
Nameless functions that are used extensively in methods that take function parameters:
let myArray = [1, 4, 42, 11, 79];
let doubleArray = myArray.map(function (item) {
return item * 2;
});
console.log(doubleArray); // returns: [2, 8, 84, 22, 158]
Arrow functions
Provide a more concise way to write functions:
let myArray = [1, 4, 42, 11, 79];
let doubleArray = myArray.map( item => {
return item * 2;
});
console.log(doubleArray); // returns: [2, 8, 84, 22, 158]
Limitations:
- no own bindings -
this
orsuper
is not available yield
cannot be used insite them
Usage: DOM elements management
e.g: triggering actions when a button is clicked is now as simple as:
let signupButton = document.getElementById("signup");
signupButton.click(event => {
console.log(`New signup: ${signupButton}`);
});
Variadic Functions
Accept an arbitrary number of arguments when called - provides flexibility and convenience, particularly when working with functions that require varying numbers of inputs.
rest operator
The rest syntax is denoted by three dots (…) before the function parameter name:
function sum(...numbers) {
return numbers.reduce((total, current) => total + current, 0);
}
function multiply(...numbers) {
return numbers.reduce((total, current) => total * current, 1);
}
console.log(sum(1, 2, 3, 4, 5, 6)); // returns: 21
console.log(multiply(1, 2, 3, 4, 5, 6)); // returns: 720
Usage: Variable Number of Parameters
function greet(greeting, ...names) {
names.forEach(name => console.log(`${greeting}, ${name}!`));
}
greet('Good morning', 'Alice', 'Bob', 'Charlie');
// Outputs:
// Good morning, Alice!
// Good morning, Bob!
// Good morning, Charlie!
Usage: Merging arrays
function mergeArrays(arr1, arr2, ...rest) {
return [...arr1, ...arr2, ...rest];
}
const array1 = [1, 2, 3];
const array2 = [4, 5, 6];
const array3 = [7, 8, 9];
const mergedArray = mergeArrays(array1, array2, ...array3);
console.log(mergedArray); // Outputs: [1, 2, 3, 4, 5, 6, 7, 8, 9]
A slightly simpler version of mergeArrays:
function mergeArrays(...arrays) {
return [].concat(...arrays);
}
const array1 = [1, 2, 3];
const array2 = [4, 5, 6];
const array3 = [7, 8, 9];
const mergedArray = mergeArrays(array1, array2, array3);
console.log(mergedArray); // Outputs: [1, 2, 3, 4, 5, 6, 7, 8, 9]
Usage: Sorting by multiple properties
function sortByProperties(property, ...rest) {
return function (a, b) {
if (a[property] < b[property]) {
return -1;
} else if (a[property] > b[property]) {
return 1;
} else {
if (rest.length === 0) {
return 0;
} else {
const [nextProperty, ...remainingProperties] = rest;
return sortByProperties(nextProperty, ...remainingProperties)(a, b);
}
}
};
}
const people = [
{ name: 'Alice', age: 30, city: 'New York' },
{ name: 'Bob', age: 30, city: 'San Francisco' },
{ name: 'Charlie', age: 25, city: 'London' },
];
const sortedPeople = people.sort(sortByProperties('age', 'city', 'name'));
console.log(sortedPeople);
// Outputs:
// [
// { name: 'Charlie', age: 25, city: 'London' },
// { name: 'Alice', age: 30, city: 'New York' },
// { name: 'Bob', age: 30, city: 'San Francisco' }
// ]
Usage: Dynamic object property assignment
function createPerson(name, age, ...extra) {
const person = {
name,
age,
};
for (const prop in extra) {
person[prop] = extra[prop];
}
return person;
}
const person = createPerson("Charlie", 30,
{ city: "London", country: "UK" });
console.log(person);
// Outputs: { '0': { city: 'London', country: 'UK' }, name: 'Charlie', age: 30 }
IIFE (Immediately Invoked Function Expression)
A design pattern that allows one to define and execute a function immediately upon its declaration. It’s a way of creating and running a function without explicitly naming or calling it:
(function() {
console.log('Hello World!');
})();
NB: Notice the final pair of parentheses:
()
- these parentheses are what actually call and execute the function.
Usage:Counter Module
A simple counter module that exposes methods to increment and display the current count, without exposing the internal count variable:
const counter = (function() {
let count = 0;
let step = 1;
function increment(newStep) {
if(newStep) { step = newStep; }
count += step;
}
function display() {
console.log(`Current count: ${count}`);
}
return {
increment,
display
};
})();
counter.increment();
counter.display(); // Outputs: "Current count: 1"
counter.increment(3);
counter.display(); // Outputs: "Current count: 4"
counter.increment();
counter.display(); // Outputs: "Current count: 7"
Usage: One-time Event Listener
Add an event listener to a button that should only execute once and then remove itself:
<button id="myBtn">One time action</button>
(function() {
const btn = document.getElementById('myBtn');
if(!btn) { return; }
function handleClick() {
console.log('One time click done!');
btn.removeEventListener('click', handleClick);
}
btn.addEventListener('click', handleClick);
})();
Usage: Configuration Setup
const config = {};
(function() {
function setDefaults() {
config.apiKey = 'YOUR_API_KEY';
config.apiUrl = 'https://api.example.com';
config.timeout = 5000;
}
// Initial config processing
function processSettings() {
console.log(`Configuring with API key: ${config.apiKey}`);
}
setDefaults();
processSettings();
})();
console.log(config);
// prints: { apiKey: 'YOUR_API_KEY',
// apiUrl: 'https://api.example.com',
// timeout: 5000 }
Why Use IIFE?
- encapsulation and scoping: IIFE creates a new scope, which means any variables declared within the function will not be accessible outside of it. This can help prevent variable name collisions and keeps the global scope clean.
- privacy: Since variables and functions declared inside an IIFE are not accessible from outside, they remain private. This is useful when you want to create a module or a piece of code with a well-defined interface while hiding its internal implementation details.
- self-contained code: IIFE can be useful when you want to create a self-contained piece of code that doesn’t rely on external variables or functions. This can be helpful for code organization and maintainability.
Built-in Functions
Extensive collection of built-in functions:
Generic
-
isNaN
- check is an expression is Not a Number:isNaN("Hello"); // returns: true isNaN(42); // returns: false isNaN(NaN); // returns: true isNaN(undefined); // returns: true isNaN(null); // returns: false
-
eval
- evaluates a string as JavaScript code and executes it; should be used with caution, due to security risks if used with untrusted input:eval("2 + 5"); // returns: 7 eval("console.log('Hello World!');"); // Outputs: Hello World!
-
parseInt
- converts a string into an integer; takes an optional base to be used for conversion:parseInt("42"); // returns: 42 parseInt("42 apples"); // returns: 42 parseInt("apples 42"); // returns: NaN parseInt("101010",2); // returns: 42 parseInt("101010",16); // returns: 1052688
-
parseFloat
- converts a string into a floating-point number:parseFloat("42"); // returns: 42 parseFloat("42.1"); // returns: 42.1 parseFloat("42.1 C"); // returns: 42.1 parseFloat("C 42.1"); // returns: NaN
Object Prototype
assign
- copy values from one or more source objects to a target objectcreate
- creates a new object with the specified prototype object and propertieskeys
- returns an array of a given object’s property namesvalues
- returns an array of a given object’s property values-
entries
- returns an array of a given object’s own enumerable property [key, value] pairsconst target = { a: 1 }; const source1 = { b: 2 }; const source2 = { c: 3 }; const result = Object.assign(target, source1, source2); console.log(result); // Outputs: { a: 1, b: 2, c: 3 } Object.keys(result); // returns: ['a', 'b', 'c'] Object.values(result); // returns: [1, 2, 3] Object.entries(result); // returns: [['a', 1], ['b', 2], ['c', 3]] Object.freeze(result); result.a = 2; // This assignment will be silently ignored console.log(result.a); // Outputs: 1
-
freeze
- freezes an object, preventing any changes to its propertiesconst result = { a: 1, b: 2, c: 3 }; Object.freeze(result); result.a = 2; // This assignment will be silently ignored console.log(result.a); // 1
-
seal
- seals an object, preventing any new properties from being added to it and existing properties from being removed:const result = { a: 1, b: 2, c: 3 }; Object.seal(result); result.a = 2; // This assignment is allowed delete result.b; // returns: false result.d = 5; // silently ignored console.log(result); // Outputs: { a: 2, b: 2, c: 3 }
Math
Math.round()
- rounds to nearest integer.Math.floor()
- rounds downward to nearest integer.Math.ceil()
- rounds a number upward to the nearest integer.Math.random()
- returns a random number between 0 and 1.Math.min()
and Math.max() - return the minimum and maximum values among the arguments, respectively.
Date
Date.now()
- returns number of milliseconds elapsed since January 1, 1970, 00:00:00 UTC.getDate()
- returns the day of the month for the specified date.getMonth()
- returns the month for the specified date.getFullYear()
- returns the year for the specified date.setTime()
- sets the date and time by adding or subtracting a specified number of milliseconds to/from midnight January 1, 1970.
JSON
JSON.parse()
- parses a JSON string and converts it into a JavaScript object.JSON.stringify()
- converts a JavaScript object or value to a JSON string.