ikerhurtado.com
You're in
Iker Hurtado's pro blog
Developer | Entrepreneur | Investor
Software engineer (entrepreneur and investor at times). These days doing performant frontend and graphics on the web platform at Barcelona Supercomputing Center

Going deeply into Javascript. Basics (III): functions, scopes and closures

15 May 2015   |   iker hurtado  
Share on Twitter Share on Google+ Share on Facebook
In this post I write down some notes on JavaScript language basics like variables, functions, scopes and closures. It's not intended to be an exhaustive or complete resource about this issues.

A namespace is a container which allows developers to bundle up functionality under a unique, application-specific name. In JavaScript, there's no language-level difference between regular objects and namespaces. The ideais simple: create one global object, and all variables, methods, and functions become properties of that object.

Functions

Functions are objects, instances of Function (hence, functions get their methods from Function.prototype).

There three ways to create a function: via a function expression, function declaration and the constructor Function().

Function expression

A function expression produces a value, a function object. For example:

var fiveTimes = function(x) { return x * 5 };
fiveTimes(3); // -> 15

The value produced by a function expression can be assigned to a variable and passed as an argument to another function. Because normal function expressions don’t have a name, they are also called anonymous function expressions.

Function declaration

function fiveTimes(x) {
   return x * 5;
}

The previous function declaration looks similar a function expression but in this case it's a statement. The function declaration declares a new variable, creates a function object, and assigns it to the variable.

The constructor Function() is not recommended to define a function.

Function declarations have two advantages over function expressions: They are hoisted, so you can call them before they appear in the source code and they have a name.

Hoisting

Hoisting means moving functions and var declarations to the beginning of a scope.

Function declarations are hoisted completely. That allows to call a function before it has been declared -JavaScript engines move the declaration to the beginning of the scope.

var declarations are hoisted, too, but only the declarations, not assignments made with them.

Function name

Most JavaScript engines support the nonstandard property name for function objects. Example of a function declaration:

> function f() {}
> f.name
'f'

The name of anonymous function expressions is the empty string. However, named function expressions do have a name that can be useful for debugging.

The variable arguments

The special variable arguments exists only inside functions. It is an array-like object that holds all of the actual parameters of the current function call.

The variable arguments is not a true array (yes an object), but has a property length, and individual parameters can be accessed by index. On the other hand, arguments is not an array, it is only similar to one. In addition, it's possible to borrow array methods or convert arguments to an array.

In JavaScript, it's not possible to pass parameters by reference; the arguments are copied and handed to the function. The unique way to do this is to wrap the value of the variable in an array.

Missing or extra function parameters

In Javascript it's possible to call a function with any number of actual parameters, independent of what formal parameters have been defined.

If the call brings extra parameter, they are ignored (but can be returned via the special array-like variable arguments).

In contrast, if the call brings fewer actual parameters than formal parameters, the missing parameters have the value undefined.

JavaScript lets you call a function and call it with an arbitrary array of arguments, using the apply() method of any function object.

avg.apply(null, [2, 3, 4, 5]);

The second argument to apply() is the array to use as arguments; the first is this object. This emphasizes the fact that functions are objects too.

Variables and scopes

Unlike most languages variables (block-scoped), JavaScript’s variables are function-scoped: only functions introduce new scopes; blocks are ignored when it comes to scoping.

In addition, JavaScript hoists variable declarations, it moves them to the beginning of their direct scopes. It's worthy to note that the assignation (in a declaration statement) is not hoisted:

function f() {
  console.log(v); // -> undefined
  var v = 7;
}

The IIFE pattern

The immediately invoked function expression (IIFE) is a common pattern in JavaScript in order to introducing a new scope for variables (to restrict the lifetime of variables). The code to do it:

(function () { 
...
}()); 

It looks like a function declaration but it's a statement (the function inside is an expression) and is immediately invoked (because of the parentheses following the closing brace).

The use of this pattern is costly, so we have to do it moderately.

Global Variables

The global or program scope is the scope containing all of a program.

Inside the global scope, it's possible to create nested scopes by defining functions and, of course, add more inner scope levels. Each scope has access to its own variables and to the variables in the scopes that surround it. Hence, global variables can be accessed everywhere.

All of the JavaScript code on a web page shares the global variables. So, name collisions can become a problem.

It's recommended to avoid creating global variables. Software using global variables is less robust, less predictably and reusable, and, in the case of Javascript, namespace pollution prone.

The global object

The ECMAScript specification uses the internal data structure environment to store variables and makes it accessible for global variables via an object: the global object. It can be used to create, read, and change global variables.

If we are in the global scope, this points to the global object.

Environments and Closures

Variables are effectively created when program execution enters their scope. The data structure (similar to Javascript objects) that provides that storage space in Javascript is called environment.

Because a function always needs access to both its own local variables and the ones of the surrounding scopes, they can keep alive after the program execution leaves their scope. Therefore, they (and the whole environment, I suspect) are stored on a heap.

When a function is invoked, a new environment is formed to sustain its parameters and variables. To handle nest calls and recursion, execution contexts (with references to environments) are stored in a stack. This is the dynamic perspective of the process.

The function references the scope it was created in via the internal property [[Scope]]. Additionally, each environment holds a field called outer that points to the outer scope’s environment. Hence, it always exists a chain of environments, starting with the currently active environment that ending with the global environment (of which the field outer is null).

In order to resolve an identifier inside an scope, the environment chain must be traversed.

The Closure concept

In Javascript, a closure means a function and its connection to the scope in which it was created. We know from the previous section that when a function leaves the scope in which it was created, it keeps connected to the variables of that scope (and of the surrounding ones).

A good example of closures: A re-introduction to JavaScript (JS tutorial) - JavaScript | MDN

This topic is very well explained in the Chapter 16 / Environments: Managing Variables of the book Speaking JavaScript.

POST A COMMENT: