This misunderstanding

1. This refers to the function itself by default.

In any case, this does not refer to the function itself by default, unless you bind this to the function itself.

2. This refers to a function scope or context object.

In any case, this does not refer to a function’s lexical scope or context object by default. A scope or context object does resemble an object, with visible identifiers as attributes, but it only exists inside the JS engine and cannot be accessed in the JS environment.

What is this

In essence, there are two working models of scope, one is lexical scope and the other is dynamic scope.

1. Lexical scope: Lexical scope refers to the scope generated at the lexical stage, which is determined by the variables and the position of the scope that the writer writes when writing code. The engine uses this location information to find the location of identifiers, or variables. For example, no matter where or how a function is called, its lexical scope is determined only by where it is declared.

2. Dynamic scope: Dynamic scope is a form that is determined dynamically at run time, not statically. Dynamic scopes do not care about how functions and scopes are nested or where they are declared, only where they are called, that is. Its scope chain is based on call stack rather than scope nesting. Ex. :

function foo(){ 
    console.log(a); 
} 
function bar(){ 
    var a=3; 
    foo(); 
} 
var a=2; 
bar(); 
Copy the code

For lexical scope, the final print is 2 according to the scope rules. But the dynamic scope goes down the call stack looking for variables, so it prints 3.

Js scope rules are lexical scope rules.

The mechanism of this is similar to that of dynamic scoping. This is bound at run time, not at write time, and its context depends on the condition at call time. The this binding is independent of where the function is declared and depends on how the function is called.

When a function is called, an active record (also known as an execution context object) is created. The record object contains information about the function call stack, how it was called, incoming parameters, and so on. This is a property of this record.

The call stack

The call stack is actually the chain of calls to a function, and the current function is called in the second to last position of the call stack. Example:

// global scopefunction func(val) {
    if(val <= 0) return;
    console.log(val);
    func(val-1);
}
func(5);
Copy the code

The execution stack is used to store the execution environment of the runtime. Of course, the stack follows a first in, last out rule.

The stack of the above code is as follows: Create global execution environment => func(5) => func(4) => func(3) => func(2) => func(1).

When the destruction is complete: func(1) => func(2) => func(3) => func(4) => func(5) => Create a global execution environment.

This binding rule (the above part can not be remembered at all, as long as this part is remembered, will be sufficient)

1. Default binding

Generated when a stand-alone function call can be understood as a default rule when no other rule can be applied. The default binding, this, points to the global Window object in non-strict mode, and undefined in strict mode. Example: Calling a function directly is itself the default binding

function func(){
	console.log('this',this); } func(); //this,Window...Copy the code
function func() {'use strict'
	console.log('this',this); } func(); //this,undefinedCopy the code

Ps1: The following rules assume the function environment, that is, this is executed inside the function body. In a non-functional environment, that is, in the browser’s global scope, this will always point to window regardless of mode. A bit of fun: the global object in the browser environment is the window, but there is a special keyword, globalThis, that prints the object in the browser environment, pointing to the window. (PS1 point of view thanks to @ru advance big guy’s special point.)

Console. log(this); // console.log(this); //windowCopy the code
// global scope'use strict'console.log(this); //windowCopy the code
function func(){ console.log(globalThis); } func(); //windowCopy the code

ps2: This refers to undefined at runtime if “use strict” is added to the lexical scope of this when it is written or declared. However, if “use strict” is not added to the lexical scope of this when it is run or called, this does not matter. Still pointing to window.

function func() {'use strict'
	console.log('this',this); } func(); //this,undefinedCopy the code
function func(){
	console.log('this',this);
}
function bar() {'use strict'func(); } bar(); //this,windowCopy the code

Ps3: In strict mode, if the execution body is not written, this refers to window. In strict mode, if the execution body is not written, this refers to undefined.

2. Implicit binding

Determines whether the call location has a context object or an execution body. Simply put, if an object calls a method it “owns”, this in the method will refer to the object (only the last or upper level of the object attribute reference chain is involved in the call location, e.g. A.B.C. Func (), this in func refers only to c objects).

var obj = {
    name:'myself',
    func:function(){ console.log(this.name); } } obj.func(); //myselfCopy the code
Function methods do not belong to objects

When it comes to the relationship between an object and its methods, it is common to think of methods as belonging to an object. This is a misconception. Functions never belong to an object, even though they are methods of objects. The relationships that exist are only referential relationships. Example 1:

// Declare a function on the property of the object var obj = {foo:function func(){}
}
Copy the code

Example 2:

// Declare a function independently and reference it with the object's propertiesfunction func(){}
var obj = {
    foo:func
}
Copy the code

The effect of the above two examples is the same, there is no essential difference, it is clear that the function belongs to the scope in which it was declared; We all know that functions are essentially stored in heap memory, and the reference address of a function is stored in stack memory for us to access, so in fact the properties in the object only hold the reference address of the function that exists in stack memory.

If holding a reference address is regarded as a kind of ownership relationship, a function’s address can be held by countless variable references, and then all variables can be regarded as owning the function. However, the ownership relationship is unique, so this argument does not hold.

Implicit loss, that is, indirect reference

Example 1:

var b = {
    func:function(){}
}
var a=b.func;  
a();
Copy the code

Example 2:

var b = {
    func:function(){}
}
function foo(fn){
    fn();
}
foo(b.func)
Copy the code

In both cases, the “this” reference is lost, as we did in the “function method does not belong to an object” section above. Here, both a and fn(passing arguments is an implicit assignment, as is passing functions) get only the reference address of the function.

Let’s modify the above two examples to make it clear.

Example 1:

function bar(){} var b = { func:bar } var a=b.func; Var a=bar; a();Copy the code

Example 2:

function bar(){}
var b = {
    func:bar
}
functionfoo(fn){ fn(); } foo(b.foo) // equivalent to foo(bar);Copy the code
3. Explicit binding

In implicit binding, when a method executes, the object contains a property that points to the function, and through this property indirectly references the function, thus implementing the This binding.

The same is true for explicit binding, which is enforced by call,apply, etc. (If input strings, booleans, numbers, etc., are used as this binding objects, these primitive types will be converted to object types, such as New String, New Boolean,new Number, etc.). This action is called boxing. Binding Example 1:

var a = 1;
function func(){ console.log(this.a); } var obj = { a:0 } func.apply(obj); / / 0Copy the code

Binding Example 2:

var a = 1;
function func(){ console.log(this.a); } var obj = { a:0 } func.call(obj); / / 0Copy the code

However, this still does not solve the problem of missing bindings (for example, callbacks cannot be called by call or apply because callbacks cannot be called by human intervention).

Sample code:

var a = 1;
function func(){
    console.log(this.a);
}
var obj = {
    a:0
}
setTimeout(func.call(obj),1000); // Execute immediately, unable to meet the requirement of delayed executionCopy the code
Hard binding in explicit binding

Bind is hard binding, and the new function can be used without losing the binding by wrapping the callback function with the hard binding of the BIND method (using the kerochemistry technology, which relies on closures).

Example:

var a = 1;
function func(){
    console.log(this.a);
}
var obj = {
    a:0
}
var newFunc = func.bind(obj);
setTimeout(newFunc,1000); // Prints 0 after 1 second delayCopy the code
Soft binding in explicit binding

Hard binding reduces the flexibility of the function and makes it impossible to modify this using either implicit or explicit binding.

Example:

function func(){ console.log(this.a); } var obj = { a:0 } var o = { a:2 } var newFunc = func.bind(obj); newFunc.apply(o); / / 0Copy the code

In order to solve the problem of flexibility, we can try a new shiM binding method based on the principle of hard binding – soft binding.

Example:

Function.prototype.softBind = function(self){
    var func = this;
    var oldArg = [...arguments].slice(1)
    return function(){ var newArgs = oldArg.concat([...arguments]); var _this = (! this || this === window) ? self : this; func.apply(_this,newArgs) } }function func(){ console.log(this.a); } var obj = { a:0 } var o = { a:2 } var newFunc = func.softBind(obj); newFunc(); //0 newFunc.apply(o); / / 2Copy the code

Core code:

var _this = (! This | | this = = = Windows)? self:this; // If this is bound to global or undefined, retain the binding that wrapped softBind when it was called, otherwise modify this to the current new this.Copy the code

Many of ps: JS built-in functions provide optional parameters to implement binding context objects, such as forEach, map, filter, etc. The first parameter is the callback function, the second is the binding context object.

4. The new binding

In traditional languages, constructors are special methods in a class that are called when a class is initialized with new. The so-called “constructors” in JS are just ordinary functions that do not belong to a class and do not instantiate a class. There are no constructors in JS, only constructor calls to functions. When calling a function (construct call) with new,

  • Execute function;
  • Create a new object (the function call in the new expression automatically returns the new object if no other object is returned, and this is bound to the returned object if no other object is returned);
  • The new object will be connected by the implementation prototype;
  • The new object is bound to the function call’s this.
function func(name){
    this.name = name;
    this.printName = function(){
        console.log(this.name);
    }
}
var instance = new func('myself'); instance.printName(); //myselfCopy the code
function func(name){
    this.name = name;
    this.printName = function(){
        console.log(this.name);
    }
    return {
        name:'yourself'.printName:function(){
            console.log(this.name);
        }
    }
}
var instance = new func('myself'); instance.printName(); //yourselfCopy the code
priority

New Binding > Explicit Binding > Implicit Binding > Default binding.

Implicit binding > Default binding
var name = window;
function func(){
    console.log(this.name);
}
var obj = {
    name:'obj'.printName:func } obj.printName(); //objCopy the code
Explicit binding > Implicit binding
var obj = {
    name:'obj'.printName:function (){
        console.log(this.name);
    }
}
var other = {
    name:'other'} obj.printName.apply(other); //other obj.printName.call(other); //otherCopy the code
New Binding > Explicit binding
function func(name){
    this.name = name;
}
var obj = {};

var foo = func.bind(obj);
foo('obj'); console.log(obj.name); //obj var bar = new foo('instance'); console.log(obj.name); //obj console.log(bar.name); //instanceCopy the code
Arrow function this binding

Depending on the lexical scope of the function, simply put, the this binding in the arrow function inherits from the this binding in the function’s scope.

var name = 'window';
var obj = {
    name:'obj'.printName:()=>{ console.log(this.name); } } obj.printName(); //windowCopy the code

The arrow function does not have its own this, so you cannot use bind, apply, or call to modify its this pointer, which still points to the same this inherited from the declaration.

var name = 'window';
var printName = () => {
        console.log(this.name);
    }
var instance = {
    name:'instance'
}
var callIns = printName.bind(instance); callIns(); //'window'

printName.apply(instance); //'window'

printName.call(instance); //'window'
Copy the code

Bind can’t change its this pointer, but it can still be preparameterized. The parameter passing of apply and call is also valid.

var func = (param) => {
    console.log(this);
    console.log(param);
}
var obj = {}
var foo = func.bind(obj,'hellow');
foo();
//window
//'hellow'
Copy the code

Ps: Arrow functions don’t have their own This and arguments objects.

var func = (param) => {
    console.log('arguments',arguments);
}
func('param'); //Error,arguments is not definedCopy the code

Write in the last

I want to make it clear that I’m not a professor, I’m just a sharer, a discussant, a learner with a different opinion or a new idea, come forward and we’ll work on it together. While sharing, it is not only the sharer who is learning and improving, but also the sharer.

Knowledge is everywhere, and when it is gathered, it is yours.

Since useful, might as well like, let more people understand, learn and improve.

Ps: I appreciate well-intentioned communication, of course, malicious attacks are not out of the question. Give me reliable evidence to convince me, not sensationalism and lack of connotation.