Functions — Key thing of JavaScript
As we all know JavaScript is functional programming language, So it is very important to know about the functions. So let’s understand the functions in JavaScript.
Generally speaking, a function is a “subprogram” that can be called by code external to the function. Like the program itself, a function is composed of a sequence of statements called the function body. Values can be passed to a function, and the function will return a value.
To return a value other than the default, a function must have a return statement that specifies the value to return. A function without a return statement will return a default value. The default return value is undefined.
The parameters of a function call are the function’s arguments. Arguments are passed to functions by value. That means if the function changes the value of an argument, this change is not reflected globally or in the calling function.
let score = 99;/* Declare the function 'increase' */
function increaseScore (score) {
return score = 99 + 1;
}/* Pass by value to the function */
increaseScore(score);/*
* Logs '99' as the value of the variable 'score',
* because the argument was passed by value not by reference.
*/
console.log(score);
However, If we pass object in the argument then it will be pass to functions by reference. Like : if the function changes the referred object’s properties, that change is visible outside the function, as shown in the following example:
/* Declare the function 'myFunc' */
function myFunc(theObject) {
theObject.brand = "Toyota";
}
/*
* Declare variable 'mycar';
* create and initialize a new Object;
* assign reference to it to 'mycar'
*/
var mycar = {
brand: "Honda",
model: "Accord",
year: 1998
};
/* Logs 'Honda' */
console.log(mycar.brand);
/* Pass object reference to the function */
myFunc(mycar);
/*
* Logs 'Toyota' as the value of the 'brand' property
* of the object, as changed to by the function.
*/
console.log(mycar.brand);Defining functions
There are several ways to define functions:
1. Function Declaration and
2. Function Expression
3. IIFEs
What is a Function Declaration?
A Function Declaration defines a named function variable without requiring variable assignment. Function Declarations occur as standalone constructs and cannot be nested within non-function blocks. It’s helpful to think of them as siblings of Variable Declarations. Just as Variable Declarations must start with “var”, Function Declarations must begin with “function”.
function bar() {
return 3;
}The function name is visible within it’s scope and the scope of it’s parent (which is good because otherwise it would be unreachable)
What is a Function Expression?
A Function Expression defines a function as a part of a larger expression syntax (typically a variable assignment ). Functions defined via Functions Expressions can be named or anonymous. Function Expressions must not start with “function” (hence the parentheses around the self invoking example below)
//anonymous function expression
var a = function() {
return 3;
}
//named function expression
var a = function bar() {
return 3;
}
//self invoking function expression
(function sayHello() {
alert("hello!");
})();The function name (if any) is not visible outside of it’s scope (contrast with Function Declarations).
What is IIFEs — Immediately Invoked Function Expressions ?
(function () {
// logic here
})();The pattern is called an immediately invoked function expression, or IIFE (pronounced “iffy”).
A function created in the context of an expression is also a function expression. For example:
// Anything within the parentheses is part of an expression
(function () {
/* logic here */
});The key thing about JavaScript expressions is that they return values. In both cases above the return value of the expression is the function.
That means that if we want to invoke the function expression right away we just need to tackle a couple of parentheses on the end. Which brings us back to the first bit of code we looked at.
(function () {
// logic here
})();Why to use IIFE ?
The primary reason to use an IIFE is to obtain data privacy. Because JavaScript’s var scopes variables to their containing function, any variables declared within the IIFE cannot be accessed by the outside world.
(function () {
var foo = "bar";
// Outputs: "bar"
console.log(foo);
})();
// ReferenceError: foo is not defined
console.log(foo);Good Job!!! Till now we have learn about Functions and several ways of defining functions.
Now, we will learn about Function parameters and Arguments object.
Function Parameters
Starting with ECMAScript 2015, there are two new kinds of parameters: default parameters and rest parameters.
Default parameters
In JavaScript, parameters of functions default to undefined. However, in some situations it might be useful to set a different default value. This is where default parameters can help.
In the past, the general strategy for setting defaults was to test parameter values in the body of the function and assign a value if they are undefined. If in the following example, no value is provided for b in the call, its value would be undefined when evaluating a*band the call to multiply would have returned NaN. However, this is caught with the second line in this example:
function multiply(a, b) {
b = typeof b !== 'undefined' ? b : 1; return a * b;
}multiply(5); // 5
With default parameters, the check in the function body is no longer necessary. Now, you can simply put 1 as the default value for b in the function head:
function multiply(a, b = 1) {
return a * b;
}multiply(5); // 5
Rest parameters
The rest parameter syntax allows us to represent an indefinite number of arguments as an array. In the example, we use the rest parameters to collect arguments from the second one to the end. We then multiply them by the first one.
function multiply(multiplier, ...theArgs) {
return theArgs.map(x => multiplier * x);
}var arr = multiply(2, 1, 2, 3);
console.log(arr); // [2, 4, 6]
Arguments Object
The arguments of a function are maintained in an array-like object. Within a function, you can address the arguments passed to it as follows:
arguments[i]where i is the ordinal number of the argument, starting at zero. So, the first argument passed to a function would be arguments[0]. The total number of arguments is indicated by arguments.length.
Using the arguments object, you can call a function with more arguments than it is formally declared to accept. This is often useful if you don't know in advance how many arguments will be passed to the function. You can use arguments.length to determine the number of arguments actually passed to the function, and then access each argument using the arguments object.
For example, consider a function that concatenates several strings. The only formal argument for the function is a string that specifies the characters that separate the items to concatenate. The function is defined as follows:
function myConcat(separator) {
var result = ''; // initialize list
var i;
// iterate through arguments
for (i = 1; i < arguments.length; i++) {
result += arguments[i] + separator;
}
return result;
}You can pass any number of arguments to this function, and it concatenates each argument into a string “list”:
// returns "red, orange, blue, "
myConcat(', ', 'red', 'orange', 'blue');// returns "elephant; giraffe; lion; cheetah; "
myConcat('; ', 'elephant', 'giraffe', 'lion', 'cheetah');// returns "sage. basil. oregano. pepper. parsley. "
myConcat('. ', 'sage', 'basil', 'oregano', 'pepper', 'parsley');
Great! So now we all know about function parameters and Arguments object in detail.
Now, we will move to the most important and frequently used feature of JavaScript related to functions :
1. Closures
2. Arrow functions
Closures
Closures are one of the most powerful features of JavaScript. JavaScript allows for the nesting of functions and grants the inner function full access to all the variables and functions defined inside the outer function (and all other variables and functions that the outer function has access to). However, the outer function does not have access to the variables and functions defined inside the inner function. This provides a sort of encapsulation for the variables of the inner function. A closure is created when the inner function is somehow made available to any scope outside the outer function.
var pet = function(name) { // The outer function defines a variable called "name"
var getName = function() {
return name; // The inner function has access to the "name" variable of the outer
//function
}
return getName; // Return the inner function, thereby exposing it to outer scopes
}
myPet = pet('Vivie');
myPet(); // Returns "Vivie"It can be much more complex than the code above. An object containing methods for manipulating the inner variables of the outer function can be returned.
var createPet = function(name) {
var sex;
return {
setName: function(newName) {
name = newName;
},
getName: function() {
return name;
},
getSex: function() {
return sex;
},
setSex: function(newSex) {
if(typeof newSex === 'string' && (newSex.toLowerCase() === 'male' ||
newSex.toLowerCase() === 'female')) {
sex = newSex;
}
}
}
}var pet = createPet('Vivie');
pet.getName(); // Viviepet.setName('Oliver');
pet.setSex('male');
pet.getSex(); // male
pet.getName(); // Oliver
In the code above, the name variable of the outer function is accessible to the inner functions, and there is no other way to access the inner variables except through the inner functions. The inner variables of the inner functions act as safe stores for the outer arguments and variables. They hold "persistent" and "encapsulated" data for the inner functions to work with.
There are, however, a number of pitfalls to watch out for when using closures. If an enclosed function defines a variable with the same name as the name of a variable in the outer scope, there is no way to refer to the variable in the outer scope again.
var createPet = function(name) { // The outer function defines a variable called "name".
return {
setName: function(name) { // The enclosed function also defines a variable called "name".
name = name; // How do we access the "name" defined by the outer function?
}
}
}Arrow Functions
An arrow function expression (previously, and now incorrectly known as fat arrow function) has a shorter syntax compared to function expressions and does not have its own this, arguments, super, or new.target. Arrow functions are always anonymous.
Two factors influenced the introduction of arrow functions: shorter functions and non-binding of this.
Shorter functions
In some functional patterns, shorter functions are welcome. Compare:
var a = [
'Hydrogen',
'Helium',
'Lithium',
'Beryllium'
];var a2 = a.map(function(s) { return s.length; });console.log(a2); // logs [8, 6, 7, 9]var a3 = a.map(s => s.length);console.log(a3); // logs [8, 6, 7, 9]
No separate this
Until arrow functions, every new function defined its own this value (a new object in the case of a constructor, undefined in strict mode function calls, the base object if the function is called as an "object method", etc.). This proved to be less than ideal with an object-oriented style of programming.
function Person() {
// The Person() constructor defines `this` as itself.
this.age = 0; setInterval(function growUp() {
// In nonstrict mode, the growUp() function defines `this`
// as the global object, which is different from the `this`
// defined by the Person() constructor.
this.age++;
}, 1000);
}var p = new Person();
In ECMAScript 3/5, this issue was fixed by assigning the value in this to a variable that could be closed over.
function Person() {
var self = this; // Some choose `that` instead of `self`.
// Choose one and be consistent.
self.age = 0; setInterval(function growUp() {
// The callback refers to the `self` variable of which
// the value is the expected object.
self.age++;
}, 1000);
}
Alternatively, a bound function could be created so that the proper this value would be passed to the growUp() function.
An arrow function does not have its own this; the this value of the enclosing execution context is used. Thus, in the following code, the this within the function that is passed to setInterval has the same value as this in the enclosing function:
function Person() {
this.age = 0; setInterval(() => {
this.age++; // |this| properly refers to the person object
}, 1000);
}var p = new Person();
Amazing!!! So now we have good amount of information about JavaScript Functions.
Thank you for reading my article, and clap if you liked it!
