JAVASCRIPT

Core concepts

the this keyword

the this object (also called the Context Object) is determined by how the function is invoked

 

this means that the value of this is evaluated at run-time

wait... what?

context types:

  • global context
  • function context
  • arrow function context (ES2015)
  • object method
  • getter methods
  • constructor methods
  • call, apply, bind
  • DOM event handlers

Global context

In the global execution context (outside of any function), this refers to the global object, whether in strict mode or not.

console.log(this.document === document); // true

// In web browsers, the window object is also the global object:
console.log(this === window); // true

this.a = 37;
console.log(window.a); // 37

function context

Inside a function, the value of this depends on how the function is called.

function f1(){
  return this;
}

f1() === window; // global object
function f2(){
  "use strict"; // see strict mode
  return this;
}

f2() === undefined;

Arrow function context

(ES2015)

In arrow functions, this is set lexically, i.e. it's set to the value of the enclosing execution context's this

var globalObject = this;
var foo = (() => this);
console.log(foo() === globalObject); // true

Object method context

When a function is called as a method of an object, its this is set to the object the method is called on.

var o = {
  prop: 37,
  f: function() {
    return this.prop;
  }
};

console.log(o.f()); // logs 37

GETTER method context

When a function is called as a method of an object, its this is set to the object the method is called on.

function sum(){
  return this.a + this.b + this.c;
}

var o = {
  a: 1,
  b: 2,
  c: 3,
  get average(){
    return (this.a + this.b + this.c) / 3;
  }
};

Object.defineProperty(o, 'sum', {
    get: sum, enumerable:true, configurable:true});

console.log(o.average, o.sum); // logs 2, 6

CONSTRUCTOR method context

When a function is used as a constructor (with the new keyword), its this is bound to the new object being constructed.

function C(){
  this.a = 37;
}

var o = new C();
console.log(o.a); // logs 37

call, apply & bind context

Where a function uses the this keyword in its body, its value can be bound to a particular object in the call using the call or apply methods that all functions inherit from Function.prototype.

function add(c, d){
  return this.a + this.b + c + d;
}

var o = {a:1, b:3};

add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16

add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34

DOM event handlers context

When a function is used as an event handler, its this is set to the element the event fired from

function bluify(e){
  console.log(this === e.currentTarget); 
  console.log(this === e.target);
  this.style.backgroundColor = '#A5D9F3';
}

// Get a list of every element in the document
var elements = document.getElementsByTagName('*');

// Add bluify as a click listener so when the
// element is clicked on, it turns blue
for(var i=0 ; i<elements.length ; i++){
  elements[i].addEventListener('click', bluify, false);
}

Closures

Closures are functions that refer to independent (free) variables (variables that are used locally, but defined in an enclosing scope). In other words, these functions 'remember' the environment in which they were created.

adica...

function init() {
  var name = "JS Internship"; // name is a local variable created by init
  function displayName() { // displayName() is the inner function, a closure
    alert(name); // use variable declared in the parent function    
  }
  displayName();    
}
init();

Example I

function makeFunc() {
  var name = "JS Inernship";
  function displayName() {
    alert(name);
  }
  return displayName;
}

var myFunc = makeFunc();
myFunc();

Example II

function makeAdder(x) {
  return function(y) {
    return x + y;
  };
}

var add5 = makeAdder(5);
var add10 = makeAdder(10);

console.log(add5(2));  // 7
console.log(add10(2)); // 12

Example III

Emulating private methods with closures

var counter = (function() {
  var privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }
  return {
    increment: function() {
      changeBy(1);
    },
    decrement: function() {
      changeBy(-1);
    },
    value: function() {
      return privateCounter;
    }
  };   
})();

console.log(counter.value()); // logs 0
counter.increment();
counter.increment();
console.log(counter.value()); // logs 2
counter.decrement();
console.log(counter.value()); // logs 1

Creating closures in loops:

A common mistake

var arr = [];
var i = 0;

for (i = 0; i < 10; i++) {
     arr[i] = function() {
         console.log(i);
     }
}

arr[3]();
arr[4]();

What will this output?

Day II: JavaScript - Core concepts

By Andrei Cacio

Day II: JavaScript - Core concepts

this & closures

  • 1,454