Block-Level Scoping in ES 2015

Scoping in JavaScript works little different compared to other languages. Without knowing this, many new and experienced developers have fallen prey to Scoping System in JavaScript. This is because of our coding habits in C#, Java or C++.
The Problem:
We usually create variables in for loop or if condition in a function and think that it will not be accessible outside that loop or if block.
Let us see this example, we are creating a variable ‘name’ in if-condition and try to print it in console outside the if-block. One may think that it will output undefined. But to our surprise, the value that is set in if condition will be printed.

function testMethod() {
     if(true) {
           var name = 'Pranav';
           console.log(name); // outputs 'Pranav'
     console.log(name);  // will output 'Pranav'

The reason for this behaviour is that unlike other languages JavaScript follows Function-level variable ScopingJavaScript hoists variables to the top of the function no matter where they were declared in the function enforcing a function-level variable scoping.

This behaviour is evil at times and cause potential problems in large scale apps.
To solve this problem, ECMA Script 2015 ( ES 2015) introduces block-level scoping using two new keywords: let and const.
The Solution: Block-level Scoping using let and const
Both let and const create variables that are block-scoped – they only exist within the innermost block that surrounds them i.e., if-blocks, loop-blocks, anything with curly braces and naked curly braces too.
Let us see an example to make it more clear.

function testMethod() {
     let name = 'Ainavolu';
     if(true) {
           let name = 'Pranav';
           console.log(name); // outputs 'Pranav'
     console.log(name);  // outputs 'Ainavolu'

Here the scope of variable name in if-condition is limited to that block. It shadows the function-level variable in that context.
Another good thing with let and const is that they have temporal dead zone (TDZ). When entering its scope, it can’t be accessed (get or set) until execution reaches the declaration.

function testMethod() {
     name = 'Ainavolu'; // uninitialized binding - reference error
     console.log(name); // reference error
     let name; // TDZ ends; name is initialized with undefined
     console.log(name);  // outputs 'undefined'
     name = 'Pranav';
     console.log(name); // outputs 'Pranav'

const creates immutable variables i.e., variables whose value cannot be changed.

     const FILE_NAME = 'MyTestLogFile.log';
     FILE_NAME = 'AnotherLogFile.log'; // throws TypeError

Variables created with let are mutable. The value of those variables can be changed any time after declaration unlike const.
Here is an interesting case of const covered by Axel Rauschmayer.

    const obj = {}; = 'Pranav';
    console.log(; // Pranav
    obj = {}; // TypeError
const does not affect whether the value of a constant itself is mutable or not: If a constant refers to an object, it will always refer to that object, but the object itself can still be changed (if it is mutable).
To make an object mutable, we need to use its freeze property.
const obj = Object.freeze(); = 'Pranav'; // TypeError

Recommended reading: Variables and scoping in ECMAScript 6 by Axel Rauschmayer

Promises in ES6

Promises are usually vaguely defined as “a proxy for a value that will eventually become available”. They can be used for both synchronous and asynchronous code flows, although they make asynchronous flows easier to reason about – once you’ve mastered promises, that is.
Consider as an example the upcoming fetch API. This API is a simplification of XMLHttpRequest. It aims to be super simple to use for the most basic use cases: making a GET request against a resource relative to the current page over http(s) – it also provides a comprehensive API that caters to advanced use cases as well, but that’s not our focus for now. In it’s most basic incarnation, you can make a request for GET foo like so.


The fetch('foo') statement doesn’t seem all that exciting. It makes a “fire-and-forget” GET request against foo relative to the resource we’re currently on. The fetch method returns a Promise. You can chain a .then callback that will be executed once the foo resource finishes loading.

fetch('foo').then(response => /* do something */)

For example,

fetch('foo', (err, res) => {
  if (err) {
    // handle error
  // handle response

The callback wouldn’t be invoked until the foo resource has been fetched, so its execution remains asynchronous and non-blocking. Note that in this model you could only specify a single callback, and that callback would be responsible for all functionality derived from the response.
Few important points about Promises:

  • Follows the Promises/A+ specification, was widely implemented in the wild before ES6 was standarized (e.g bluebird)
  • Promises behave like a tree. Add branches with p.then(handler) and p.catch(handler)
  • Create new p promises with new Promise((resolve, reject) => { /* resolver */ })
    • The resolve(value) callback will fulfill the promise with the provided value
    • The reject(reason) callback will reject p with a reason error
    • You can call those methods asynchronously, blocking deeper branches of the promise tree
  • Each call to p.then and p.catch creates another promise that’s blocked on p being settled
  • Promises start out in pending state and are settled when they’re either fulfilled or rejected
  • Promises can only be settled once, and then they’re settled. Settled promises unblock deeper branches
  • You can tack as many promises as you want onto as many branches as you need
  • Each branch will execute either .then handlers or .catch handlers, never both
  • A .then callback can transform the result of the previous branch by returning a value
  • A .then callback can block on another promise by returning it
  • p.catch(fn).catch(fn) won’t do what you want — unless what you wanted is to catch errors in the error handler
  • Promise.resolve(value) creates a promise that’s fulfilled with the provided value
  • Promise.reject(reason) creates a promise that’s rejected with the provided reason
  • Promise.all(...promises) creates a promise that settles when all ...promises are fulfilled or 1 of them is rejected
  • Promise.race(...promises) creates a promise that settles as soon as 1 of ...promises is settled
  • Use Promisees — the promise visualization playground — to better understand promises

Generators in ES6

Generators are a new feature in ES6. You declare a generator function which returns generator objects g that can then be iterated using any of Array.from(g), [...g], or for value of g loops. Generator functions allow you to declare a special kind of iterator. These iterators can suspend execution while retaining their context.
Here is an example generator function. Note the * after function. That’s not a typo, that’s how you mark a generator function as a generator.

function* generator () {
  yield 'f'
  yield 'o'
  yield 'o'

A quick overview of Generators:

  • Generator functions are a special kind of iterator that can be declared using the function* generator () {} syntax
  • Generator functions use yield to emit an element sequence
  • Generator functions can also use yield* to delegate to another generator function — or any iterable object
  • Generator functions return a generator object that’s adheres to both the iterable and iterator protocols
    • Given g = generator(), g adheres to the iterable protocol because g[Symbol.iterator] is a method
    • Given g = generator(), g adheres to the iterator protocol because is a method
    • The iterator for a generator object g is the generator itself: g[Symbol.iterator]() === g
  • Pull values using Array.from(g), [...g], for (let item of g), or just calling
  • Generator function execution is suspended, remembering the last position, in four different cases
    • A yield expression returning the next value in the sequence
    • A return statement returning the last value in the sequence
    • A throw statement halts execution in the generator entirely
    • Reaching the end of the generator function signals { done: true }
  • Once the g sequence has ended, simply returns { done: true } and has no effect
  • It’s easy to make asynchronous flows feel synchronous
    • Take user-provided generator function
    • User code is suspended while asynchronous operations take place
    • Call, unsuspending execution in user code

I highly recommend you go over Axel’s article on generators, as he put together an amazing write-up on use cases for generators just a few months ago.

Iterators in ES6

JavaScript gets two new protocols in ES6, Iterators and Iterables. In plain terms, you can think of protocols as conventions. As long as you follow a determined convention in the language, you get a side-effect. The iterable protocol allows you to define the behavior when JavaScript objects are being iterated.
The code below is an iterable object in ES6.

var foo = {
  [Symbol.iterator]: () => ({
    items: ['p', 'o', 'n', 'y', 'f', 'o', 'o'],
    next: function next () {
      return {
        done: this.items.length === 0,
        value: this.items.shift()

Here is a quick snap-in of iterators:

  • Iterator and iterable protocol define how to iterate over any object, not just arrays and array-likes
  • A well-known Symbol is used to assign an iterator to any object
  • var foo = { [Symbol.iterator]: iterable}, or foo[Symbol.iterator] = iterable
  • The iterable is a method that returns an iterator object that has a next method
  • The next method returns objects with two properties, value and done
    • The value property indicates the current value in the sequence being iterated
    • The done property indicates whether there are any more items to iterate
  • Objects that have a [Symbol.iterator] value are iterable, because they subscribe to the iterable protocol
  • Some built-ins like Array, String, or arguments — and NodeList in browsers — are iterable by default in ES6
  • Iterable objects can be looped over with for..of, such as for (let el of document.querySelectorAll('a'))
  • Iterable objects can be synthesized using the spread operator, like [...document.querySelectorAll('a')]
  • You can also use Array.from(document.querySelectorAll('a')) to synthesize an iterable sequence into an array
  • Iterators are lazy, and those that produce an infinite sequence still can lead to valid programs
  • Be careful not to attempt to synthesize an infinite sequence with ... or Array.from as that will cause an infinite loop

Symbols in ES6

Symbols are a new primitive type in ES6. If you ask me, they’re an awful lot like strings. Just like with numbers and strings, symbols also come with their accompanying Symbol wrapper object.
We can create our own Symbols.

var mystery = Symbol()

Note that there was no new. The new operator even throws a TypeError when we try it on Symbol.

var oops = new Symbol()
// <- TypeError

For debugging purposes, you can describe symbols.

var mystery = Symbol('this is a descriptive description')

Symbols at quick glance:

  • A new primitive type in ES6
  • You can create your own symbols using var symbol = Symbol()
  • You can add a description for debugging purposes, like Symbol('ponyfoo')
  • Symbols are immutable and unique. Symbol(), Symbol(), Symbol('foo') and Symbol('foo') are all different
  • Symbols are of type symbol, thus: typeof Symbol() === 'symbol'
  • You can also create global symbols with Symbol.for(key)
    • If a symbol with the provided key already existed, you get that one back
    • Otherwise, a new symbol is created, using key as its description as well
    • Symbol.keyFor(symbol) is the inverse function, taking a symbol and returning its key
    • Global symbols are as global as it gets, or cross-realm. Single registry used to look up these symbols across the runtime
      • window context
      • eval context
      • <iframe> context, Symbol.for('foo') === iframe.contentWindow.Symbol.for('foo')
  • There’s also “well-known” symbols
    • Not on the global registry, accessible through Symbol[name], e.g: Symbol.iterator
    • Cross-realm, meaning Symbol.iterator === iframe.contentWindow.Symbol.iterator
    • Used by specification to define protocols, such as the iterable protocol over Symbol.iterator
    • They’re not actually well-known — in colloquial terms
  • Iterating over symbol properties is hard, but not impossible and definitely not private
    • Symbols are hidden to all pre-ES6 “reflection” methods
    • Symbols are accessible through Object.getOwnPropertySymbols
    • You won’t stumble upon them but you will find them if actively looking

Arrow Functions in ES6

Arrow functions are available to many other modern languages and was one of the features I sorely missed a few years ago when I moved from C# to JavaScript. Fortunately, they’re now part of ES6 and thus available to us in JavaScript. The syntax is quite expressive. We already had anonymous functions, but sometimes it’s nice to have a terse alternative.
Here’s how the syntax looks like if we have a single argument and just want to return the results for an expression.

[1, 2, 3].map(num => num * 2)
// <- [2, 4, 6]

The ES5 equivalent would be as below.

[1, 2, 3].map(function (num) { return num * 2 })
// <- [2, 4, 6]

If we need to declare more arguments (or no arguments), we’ll have to use parenthesis.

[1, 2, 3, 4].map((num, index) => num * 2 + index)
// <- [2, 5, 8, 11]

A cool aspect of arrow functions in ES6 is that they’re bound to their lexical scope. That means that you can say goodbye to var self = this and similar hacks – such as using .bind(this) to preserve the context from within deeply nested methods.

function Timer () {
    this.seconds = 0
    setInterval(() => this.seconds++, 1000)
var timer = new Timer()
setTimeout(() => console.log(timer.seconds), 3100)
// <- 3
  • Terse way to declare a function like param => returnValue
  • Useful when doing functional stuff like [1, 2].map(x => x * 2)
  • Several flavors are available, might take you some getting used to
    • p1 => expr is okay for a single parameter
    • p1 => expr has an implicit return statement for the provided expr expression
    • To return an object implicitly, wrap it in parenthesis () => ({ foo: 'bar' }) or you’ll get an error
    • Parenthesis are demanded when you have zero, two, or more parameters, () => expr or (p1, p2) => expr
    • Brackets in the right-hand side represent a code block that can have multiple statements, () => {}
    • When using a code block, there’s no implicit return, you’ll have to provide it — () => { return 'foo' }
  • You can’t name arrow functions statically, but runtimes are now much better at inferring names for most methods
  • Arrow functions are bound to their lexical scope
    • this is the same this context as in the parent scope
    • this can’t be modified with .call, .apply, or similar “reflection”-type methods
    • arguments is also lexically scoped to the nearest normal function; use (...args) for local arguments
  • Read ES6 Arrow Functions in Depth