This is the 11th day of my participation in the August More text Challenge. For details, see: August More Text Challenge

The this of each function is bound at the time it is called, depending entirely on where the function is called, which is where in the code the function is called (rather than where it is declared).

I. Binding rules

This always points to the object that last called it

Misconceptions about this: this refers to the function itself, and this refers to the function scope.

  • This is bound at run time, depending entirely on where the function is called
  • Is not bound at writing-time, and its context depends on various conditions at the time of the function call.

⚠️ : The scope chain is based on lexical scope and this is based on dynamic scope.

1.1 Default Binding

When a function is called directly with an undecorated function reference, it is bound to a global object or undefined (in strict mode)

function foo() {    
  console.log(this.a);
}

var a = 2;
foo();/ / 2
Copy the code

1.2 Implicit binding

An implicit binding rule binds this in a function call to the context object

function foo() {    
  console.log(this.a);
}

var obj2 = {
    a: 42.foo: foo
};

var obj1 = {
    a: 2.obj2: obj2
}

obj1.obj2.foo();/ / 42
Copy the code

Note: Only the previous or last level in the chain of object property references counts in the call location

1.2.1 Implicit loss

Implicitly bound functions lose the binding object, that is, default binding, which binds this to the global object or undefined

function foo() {    
  console.log(this.a);
}

var obj = {
  a: 42.foo: foo
};

var bar = obj.foo; // Function alias
var a = "oops";

bar(); // "oops"
Copy the code
// When the callback function is passed
function foo() {    
  console.log(this.a);
}

function doFoo(fn) {
  // fn refers to foo
  fn(); // <-- call location
}

var obj = {
  a:42.foo: foo
};

var a = "oops";
doFoo(obj.foo);// oops
Copy the code
// setTimeout() also loses this binding
function foo() {    
  console.log(this.a);
}

var obj = {
  a:42.foo: foo
};

var a = "oops";
setTimeout(obj.foo, 100);
Copy the code

It is very common for callbacks to lose this binding

1.3 Explicit binding

Call (), apply()

function foo() {    
  console.log(this.a);
}

var obj = {
  a:2
};

foo.call(obj); / / 2
Copy the code

The difference is that the second argument, call (), is an input argument, whereas apply () is an array of arguments

1.3.1 hard binding

The function bar() is created first, and foo.call(obj) is manually called inside it, so that foo’s this is bound to obj. No matter how bar is later called, it will always manually call foo on obj. This binding is a display binding and is called a hard binding.

function foo() {    
  console.log(this.a);
}

var obj = {
  a:2
};

var bar = function() {
  foo.call(obj);
}

bar(); / / 2
setTimeout(bar, 100); / / 2
bar.call(window); / / 2
Copy the code

A typical application scenario is to create a wrapper function that accepts parameters and returns values.

function foo(something) {    
  console.log(this.a, something);
  return this.a + something;
}

var obj = {
  a: 2
}

var bar = function() {    
  return foo.apply(obj, arguments);
};

var b = bar(3); / / 2, 3
console.log(b);/ / 5
Copy the code

We can then create a function that can be reused:

function foo(something) {    
  console.log(this.a, something);
  return this.a + something;
}

var obj = {
  a: 2
}

function bind(fn, obj) {
  return function() {
    return fn.apply(obj, arguments); }}var bar = bind(foo, obj);

var b = bar(3); / / 2, 3
console.log(b);/ / 5
Copy the code

Bind () returns a hard-coded new Function that sets the argument you specify to the context of this and calls the original Function.

1.3.2 Context of the API call

Many functions in third-party libraries, as well as many new built-in functions in the JavaScript language and host environments, provide an optional argument, often referred to as the “context.”

function foo(el){
  console.log(el, this.id);
}

var obj = {
  id: 'a'
}

// Bind this to obj when calling foo
[1.2.3].forEach(foo, obj);
// 1 a 2 a 3 a
Copy the code

1.4 the new binding

There is no such thing as a “constructor,” only a “construct call” to a function.

function foo(a) {    
  this.a = a;
}

var bar = new foo(2);
console.log(bar.a); / / 2
Copy the code

When we call foo with new, we construct a new object and bind it to this in the call to foo().

1.5 Rule Supplement

1.5.1 priority

New binding > Explicit binding > Implicit binding > Default binding

1.5.2 Binding Exception

The default binding rules apply below

call(null/undefined)
apply(null[2.3])
bind(null.2)
Copy the code

1.5.3 this lexical

Instead of using the four binding rules, the arrow function in ES6 determines this based on the current lexical scope.

The arrow function inherits the this binding from the outer function call, which is actually the same as the self = this mechanism in the code before ES6.

function foo() {
  // Return an arrow function
  return (a) = > {
    // this inherits from foo()
    console.log(this.a);
  };
}

var obj1 = {
  a: 2
};
var obj2 = {
  a: 3
};

var bar = foo.call(obj1);
bar.call(obj2); / / 2
Copy the code

The arrow function created inside foo() captures the this of foo() when called. Since foo() ‘s this is bound to obj1, bar (referring to the arrow function)’ s this is bound to obj1, and the arrow function binding cannot be modified.

There is no “this” in the arrow function. The “this” in this function depends only on the “this” of the first function outside of it that is not an arrow function. In the following example, this is window because calling a matches the first case in the previous code. And once this is context-bound, it will not be changed by any code.

function a() {
  return () = > {
    return () = > {
      console.log(this)}}}console.log(a()()()) // window
Copy the code