A walk in JavaScript

DAY 6

Functions

General definition

Let’s start with a general definition to understand what a function is:

In computer programming, a subroutine is a sequence of program instructions that performs a specific task, packaged as a unit. This unit can then be used in programs wherever that particular task should be performed.

Subprograms may be defined within programs, or separately in libraries that can be used by many programs. In different programming languages, a subroutine may be called a procedure, a function, a routine, a method, or a subprogram. The generic term callable unit is sometimes used.

Source: Wikipedia

Nice, we now know that a function might contain instructions to do something and is “callable”.

We also know from our previous lessons that a function is a Function Object with a complex definition:

ECMAScript function objects encapsulate parameterized ECMAScript code closed over a lexical environment and support the dynamic evaluation of that code. An ECMAScript function object is an ordinary object and has the same internal slots and the same internal methods as other ordinary objects. The code of an ECMAScript function object may be either strict mode code (10.2.1) or non-strict mode code. An ECMAScript function object whose code is strict mode code is called a strict function. One whose code is not strict mode code is called a non-strict function.

Source: ECMAScript International

Lot of terms are completely obscure at this time but we will shed light to them as the day grows.

Now let’s see if MDN has something more to say:

In JavaScript, functions are first-class objects, because they can have properties and methods just like any other object. What distinguishes them from other objects is that functions can be called. In brief, they are Function objects. Source: MDN

That’s a great reminder of something important. In JS, functions are first-class citizens, therefore they can:

Now let’s start digging with the following topics:

Function declaration (function statement)

A function declaration or function statement defines a function with a name and arbitrary number of specified parameters. It might or might not contain statements on its body and it’ll implicitly return undefined unless an explicit value is defined on the return ...; statement.

function name([param[, param,[..., param]]]) {
   [statements]
}

See MDN Function declaration

Function expression

A function declaration can be defined inside an expression like a assignment expression where the function is assigned as a value for a given variable. In the case of a function expression the name of the function can be omitted resulting in two variants, named function expression or anonymous function expression; the differences between the two are significant and we’ll see them soon.

var myFunction = function [name]([param1[, param2[, ..., paramN]]]) {
   statements
};

See MDN Function expression

Function constructor

Function objects created with the Function constructor are parsed when the function is created. This is less efficient than declaring a function with a function expression or function statement and calling it within your code because such functions are parsed with the rest of the code.

Source: MDN Function Constructor

new Function ([arg1[, arg2[, ...argN]],] functionBody)

See MDN Function constructor

Constructor vs declaration vs expression

Even though they will end up producing a function, there are several differences between them, some subtle and some coarse. Let’s see some examples in MDN - Constructor vs declaration vs expression

Properties of the Function object in the prototype chain

As we already learn, a function is an object, therefore it benefits from the prototype chain defined properties, which can be any of the ECMAScript types we know. Let’s take a look at MDN - Function prototype object

Arity & formal parameters

Arity is the term used to describe the number of arguments a function or operation accepts. They can be described as nullary (0 arguments), unary (1), binary (2) and so on.

Intrinsically, functions in JavaScript are variadic ( a.k.a multigrade, n-ary, polyadic …), it means that even though you can define the formal parameters at function declaration time, it will accept AND handle less or more arguments. That opens a whole world of interesting implementations.

Example from Wikipedia - Variadic function in Javascript

function add(n, i) {
    return n + i;
}

function sum(...numbers) {
    return numbers.reduce(add);
}

sum(1, 2, 3) // 6
sum(3, 2, 1) // 6

Example of LHS and RHS analysis


/**
 * How many LHS look-ups can you see?
 * How many RHS look-ups can you see?
 */

function speakToMe(input) {
    var helperVal = input;
    return input + helperVal;

}

var result = speakToMe( 10 );

Formal parameters and the arguments thing

Did you note something weird about those terms arguments and parameters that seem to be interchangeable but … not quite? Well, you’re not alone. It turns out the ARE kinda vague, so for clarity well see a couple of definitions here:

In computer programming, a parameter or a formal argument, is a special kind of variable, used in a subroutine to refer to one of the pieces of data provided as input to the subroutine. These pieces of data are the values of the arguments (often called actual arguments or actual parameters) with which the subroutine is going to be called/invoked. … Unlike argument in usual mathematical usage, the argument in computer science is thus the actual input expression passed/supplied to a function, procedure, or routine in the invocation/call statement, whereas the parameter is the variable inside the implementation of the subroutine.

Source: Wikipedia - Parameter

In mathematics, an argument of a function is a specific input to the function; it is also called an independent variable.

Source: Wikipedia - Argument

In short, the parameters are the signature, or the variables you define at function declaration time, and the arguments are the values you pass to the function at function call time.

That said, arguments itself has a special meaning in JavaScript. Now let’s see more about how JavaScript handles arguments, provides a new way in ES6 to handle those arguments in a consistent way, and provides a feature to define default values for the formal parameters (like other languages do)

Functions as properties of an object

We’ve learned the concept of first-class citizens, therefore we can assign a function to a variable …. what if that variable happens to be an object property? Now we’re talking, we could create an object with many values of any ECMAScript valid type, including functions, that might manipulate values of the same or other objects!!!. This functions are sometimes called “methods” but that might be an arguable statement. (the door for Object Oriented Programming has been opened )

Let’s get some insights from MDN - Method definitions

IIFE

Do you remember what an expression is? Now what if I tell you there’s a particular expression that let’s you declare a function in an expression that immediately executes that function? Many JavaScripts common patterns are built around that feature called Immediately Invoked Function Expression best known by its acronym IIFE


// not very useful but clear

(function(){
  alert(`I'm a teapot`);
}())

Pure Functions

Hey function, you shouldn’t change anything, you should only accept data and return new data, that’s it.

Behind that simplicity there’s a whole paradigm called functional programming. Let’s take a look a those concepts.


let a = [1, 2, 3, 4, 5];
let b = a.map( i => i+1);

console.log(a); // [1, 2, 3, 4, 5]
console.log(b); // [2, 3, 4, 5, 6]

Side Effects

Hey function you can explicitly (because I told you so) or implicitly (because someone told you so, even without knowing they told you so) change everything you can get your claws into, even without letting anyone know about that.

Scary huh? But also powerful, it all depends on the agreement you have with the rest of the engineers (scary huh ? :P). That said, even here a whole world of paradigms lay on top of that Side Effects thing, like Imperative programming


// a compendium or WRONG STAFF

var a = [1, 2, 3, 4, 5];
var b = [];

a.forEach((v,i) => {
  b[i] = ++a[i];
});

console.log(b); // [2, 3, 4, 5, 6] NICE!!!
console.log(a); // [2, 3, 4, 5, 6] OOPS! we change it!!!


Execution Context

See Execution Context documentation

👎 Execution context != context (aka this)
👍 Execution context ~ scope

Types of Execution Context (executable code)

See Types of Source Code

Execution Stack

How Execution Context is defined?

Creation Phase

Execution Phase

example taken from: Understanding Execution Context and Execution Stack in Javascript. (by Sukhjinder Arora)

0 - The code

let a = 20;

const b = 30;

var c;

function multiply(e, f) {
 var g = 20;
 return e * f * g;
}

c = multiply(20, 30);

1 - Global context creation

// (PSEUDO-CODE)

GlobalExectionContext = {
  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      // Identifier bindings go here
      a: < uninitialized >,
      b: < uninitialized >,
      multiply: < func >
    }
    outer: <null>,
    ThisBinding: <Global Object>
  },
  VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      // Identifier bindings go here
      c: undefined,
    }
    outer: <null>,
    ThisBinding: <Global Object>
  }
}

2 - Global execution

// (PSEUDO-CODE)

GlobalExectionContext = {
  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      // Identifier bindings go here
      a: 20,
      b: 30,
      multiply: < func >
    }
    outer: <null>,
    ThisBinding: <Global Object>
  },
  VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      // Identifier bindings go here
      c: undefined,
    }
    outer: <null>,
    ThisBinding: <Global Object>
  }
}

3 - multiply context creation

// (PSEUDO-CODE)

FunctionExectionContext = {
  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      // Identifier bindings go here
      Arguments: {0: 20, 1: 30, length: 2},
    },
    outer: <GlobalLexicalEnvironment>,
    ThisBinding: <Global Object or undefined>,
  },
  VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      // Identifier bindings go here
      g: undefined
    },
    outer: <GlobalLexicalEnvironment>,
    ThisBinding: <Global Object or undefined>
  }
}

4 - multiply execution

// (PSEUDO-CODE)

FunctionExectionContext = {
  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      // Identifier bindings go here
      Arguments: {0: 20, 1: 30, length: 2},
    },
    outer: <GlobalLexicalEnvironment>,
    ThisBinding: <Global Object or undefined>,
  },
  VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      // Identifier bindings go here
      g: 20
    },
    outer: <GlobalLexicalEnvironment>,
    ThisBinding: <Global Object or undefined>
  }
}

Articles and books used for the “execution context” section


Scope

REMINDER
DO NOT CONFUSE “scope” with “context”

Define Scope

Scope is the “part of the program” where a Name Binding is valid.

“Part of a program” meaning

WHEN defined at RUN-TIME ( Dynamic Scope )

“Dynamic scoping does not care how the code is written, but instead how it executes. Each time a new function is executed, a new scope is pushed onto the stack. This scope is typically stored with the function’s call stack. When a variable is referenced in the function, the scope in each call stack is checked to see if it provides the value.”

Source: Lua

Late binding, non-optimizable at compile time

WHEN defined at LEX-TIME ( Lexical Scope )

“The scope of a quantity is the set of statements and expressions in which the declaration of the identifier associated with that quantity is valid.”

Source: Algol60

Early binding, optimizable at compile time
JavaScript use this scope paradigm

ECMAScript definitions

General definitions:

Examples

/**
 * REMEMBER
 * In JavaScript a variable can't have a reference to another variable!!!! IT'S ALL ABOUT VALUES!!!!
 *
 * A value can be assigned to a variable in two ways
 *      BY VALUE -> for primitives -> the data is duplicated and then the variable points to that new duplicated data
 *          var a = 2;
 *          var b = a; -> a new numeric data is created and b will point to this new data
 *                        there's no relationship between the 2 of a and the 2 of b
 *
 *      BY REFERENCE -> for compound (objects) -> the variable points the the data
 *          var a = {x: 3};
 *          var b = a; -> there's no reference from b to a,
 *                        the references if from that both a and b point to the same object in memory { x:3 }
 *
 *                        It means if we modify the actual object { x:3 } by adding or removing information, all identifiers will
 *                          be still linked to the same data which has changed. Instead of we reassign the identifier data or redefine the identifier,
 *                          the data will be accessible through any remaining identifier pointing to it otherwise it'll be garbage collected
 *
 * Below a simple verification
 */

// Synchronous modification

var a = { x:3 };
var b = a;
a = { n:8 };

console.log(a); // -> {n: 8}
console.log(b); // -> {x: 3}

// Asynchronous modification
var c = { x:3 };
var d = c;

// will see asynchronous programming and arrow functions later
setTimeout(() => c = { x:4 }, 1000);
setTimeout(() => console.log(c), 2000); // -> {x: 4}
setTimeout(() => console.log(d), 3000); // -> {x: 3}

/**
 * explain scope of:
 *  a
 *  b
 *  c
 *  d
 *
 *  what is TDZ in ES6?
 */
function n ( z ) {
    a = 3;
    var b = 4;

    {
        var c = 5;
        let d = 7;
    }
}

/**
 *
 */
(function(){
  var a = b = 3;
})();

console.log(a); // what will it print?
console.log(b); // and this?


Hoisting

Hoisting is a concept described by Douglas Crockford many years ago, way before ES6 was even close to be dreamed. That concept was particularly significant in ECMAScript < 5.x and ES6 introduced a couple of changes in the syntax that directly affects how that concept is defined. Kyle Simpson dedicated a full section for that and, truly, there’s no better explanation I can share with you than that.

Let’s see YDKJS - Scope & Closures - Hoisting


Closure

“A closure is the combination of a function and the lexical environment within which that function was declared.”

Source: MDN

“In programming languages, a closure, also lexical closure or function closure, is a technique for implementing lexically scoped name binding in a language with first-class functions. Operationally, a closure is a record storing a function together with an environment.The environment is a mapping associating each free variable of the function (variables that are used locally, but defined in an enclosing scope) with the value or reference to which the name was bound when the closure was created. Unlike a plain function, a closure allows the function to access those captured variables through the closure’s copies of their values or references, even when the function is invoked outside their scope.”

Source: Wikipedia

“In computer science, a closure (also lexical closure, function closure, function value or functional value) is a function together with a referencing environment for the non-local variables of that function. A closure allows a function to access variables outside its typical scope. Such a function is said to be “closed over” its free variables. The referencing environment binds the non-local names to the corresponding variables in scope at the time the closure is created, additionally extending their lifetime to at least as long as the lifetime of the closure itself. When the closure is entered at a later time, possibly from a different scope, the function is executed with its non-local variables referring to the ones captured by the closure.”

Source: Enacademic

General Definition

/**
 * CLOSURE example from wikipedia
 * @see https://en.wikipedia.org/wiki/Closure_(computer_programming)#Lexical_environment
 *
 * in ECMAScript
 */

var f, g;

function foo() {
  var x;
  f = function() { return ++x; };
  g = function() { return --x; };
  x = 1;
  alert('inside foo, call to f(): ' + f());
}

foo();  // 2
alert('call to g(): ' + g());  // 1 (--x)
alert('call to g(): ' + g());  // 0 (--x)
alert('call to f(): ' + f());  // 1 (++x)
alert('call to f(): ' + f());  // 2 (++x)

/**
 * Function foo and the closures referred to by variables f and g all use the same relative memory location signified by local variable x.
 *
 * In some instances the above behavior may be undesirable, and it is necessary to bind a different lexical closure.
 * Again in ECMAScript, this would be done using the Function.bind(). We'll see `bind` later.
 */


Relative Concepts Readings


Can we cheat scope?

“Abandon all hope who enter here”

Ev[a|i]l

Modifying the lex-time defined scope dynamically


/**
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval
 *
 */

function cheat(a, b, c) {
    // 'use strict'; // <- what if we use strict mode? ( we'll see strict mode details on day 7 )
    eval(a);
    console.log(b + c);
}

cheat('var c = 7', 10, 5); // <- what if we omit the var statement?

function cheatAgain(a, b) {
    // 'use strict'; // <- what if we use strict mode? ( we'll see strict mode details on day 7 )
    eval(a);
    console.log(b + c);
}

var c = 5;

cheatAgain('var c = 7', 10); // <- what if we omit the var statement?

with

Creating a lexical scope at run-time


/**
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with
 *
 */

var a = {
    b: 2
};

var a1 = {
    c: 3
}

with(a){
   b = 3;
}

with(a1){
   b = 4;
}

console.log(a);
console.log(a1); // <- oops
console.log(b); // <- what?!!!


'use strict';
with (Math){x = cos(2)};

Other

Preliminary Practice

Now let’s have some time to practice. Here a list of resources we can use:

Exercises

Let’s open our test files:

Now open your terminal.

  1. Make sure you’re at the project location
  2. If you didn’t install all the packages yet the run npm i for a fresh dependency install, or npm ci for an installation based on the lock file.
  3. Type npm run test:watch, this will start running your tests every time you make a change.

Our task is to make ALL our DAY 6 tests pass ;)