In JavaScript, functions are one of the fundamental concepts, and I've discussed them in the past blogs. As we know, a function is like a black box: we provide input and get an expected result without needing to understand its internal structure. Given the same input, a function will always produce the same output.
JavaScript has eight data types: string
, number
, bigint
, boolean
, undefined
, null
, symbol
, and object
. Functions are indeed part of the object type, specifically as Function objects. As such, they inherit properties defined on Function.prototype
.
Today, I'll cover the following:
- Function.name
- Function.length
- Polymorphism
- Named Function Expression (NFE)
Function.name
The name data property of a Function instance indicates the function's name as specified when it was created, or it may be either anonymous or '' (an empty string) for functions created anonymously.
These examples are from MDN:
function doSomething() {}
doSomething.name; // "doSomething"
Read-only:
function someFunction() {}
someFunction.name = "otherFunction";
console.log(someFunction.name); // someFunction
new Function().name; // "anonymous"
const someFunction = function someFunctionName() {};
someFunction.name; // "someFunctionName"
(function () {}).name; // ""
(() => {}).name; // ""
The name property is read-only and is primarily used for debugging and error messages.
Function.length
Specifies the number of arguments expected by the function.
Let's learn using the modified examples based on MDN:
function.length
returns the number of arguments as a number:
function fn() {}
console.log(fn.length); // 0
function fn(a) {}
console.log(fn.length); // 1
function fn(a, b) {}
console.log(fn.length); // 2
A rest parameter is not counted:
function fn(...args) {}
console.log(fn.length); // 0
function fn(a, b, ...args) {}
console.log(fn.length); // 2
The .length
property only counts the parameters before the first default value.
function fn(a, b = 1, c) {}
console.log(fn.length); // 1
Each destructuring pattern is considered one parameter:
function fn({ a, b }, [c, d]) {}
console.log(fn.length); // 2
// { a, b } + [c, d] = 2
The Modern JavaScript Tutorial provides an example that may seem a little complicated:
function ask(question, ...handlers) {
let isYes = confirm(question);
for(let handler of handlers) {
if (handler.length == 0) {
if (isYes) handler();
} else {
handler(isYes);
}
}
}
// for positive answer, both handlers are called
// for negative answer, only the second one
ask("Question?", () => alert('You said yes'), result => alert(result));
This ask
function takes a question
argument and an unspecified number of handler
functions. The handlers
can either take zero arguments or one argument. The handler.length
property is used in the if
condition to determine which handler to call.
This is an example of polymorphism.
Polymorphism
Polymorphism in JavaScript is the ability of a function, method, or object to take multiple forms, allowing the same method name to be used for different implementations depending on the object or class.
There are two types: Method Overriding and Method Overloading.
In the ask
function, Method Overloading is used.
Method Overloading (simulated): A function behaves differently based on the number or type of its arguments.
Geeks for Geeks
In the ask
function, the same function name (handler
) is used for different implementations depending on the number of arguments, which is determined by the .length
property.
Named Function Expression (NFE)
Named Function Expression, or NFE, is a term for Function Expressions that have a name.
The Modern JavaScript Tutorial
When we assign a function to a variable, we can skip naming the function. We can even use an arrow function.
const example = function () {};
const example = () => {};
When we add a name to a function, it is called a Named Function Expression.
const example = function exampleFn () {};
Use case of NFE:
According to The Modern JavaScript Tutorial,
- It allows the function to reference itself internally.
- It is not visible outside of the function.
let sayHi = function(who) {
if (who) {
alert(`Hello, ${who}`);
} else {
sayHi("Guest"); // Error: sayHi is not a function
}
};
let welcome = sayHi;
sayHi = null;
welcome(); // Error, the nested sayHi call doesn't work any more!
As I mentioned in a previous blog, JavaScript uses a lexical environment, so it tries to find a reference in the outer environment. However, when sayHi
is called, the variable has been changed.
The following code works because it always references func
:
let sayHi = function func(who) {
if (who) {
alert(`Hello, ${who}`);
} else {
func("Guest"); // Now all fine
}
};
let welcome = sayHi;
sayHi = null;
welcome(); // Hello, Guest (nested call works)
Although Function.length
and Function.name
may not be frequently used in our code, understanding them deeply will enhance our skills as developers.
Top comments (0)