This default binding

The situation in which a function is called without any call prefix is called default binding. When bound by default, this points to a global object (in non-strict mode).

function fn1() {
    let fn2 = function() {
        console.log(this);    // window
    }
    console.log(this);    // window
    fn2()
}

fn1();
Copy the code

Note: In strict mode, the default binding this refers to undefined; However, calling a function in strict mode that is not in strict mode does not affect this pointing.

function fn() { console.log(this); //window console.log(this.name); }; function fn1() { "use strict"; fn(); // Call the function console.log(this) that is not in strict mode; //undefined console.log(this.name); } var name = ""; fn(); Fn1 (); /* undefined TypeError: Cannot read property 'name' of undefined */Copy the code

This is implicitly bound

When a function is called, this is implicitly bound to the object on which it was called.

function fn() { console.log(this.name); } let obj = {name: 'func', func: fn} obj.func(); // 'My heart is in the forest'Copy the code

If there are more than one object before a function call, this refers to the closest (innermost) object to the call itself.

function fn() { console.log(this.name) }; Let obj = {name: func: fn}; Let obj1 = {name: 'obj', obj: obj}; obj1.obj.func(); // I have a heartCopy the code

Consider this question: If we delete name from obj at this point, what will be printed?

a. undefinded; B. ‘Heart to heart’

Undefined, of course. Obj is a property of obj1, but its two prototype chains are not the same and are not parent-child, so if obj does not provide a name property, undefined will be printed.

function Fn() {}; Fn. Prototype. Name = 'prototype'; function fn() { console.log(this.name); }; const obj = new Fn(); obj.func = fn; Const obj1 = {name: 'heart', o: obj}; obj1.o.func(); // 'My heart is in the forest'Copy the code

Although the obj object does not have a name attribute, it follows the stereotype chain to find the constructor Fn that generates itself, and then finds the name attribute in the Fn stereotype chain.

The difference between a scope chain and a prototype chain: When accessing a variable, the interpreter first looks for the identifier in the current scope. If not, the interpreter looks for the identifier in the parent scope. At the top of the scope chain is the global object Window.

When an attribute is accessed on an object, the current object is searched first. If not, the current object is searched up the prototype chain, and null is found at the top of the prototype chain. If not, undefined is returned.

Implicit loss: Implicit binding loss can occur in certain situations, most commonly passing as arguments and assigning values to variables.

// const name = 'heart, heart'; Const obj = {name: 'mind ', fn: function() {console.log(this.name); } } funciton fn1(func) { func(); } fn1(obj.fn); // 'My heart is in the forest'Copy the code

In this example, we pass obj.fn as an argument to fn1. This is not bound to the function, so this is lost and refers to the window.

// Const name = 'xinyuxi'; Const obj = {name: 'mind ', fn: function() {console.log(this.name); } } let fn1 = obj.fn; fn1(); // 'My heart is in the forest'Copy the code

Note: Implicit binding losses do not always point to global objects

Const name = 'heart, heart'; Const obj = {name: 'mind ', fn: function() {console.log(this.name); }} const obj1 = {name: 'I don't want to see it'}; obj1.fn1 = obj.fn; obj1.fn1(); // 'Mind acts upon mind'Copy the code

Although the implicit binding of obj is missing, a new implicit binding is created during assignment, where this points to the object obj1.

This is explicitly bound

Changing the reference to this through call, apply, and bind is called explicit binding.

Let obj1 = {name: 'heart has linxi '}; Let obj2 = {name: 'mind '}; Let obj3 = {name: 'mind, mind '}; Const name = '1'; function fn() { console.log(this.name); }; fn(); Fn. call(obj1); // apply(obj2); Fn. Call (obj3)(); // Mind acts upon mindCopy the code

In JS, when we call a function, we’re used to calling it a function call, and the function is in a passive state; However, call and apply change functions from passive to active, and functions can actively choose their own context, so this writing method is also called function application.

Note: If the reference argument is supplied with null or undefined when this is changed using a method like call, this will point to the global object.

Let obj1 = {name: 'heart has linxi '}; Let obj2 = {name: 'mind '}; Let obj3 = {name: 'mind, mind '}; Const name = '1'; function fn() { console.log(this.name); }; fn(); // call(undefined); // fn.apply(null); Fn. Call (undefined)(); / / first whiffCopy the code

What’s the difference between call, apply and bind?

  1. Call, apply, and bind are all used to change the this binding, but call and apply change this while executing the function, and bind returns a new boundFunction binding after changing this. This is why bind is followed by a bunch of parentheses in the example above.
  2. Bind is hard bound, and the returned this pointer of the bound Function cannot be changed again by bind, apply, or call; The call/apply binding only applies to the current call, then disappears and must be bound again the next time it is used.
  3. Call functions exactly the same as apply, except that the call method passes function call parameters as hashes, whereas the Apply method takes an array of parameters. In the case of passing arguments, call performs better than Apply because Apply executes without parsing the array.
// difference 2: let obj1 = {name: 'heart has linxi'}; Let obj2 = {name: 'mind'}; Var name = 1; function fn() { console.log(this.name); }; fn.call(obj1); // the heart has Lin Xi fn(); Fn. apply(obj2); // fn(); // let boundFn = fn.bind(obj1); Call (obj2); // apply(obj2); Bind (obj2)(); // 表 三 : let obj = {name: 'obj'}; Function fn(age, desc) {console.log(' I am ${this.name}, I am ${age}, I am ${desc}! ')} fn. Call (obj, 18, 'handsome '); Fn. Apply (obj, [18, 'handsome ']);Copy the code

application

Math.max(1, 10); //10 Math.min(1, 10); //1 Math.max.apply(null, [1, 2, 10]); //10 Math.min.apply(null, [1, 2, 10]); Let a = []; let b = function () {}; Object.prototype.toString.call(a) === "[object Array]"; //true Object.prototype.toString.call(b) === "[object Function]"; //trueCopy the code

The new binding

New A function can be roughly divided into three steps:

  1. Create a new object based on the constructor’s Prototype property.
  2. Pass this(which can be interpreted as the new object created in the first step) and the call parameters to the constructor, execute;
  3. If the constructor does not manually return an object, the object created in the first step is returned.

The new procedure creates a new object that inherits the stereotype of the constructor and its properties, and is eventually returned as an instance of a procedure called a construct call.

Function Fn() {this.name = '.name '; } const echo = new Fn(); console.log(echo.name); // The heart is readyCopy the code

Priority of this binding

Display Binding > Implicit Binding > Default binding

New Binding > Implicit binding > Default binding

There is no display binding and new binding in effect at the same time.

Arrow function this

The this in the arrow function does not apply to the four binding rules described above. To be exact, the arrow function does not have this. The arrow function’s this points to this in the outer scope. The arrow function’s this points to whoever the outer scope or function’s this points to.

function fn() { return () => { console.log(this.name); }; } let obj1 = {name: 'I have a heart'}; Let obj2 = {name: 'mind'}; let bar = fn.call(obj1); // fn this points to obj1 bar.call(obj2); // The heart is readyCopy the code

So the question is, why did the first binding of this return arrow function not change this pointer again?

The arrow function this also has the property that once the arrow function this is bound, it cannot be modified again. But we can modify the arrow function this indirectly by modifying the outer function this pointer.

function fn() { return () => { console.log(this.name); }; } let obj1 = {name: 'I have a heart'}; Let obj2 = {name: 'mind'}; fn.call(obj1)(); Call (obj2)(); // Mind is like mindCopy the code