Advanced Concepts of Functions in JavaScript

In this section of the tutorial, we will discuss Advanced Concepts of Functions in JavaScript such as Function as values, Function as namespaces, Functional Programming, and much more that are extensively used in the JavaScript program with some good examples for in-depth understanding.

Functions as Values in JS

In JavaScript, functions can be syntax and values as well which means they can be assigned to variables, can be stored in object properties or array elements, can be passed as arguments to functions, etc.

Functions are a very important feature in any programming language as they can be defined and invoked in a program.

Now, we will take an example to understand how a function can be represented as JavaScript data as well as JavaScript syntax.

Example:

<html>
<head>
<title>JavaScript</title>
<script type="text/javascript">

function square(x) { return x*x; }

</script>
</head>
<body>
</body>
</html>
  • Here, the function definition creates a new function object.
  • The function object is then assigned to the variable square.

We will take another example to understand it more clearly.

Example:

<html>
<head>
<title>JavaScript</title>
<script type="text/javascript">

let s = square;
square(4)
s(4)

</script>
</head>
<body>
</body>
</html>
  • Here, s refers to the same function as the variable square.
  • It shows that functions can also be assigned to object properties rather than variables.

Defining Function Properties

In JavaScript, functions can have properties as they are not primitive values, they are special kinds of objects.

When a static variable is required by the function whose value persists across every invocation, then it is more efficient to use the property of the function.

We will take an example to understand how function’s property is used.

Example:

<html>
<head>
<title>JavaScript</title>
<script type="text/javascript">

uniqueInteger.counter = 0;
function uniqueInteger() {
    return uniqueInteger.counter++;
}
uniqueInteger()
uniqueInteger()

</script>
</head>
<body>
</body>
</html>
  • Here, we first initialize the counter property of the function object.
  • Function uniqueInteger.counter retruns distinct values each time it is invoked.
  • It uses its own property to remember the next value to be returned.

Functions as Namespaces in Js

In JavaScript, sometimes variables declared inside a function are not visible outside of the function, so we define a function simply to act as a temporary namespace in which variables can be defined without disturbing the global namespace.

We will take an example to understand the use of functions as namespaces.

Example:

<html>
<head>
<title>JavaScript</title>
<script type="text/javascript">

function chunkNamespace() {
    //chunk of code
}
chunkNamespace();

</script>
</head>
<body>
</body>
</html>
  • Here, the chunk of code is inserted inside the function chunkNamespace().
  • Variables that are defined in the chunk of code are local to this function without cluttering up the global namespace.
  • Then the function chunkNamespace() is invoked.

Closures in Function

In JavaScript, functions are executed using the variable scope in effect when they are defined, not the variable scope in effect when they are invoked, this is called lexical scoping.

To implement the lexical scoping, the internal state of a function object must include a reference of the scope along with the code of the function. This pair of the function object and scope in which function variables are resolved is called a closure in JavaScript.

Now, we will take an example to understand the closures in Function.

Example:

<html>
<head>
<title>JavaScript</title>
<script type="text/javascript">

let scope = "global scope";
function checkscope() {
    let scope = "local scope";
    function f() {
        return scope;
    }
    return f();
}
checkscope()

</script>
</head>
<body>
</body>
</html>
  • Here, in line 6, scope is a global variable.
  • In line 8, scope is local variable.
  • The function f() returns the value in scope.
  • Function checkscope() returns local scope.

JavaScript allows two or more nested functions to be defined within the same outer function and share the same scope.

Example:

<html>
<head>
<title>JavaScript</title>
<script type="text/javascript">

function counter() {
    let n = 0;
    return {
        count: function () { return n++ }
        count: function () { n = 0; }
    };
}

let c = counter(), d = counter();
c.count()
d.count()
c.reset()
c.count()
d.count()

</script>
</head>
<body>
</body>
</html>
  • Here, two counters are created namely c and d.
  • c.count() d.count() returns 0, they count independently.
  • reset() and count() methods share state.
  • Since we reset, c.count() again returns 0.
  • d.count() will return 1 now, since it was not reset.

It is clear from the above example that calling count() and reset() on one counter object has no effect on the other.

Functions Properties

Till now, we have seen various properties of Functions in JavaScript such as functions as values, typeof operator returns string function when applied to a function, and many more.

Now we will discuss some more properties of Function that will specify the length, name, and prototype properties.

Also, we will discuss function methods, such as call(), apply(), bind(), and toString() with function() constructor.

Length Property

The length property of a function in read-only state specifies the arity of the function, which means the number of parameters it declares in its parameter list, i.e. the number of arguments expected by the function.

Name Property

The name property of a function in read-only state specifies the name used to define the function, if it was defined with a name, or a variable name, or property of an unnamed function expression assigned to it when it was initially created.

Prototype Property

The prototype property is associated with all functions except arrow functions. It refers to an object called the prototype object. Prototype object is different for different functions. When a function is used as a constructor, the object created inherits all the properties of the prototype object.

Function Methods

We have thoroughly discussed Methods in JavaScript, now we will discuss some more function methods such as call() and apply(), bind(), and toString() methods briefly.

call() and apply() Method

In JavaScript, the call() and apply() methods enable a user to invoke a function indirectly considering them as a method of some other object. The object on which the function is to be invoked happens to be the first argument of both call() and apply(), this argument then becomes the value of the this keyword within the function body.

We will understand the use of call() and apply() Method with the help of an example.

Example:

<html>
<head>
<title>JavaScript</title>
<script type="text/javascript">

f.call(o);
f.apply(o);

o.m = f;
o.m();
delete o.m;

f.call(o, 1, 2);
f.apply(o, [1, 2]);

</script>
</head>
<body>
</body>
</html>
  • Here, in line 6 and 7, function f() is invoked as a method of the object o without passing any arguments, either of call() or apply() can be used.
  • In line 9, f is a temporary method of o.
  • In line 10, method of o is invoked without passing any arguments.
  • In line 11, temporary method o.m is removed using delete keyword.
  • In line 13, using call() method to the function f(), two arguments are passed and invoked considering it as a method of object o.
  • In line 14, apply() method is used just like the call() method, except that the arguments are specified as an array.

bind() Method

The bind() method is used to bind a function to an object. When the blind() is invoked on a function (say) f() and passes an object o, the bind() method returns a new function. Whenever a new function is invoked, it invokes the original function f() as a method of o. Similarly, any arguments passed to the new function are passed to the original function as well.

We will take an example to understand the use of the bind() method.

Example:

<html>
<head>
<title>JavaScript</title>
<script type="text/javascript">

function f(y) {
    return this.x + y;
}
let o = { x: 1 };
let g = f.bind(o);
g(2)

let p = { x:10, g };
p.g(2)

</script>
</head>
<body>
</body>
</html>
  • Here, in line 6, this function f() needs to be bound.
  • In line 9, the object will be binded to function f().
  • In line 10, when we call function g(), it invoked the function f() on o.
  • In line 11, function g() will return 3.
  • In line 13, function g() is invoked as a method of object.

toString() Method

In JavaScript, the toString() method mostly returns the complete source code for the function. the built-in functions typically return a string having the native code as the function body.

Function() Constructor

In JavaScript, since function are treated as objects, there is a function() constructor that is used to create new functions:

Example:

const f = new Function("x", "y", "return x*y;");

Here, we can see that a new function is created that is somewhat equivalent to a function defined with similar syntax.

const f = function(x, y) { return x*y; };

We must keep in mind that function() constructor is not passed with any argument that specifies a function name created. It creates random and anonymous functions.

We will take an example to understand how to use a Function() constructor.

Example:

<html>
<head>
<title>JavaScript</title>
<script type="text/javascript">

let scope = "global";
function constructFunction() {
    let scope = "local";
    return new Function("return scope");
}
constructFunction()()

</script>
</head>
<body>
</body>
</html>

Functional Programming in JavaScript

In this section, we will discuss the techniques of functional programming in JavaScript, which serves as a powerful demonstration of the features of JavaScript’s Functions.

Arrays with Functions

In JavaScript, arrays can be processed with functions using array methods such as map() and reduce().

We will take an example to understand it more clearly.

Suppose we have to compute the mean and standard deviation of some values.

Example:

<html>
<head>
<title>JavaScript</title>
<script type="text/javascript">

const sum = (x,y) => x+y;
const square = x => x*x;

let data = [1,1,3,3,5];
let mean = data.reduce(sum)/data.length;
let deviations = data.map(x => x-mean);
let stddev = Math.sqrt(deviations.map(square).reduce(sum)/(data.length-1))
stddev

const map = function (a,...args) { return a.map(...args); };
const reduce = function (a,...args) { return a.reduce(...args); };

</script>
</head>
<body>
</body>
</html>
  • Here, we can see that the methods map() and reduce() are invoked on objects.
  • The functions form of these methods are also defined, which computes the mean and standard deviation.

Higher-Order Functions

In JavaScript, the higher-order functions are operated on functions, taking one or more functions as arguments and returning a new function.

Example:

<html>
<head>
<title>JavaScript</title>
<script type="text/javascript">

function not(f) {
    return function (...args) {
        let result = f.apply(this,args);
        return !result;
    };
}

const even = x => x % 2 === 0;
const odd = not(even);
[1,1,3,5,5].every(odd)

</script>
</head>
<body>
</body>
</html>
  • Here, the higher-order function not() returns a new function that passes it.
  • The functions determine whether a number is even or odd.
  • And after the evaluation of the array element, a true or false statement is returned based on the observation.

We will take another example to understand it more clearly.

Example:

<html>
<head>
<title>JavaScript</title>
<script type="text/javascript">

function compose(f, g) {
    return function (...args) {
        return f.call(this, g.apply(this, args));
    };
}

const sum = (x,y) => x+y;
const square = x => x*x;
compose(square, sum)(2,3)

</script>
</head>
<body>
</body>
</html>
  • Here, f() and g() are higher-order functions that returns a new function f(g()).
  • The returned function passes all its arguments to g() then passes the return value of g() to f(), then returns the return value of f().
  • Both f() and g() are invoked having the same this value as the returned function was invoked with.

Partial Applications of Functions

The partial application of functions enables us to define functions out of the function that is already defined.

Example:

<html>
<head>
<title>JavaScript Examples</title>
<script type="text/javascript">

const increment = partialLeft(sum, 1);
const cuberoot = partialRight(Math.pow, 1/3);
cuberoot(increment(26))

</script>
</head>
<body>
</body>
</html>

Memoization and Functions

In JavaScript, functional programming can cache its previously computed result, this kind of caching is known as memoization.

We will take an example to understand the memoization more clearly.

Example:

<html>
<head>
<title>JavaScript</title>
<script type="text/javascript">

function memoize(f) {
    const cache = new Map();

    return function (...args) {
        let key = args.length + args.join("+");
        if (cache.has(key)) {
            return cache.get(key);
        } else {
            let result = f.apply(this, args);
            cache.set(key, result);
            return result;
        }
    };
}

</script>
</head>
<body>
</body>
</html>
  • Here, the function memoize() accepts a function as its argument and returns a memoized form of the function.
  • The memoize() function creates a new object to be used as cache and it assigns this object to a local variable so that it is private to the returned function.
  • The returned function converts its arguments array to string and it is then used as a property name for the cache object.
  • It returns directly if a value exists in the cache.
  • Otherwise, the argument’s value is computed by calling the specific functions and then caches and finally returned.

In the next section of the tutorial, we will discuss Objects in JavaScript and their uses with their different properties, i.e. key-value pairs that are used in the JavaScript program with some good examples for in-depth understanding.