Five different scenarios of this

Keywords: Javascript

Five different scenarios of this

Default

By default, pure function calls are regarded as Global calls, where this points to the Global object, which in the browser environment is also called the window object.

window.x = 'Jackie'

function func() {
  console.log(this.x)
}

func() // Jackie

In strict mode, this is forbidden to point to the global object, which is undefined.

Method calls as objects

This points to the object that calls this method.

var x = 'Property of Window'

var obj = {}
obj.x = 'Property of obj'
obj.f = function () {
    console.log(this.x)
}

obj.f() // Property of obj

// Notable circumstances
var f = obj.f
f() // Property of Window

Explicit binding of call, apply and bind

call, apply, and bind can all change the direction of this of a function.

call and apply

call and apply point this of their calling objects to their first parameter.

function f () {
  console.log(this.x)
}

var x = 'Property of Window'

var obj = {
  x: "Property of obj"
}

f.apply(obj)     // "Property of obj"

When the first parameter is undefined or not, this will automatically point to the Global object in the non-strict mode, the window object in the browser, and undefined in the strict mode:

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

f.apply()             // window
f.apply(undefined)     // window

function ff () {
  'use strict'
  console.log(this)
}
ff.apply()             // undefined
ff.apply(undefined) // undefined

call and apply are not essentially different. The only difference is that:

The call() method accepts a list of several parameters, while the apply() method accepts an array of multiple parameters.

bind

There is no essential difference between bind and the previous two, except that bind binds the first parameter to this of the calling function and returns the function (not executed).

function f () {
  console.log(this.x)
}

var x = 'Property of Window'

var obj = {
  x: "Property of obj"
}

var ff = f.bind(obj)
ff() // "Property of obj"

Constructor

When a function is used as a constructor to create a new object with the new keyword, this inside the function and this on the prototype chain will point to the new object.

function Jackie(para) {
  this.para = para
  console.log(this)
}
Jackie.prototype.log = function(){
  console.log(this)
}

Jackie('hehe')                 // Window
var p = new Jackie('haha')     // Jackie {para: "haha"}
p.log()                     // Jackie {para: "haha"}

Other noteworthy bindings

Put it in super-time code

The code for timeout calls in JavaScript is executed in global scope, so the value of this in the function points to the window object, as well as in strict mode. Because the code for timeout calls has an implicit binding: setTimeout(f, time) == setTimeout(f.bind(window), time).

"use stric"
var x = 'Property of Window'

var obj = {}
obj.x = 'Property of obj'
obj.ff = function () {
    setTimeout(
        function () {
            console.log(this.x)
        }, 100)
}

obj.ff()     // Property of Window

// That's how it works out.
obj.fff = function () {
    var that = this
    setTimeout(
        function () {
            console.log(that.x)
        }, 100)
}
obj.fff()     // Property of obj

this in the event listener function

this in the event listener function points to the listener object.

var one = document.getElementById('one')
one.onclick = function () {
  console.log(this)
};

one.click() // <div id="one"></div>

Arrow function

The direction of this in the arrow function is bound when the function is defined and cannot be changed later.

var obj = {
  x: 1
}

var f1 = () => {
  console.log(this)
}
f1.apply(obj) // Window

var f2 = function () {
  var f3 = () => {
    console.log(this)
  }
  return f3
}

var f4 = f2.apply(obj)
f4() // Object {x: 1}

A more magical example is that the code that calls a timeout binds the direction of this when it is defined.

function foo() {
  setTimeout(() => {
    console.log('id:', this.id);
  }, 100);
}

var id = 21;

foo.call({ id: 42 }); // id: 42

Priority of binding

var obj = {x: 0, name: 'obj'}
var robj = {x: -1, name: 'robj'}
var factory = function (x) {
  this.x = x
  console.log(this)
}

var factoryBind = factory.bind(obj)
robj.factory = factoryBind
robj.factory(2) // Object {x: 2, name: "obj"}, the priority of binding as a method is lower than the explicit binding of bind

factoryBind.call(robj, 3) // Object {x: 3, name: "obj"}, call has lower priority than bind
console.log(robj) // Object {x:-1, name:'robj', factory: function}, no modification to robj
console.log(obj) // Object {x: 3, name: "obj"}, modified obj, because this pointer pointed unchanged

var p = new factoryBind(4) // factory {x: 4}
console.log(p) // factory {x: 4}
console.log(obj) // Object {x: 3, name: "obj"}, the priority of constructor binding is higher than that of explicit binding of bind

As you can see, priority ranges from high to low:

  1. new, construct binding

  2. bind, explicit binding

  3. call/apply, showing bindings

  4. Binding as a method

  5. Default binding

Posted by trackz on Sun, 09 Jun 2019 13:24:12 -0700