Scope and closures in JavaScript

  • Function scope

  • Scope chains

  • Block scope

  • Hoisting

What is scope?

Scope is the set of variables you have access to.

Function scope

function bar() {
    var foo = 'local value'
    console.log(foo)
}

bar() // ?

console.log(foo) // ?
function bar() {
    var foo = 'local value'
    console.log(foo)
}

bar() // 'local value'

console.log(foo) // foo is not defined
function someFunc(){

    var outerVar = 1;
    console.log(innerVar)
    console.log(outerVar)
  
    function zip(){
        var innerVar = 2;
        console.log(innerVar)
        console.log(outerVar)
    }
  
    zip()
}

someFunc()

// ?
function someFunc(){

    var outerVar = 1;
    console.log(innerVar)
    console.log(outerVar)
  
    function zip(){
        var innerVar = 2;
        console.log(innerVar)
        console.log(outerVar)
    }
  
    zip()
}

someFunc()

//Uncaught ReferenceError: innerVar is not defined

The inner function has access to the outer function. But not vice versa.

function someFunc(){

    var outerVar = 1;
    //console.log(innerVar)
    console.log(outerVar)
  
    function zip(){
        var innerVar = 2;
        console.log(innerVar)
        console.log(outerVar)
    }
  
    zip()
}

someFunc()

// ?

function someFunc(){

    var outerVar = 1;
    //console.log(innerVar)
    console.log(outerVar)
  
    function zip(){
        var innerVar = 2;
        console.log(innerVar)
        console.log(outerVar)
    }
  
    zip()
}

someFunc()

//1
//2
//1

Functions cannot access sibling function scopes.

function someFunc(){

	function zip(){
		var sibling1 = 'hey'
		console.log(sibling2)
	}

	function quux(){
		var sibling2 = 'hi'
		console.log(sibling1)
	}

	zip()
	quux()
}

someFunc()

// ?
function someFunc(){

	function zip(){
		var sibling1 = 'hey'
		console.log(sibling2)
	}

	function quux(){
		var sibling2 = 'hi'
		console.log(sibling1)
	}

	zip()
	quux()
}

someFunc()

//sibling1 and sibling2 are undefined

Scope chains

If a variable is in scope, it is closed over. That is a closure.

Closure uses the concept of scope to build up a list of what variables are available to it.

Block scope

The new ES6 keyword 'let' allows for block scoping.

var things = ['a', 'b', 'c']

for(let i = 0; i < things.length; i++){

    console.log(things[i])

}

console.log(i)

// ?
var things = ['a', 'b', 'c']

for(let i = 0; i < things.length; i++){

    console.log(things[i])

}

console.log(i)

//a

//b

//c

//Uncaught ReferenceError: i is not defined
var things = ['a', 'b', 'c']

for(var i = 0; i < things.length; i++){

    console.log(things[i])

}

console.log(i)

// ?
var things = ['a', 'b', 'c']

for(var i = 0; i < things.length; i++){

    console.log(things[i])

}

console.log(i)

//a

//b

//c

//3

Unlike C#, all variables declared with the keyword 'var' get hoisted to the top of the function. 

Hoisting

The variable gets

  • declared at the top of the nearest function,
  • assigned now,
  • and the reference persists to the end of the function.
function addToQueue(names, queueLength){
  var positions = []

  for (var i = 0; i < names.length; i++) {
    positions[i] = function() {
      return queueLength + i + 1
    }
  }
  console.log(positions)
  console.log(i)
  return positions
}

var people = ['Ash', 'Kelly']
var queuePositions = addToQueue(people, 10)

console.log(queuePositions[0]()) // 13?! Should be 11
console.log(queuePositions[1]()) // 13 As well! Should be 12

http://bit.ly/1XsCRFO

Solutions

http://bit.ly/24UXp9k

Made with Slides.com