Skip to content

Instantly share code, notes, and snippets.

@k26dr
Last active June 14, 2016 19:07
Show Gist options
  • Save k26dr/1992731d8cd0b64ad0b0 to your computer and use it in GitHub Desktop.
Save k26dr/1992731d8cd0b64ad0b0 to your computer and use it in GitHub Desktop.
Javascript context and scope

Context and Scope in JS


Review

  1. What is variable hoisting?
  2. What are the rules of lexical scoping?
  3. What is the value of this in an event handler?

Context vs Scope

  • Scope: Either the global scope or the current function
  • Context: Whatever this is equal to when you console.log it

Scope Practice

// What will this snippet of code output?

var tiredSoul = "Adam Ewing";
var futureSelf = "Zachry";

function logMe () {
  var tiredSoul = "Luisa Rey";
  var sensedConnection = "Robert Frobisher";

  console.log(tiredSoul, sensedConnection, futureSelf);
}
logMe()

Scope Practice

// What will this snippet of code output?

for(var i = 0; i < 10; i++) {
  console.log(i);
  document.addEventListener('DOMContentLoaded', function() {
    console.log(i);
  }); 
}

Variable Hoisting

// What does this output?

var x = 2
function hoister () {
    console.log(x)
    x = 3
}
hoister()

Variable Hoisting

// What does this output?

var x = 2
function hoister () {
    console.log(x)
    var x = 3
}
hoister()

Context

// What does this output?
var a = 2
console.log(this.a) // it matters...

Default Context

  • Browser: global window object
  • Node Console: global object
  • Node Script: empty object {}
  • Never rely on default contexts: Bad Pratice

Context

// What does this output in the browser? In the Node console? In a Node script?

var a = 2
function context() {
  var a = 3
  console.log(this.a)
}
context()

Context

var obj = {
  a: 2,
  b: function () {
    console.log(this.a)
  }
}
obj.b() // What's the output?

Context

// What's the output when you click on a page?

document.addEventListener('click', function () {
  console.log(this)
})

Context

var obj = {
  a: 2,
  b: function () {
    console.log(this.a)
  }
}

// What's the output on a click?
document.addEventListener('click', obj.b)

Setting the context

  • 3 Javascript functions for modifying context
  • .bind(context)
  • .apply(context, [function_args])
  • .call(context, function_arg1, function_arg2)

.bind

Creates a copy of a function with a modified context


.bind example

function sameSoul(soulC, soulD){
  return this.soulA + " is " + this.soulB + " is " + soulC + " is " + soulD + "!";
}

var noGood = {
  soulA: "Colonel Mustard",
  soulB: "Henry Goose",
}

var badSouls = sameSoul.bind(noGood);

badSouls("Professor Plum", "Mrs. Peacock"); // "Colonel Mustard is Henry Goose is Professor Plum is Mrs. Peacock!"

.bind

// Modify this code so that it prints 2 on a click event

var obj = {
  a: 2,
  b: function () {
    console.log(this.a)
  }
}

document.addEventListener('click', obj.b)

.call & .apply

  • Same functionality, different syntax
  • Executes a function with a specified context
myFunction.call(context, arg1, arg2)
myFunction.apply(context, [arg1, arg2])

.call example

var obj = {
  a: 2
}

function badAddition (b) {
  return this.a + b
}

badAddition(3) // NaN
badAddition.call(obj, 3) // 5

.apply example

function sameSoul(soulC, soulD){
  return this.soulA + " is " + this.soulB + " is " + soulC + " is " + soulD + "!";
}

var noGood = {
  soulA: "Colonel Mustard",
  soulB: "Henry Goose",
}

sameSoul.apply(noGood, ["Professor Plum", "Mrs. Peacock"]); // "Colonel Mustard is Henry Goose is Professor Plum is Mrs. Peacock!"

Your turn

function log () {
  console.log(this.firstChild)
}

document.addEventListener('click', function () {
  log() // modify this line with .call so that it prints the document's first child element
})

.apply

// Modify this to print Keyan instead of Grant
// 1) Modify it using .bind
// 2) Modify it using .apply

this.wanderinSoul = "Grant";

var lemniscate = {
  wanderinSoul: "Keyan",
  getWanderer: function() { return this.wanderinSoul; }
};
var endingSoul = lemniscate.getWanderer;
endingSoul();

In conclusion

  • Scopes are well defined. Use them wisely.
  • Conflicting variable names across different scopes cause weird errors. Avoid them
  • Context is a difficult beast. Avoid it unless necessary. Explicit over implicit
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment