Let's talk JavaScript functions: Part two for the VOX DC

VOXDC_Header_Multi_Colors.png

In JavaScript, functions have their own lexical scope [1]. Parameters of the function are defined in this local scope. A further implication is that identifiers inside the function are not accessible outside of it, though the function itself has access to names in its containing environment.

Now it should be mentioned that recently an additional syntax/semantic for function expressions was introduced into the language specification. This change was made along with numerous others in the 2015 update provided by the standards organization ECMA. In this new format the 'function' keyword is removed and instead an '=>' is used to link the parameters in '()' with the body '{}', like so '() => {}'. Aside from the obvious syntactical difference, there are some important semantic differences. Most notably, arrow function expressions do not have their own implicit parameters.

All function declarations and function expressions with the 'function' keyword have two implicit parameters. One is the 'arguments' object. As the name implies, this object contains all the arguments with which the function was called. It is similar to an array in that it has a zero-based index to reference the parameters and a 'length' property. Thus, if a programmer wants to reference the Nth argument passed to a function they could do so by 'arguments[N - 1]'. This construct makes it possible to handle an arbitrary number of parameters as JavaScript functions do not have signatures.

Screen Shot 2018-08-13 at 7.36.03 AM.png
The second implicit parameter, which is less straightforward is 'this'. Unlike in other languages, the value of 'this' can vary with how the function is invoked. As such, it refers to the object invoking the function and is bound when the function is called (not when it is created).

To fully understand 'this', one must first be aware of how a function can be invoked. When called, function parameters are passed by value if they are primitives, which are 'Number', 'Boolean', 'String', 'null', 'undefined', and 'Symbol'; otherwise, they are passed by object reference. A function invocation can occur in one of four ways:

  1. As a function. This is the most straightforward way. It is simply calling the function that has been declared or assigned to a variable. In this case the value of 'this' is 'undefined'[2].
  2. As a method. When a function is a property of an object it is referred to as a method. Once this property is accessed it can be called as a function. The value of 'this', as one may expect, is the object that has the relevant function as a property.
  3. As a constructor. Constructor functions should always be named with a leading capital letter to denote they should be used with the 'new' keyword [3]. The 'new' keyword proceeds the constructor invocation; it creates a new object that is bound to the 'this' value of the constructor function.
  4. Through the 'call' & 'apply' methods. With these methods on the Function prototype [4], the user can explicitly state the value of 'this' and invoke the function.

There is one final important point on 'this'. The 'bind' method on the Function prototype allows the programmer to create a new function from an existing function with an explicitly bound value for 'this'. The method can be helpful in certain situations, but consistent use would suggest poor code design.

Screen Shot 2018-08-13 at 7.36.16 AM.png
Lastly – the topic of "closure" in JavaScript. A closure is a combination of a function and an encapsulating lexical environment. Whenever a function is created it captures the state of its lexical scope, while often times this is trivial, it can be very powerful when used intentionally. How this typically manifests in code is to have a function that returns another function. In this case, the function that is returned will have access to the lexical scope of the function that returned it at the time it was returned. So even though the initial function has long returned and been remove from the stack, the new function that was returned maintains access the lexical environment. As one may imagine, this is a great technique for elegant state management and allows a more precise scope chain for name resolution. 

Screen Shot 2018-08-13 at 7.36.32 AM.png
You can't have an extensive conversation about JavaScript without a discussion on functions. Given the way functions are implemented, they are such an important and valuable piece of the language. This has been an overview functions in JavaScript—certainly far from an exhaustive analysis—which should serve as a good basis for further exploration.

[1] Until a spec update in 2015, functions and catch blocks were the only constructs to have their own lexical scope.
[2] Assuming "strict mode" is enabled; always write JavaScript in "strict mode".
[3] If the 'new' keyword is neglected when calling a constructor, then disastrous things may happen.
[4] JavaScript is an object-oriented language through prototypes as opposed to classes.