1, About this

This is one of the most complex mechanisms in JavaScript and it’s a very special keyword that is custom defined in the scope of all functions.

function identify(){
    return this.name.toUpperCase();
}

function speak(){
    var greeting = "Hello,I am "+identify.call(this)
    console.log(greeting)
}
var me={
    name:"Good"
}
var you={
    name:"Morning"
}
identify.call(me)
identify.call(you)

speak.call(me)
speak.call(you)
Copy the code

This provides an elegant way to implicitly “pass” an object reference, so the API can be designed to be more compact and easy to reuse.

This does not refer to the function itself or its lexical scope; this is actually a binding that occurs when the function is called, and what it refers to depends entirely on where the function is called.

2. Binding rules

2.1 Default Binding

The most common type of function call: standalone function call. This rule is the default when no other rule can be applied.

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

var a=2;

foo();/ / 2
Copy the code

First, a variable declared in global scope is an attribute of the same name of the global object, which is essentially the same thing. When foo() is called, this.a is resolved to the global variable a. The default binding for this is applied when the function is called, so this points to the global object.

If strict mode is used, global objects cannot be used for the default binding, so this is bound to undefined:

function foo(){
    "use strict";
    console.log(this.a);
}
var a=2;
foo();//TypeError:this is undefined
Copy the code

The default binding can only be bound to global objects when foo() is not running in strict mode; Calling foo() in strict mode does not affect the default binding

2.2 Implicit binding

Another rule to consider is whether the calling location has a context object, or whether it is owned or contained by an object.

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

var obj={
    a:2.foo:foo
};
obj.foo();/ / 2
Copy the code

The way foo() is declared, and later added to obj as a reference property, indicates that this function is not an OBj object. However, the calling location references the function using the OBJ context, so the OBJ object can be said to “own” or “contain” the function reference when the function is called.

2.3 Explicit Binding

The display binding is using the call(..) of the function And the apply (..) Methods. Strictly speaking, JavaScript hosting environments sometimes provide very special functions that don’t have these two methods. But such functions are very rare, and most of the functions provided by JavaScript and all the functions you create yourself can use both methods. Their first argument is an object for this, which is then bound to this when the function is called. Because you can specify the binding object for this directly, it becomes an explicit binding.

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

Through the foo. Call (..) , we can force foo to bind its this to obj when calling foo.

2.3.1 hard binding

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); / / 5Copy the code

Hard binding is a variant of explicit binding. In the code above, I created the function bar() and manually called foo.apply(obj) inside it, thereby forcing foo’s this to be bound to obj. No matter how bar is called later, it will always manually call foo on obj, okay

2.3.2 soft binding

Soft binding is not an explicit binding rule, but is put here to make a better comparison with hard binding.

Hard binding forces this to the specified object, preventing function calls from applying the default binding rules. But hard binding greatly reduces the flexibility of the function, making it impossible to modify this using implicit or explicit binding.

If you can give the default binding a global object and a value other than undefined (if null or undefined is used as the display binding object for this, these values will be ignored on the call), you can achieve the same effect as hard binding, while preserving the ability of implicit or explicit binding to modify this.

This can be done by soft binding:

if(!Function.prototype.softBind){
    Function.prototype.softBind=function(obj){
        var fn=this;
        // Capture all curride parameters
        var curried=[].slice.call(arguments.1);
        var bound = function(){
            return fn.apply(
                (!this || this= = = (window || global))? obj:this,
                curried.concat.apply(curried,arguments)
            )
        }
        bound.prototype=Object.create(fn.prototype)
        returnbound; }}Copy the code

softBind(..) And bind (..) Similarly, it will wrap the specified function, first checking this when called, if this is bound to a global object or undefined, then binding the specified default object obj to this, otherwise it will not change.

The following code is an example of how softBind implements soft binding:

function foo(){
    console.log("name:"+this.name);
}
var obj={name:"obj"},
    obj2={name:"obj2"},
    obj3={name:"obj3"};
var fooOBJ=foo.softBind(obj);
fooOBJ();  // name:obj
obj2.foo=foo.softBind(obj);
obj2.foo(); // name:obj2
fooOBJ.call(obj3);//name:obj3
setTimeout(obj2.foo,10);//name:obj where soft binding is applied
Copy the code

Soft-bound foo() can manually bind this to obj2 or obj3, but if the default binding rules apply, this will be bound to obj.

2.4 the new binding

The new mechanism in JavaScript is completely different from class-oriented languages.

In JavaScript, constructors are simply functions that are called when the new operator is used. They do not belong to a class and do not instantiate a class. In fact, they are not even a special type of function; they are just ordinary functions called by the new operator.

When a function is called with new, the following action is automatically performed:

  1. Create a brand new object
  2. The new object will be linked by the implementation [[Prototype]]
  3. This new object is bound to the function call’s this
  4. If the function returns no other object, the function call in the new expression automatically returns the new object
function foo(a){
    this.a=a;
}
var bar = new foo(2);
console.log(bar.a)/ / 2
Copy the code

3. Priority

In the above binding rules, the default binding is the one with the lowest priority. Explicit binding takes precedence over implicit binding.

function foo(){
    console.log(this.a)
}
var obj1={
    a:1.foo:foo
}
var obj2={
    a:2.foo:foo
}
obj1.foo();/ / 1
obj2.foo();/ / 2
obj1.foo.call(obj2);/ / 2
obj2.foo.call(obj1);/ / 1
Copy the code

Which has higher priority, new binding or explicit binding? A new object is created when the new binding is called, so the new binding replaces the hard-bound this with the newly created this.

function foo(something){
    this.a=something
}
var obj1={}
var bar=foo.bind(obj1)
bar(2)
console.log(obj1.a)/ / 2
var baz=new bar(3)
console.log(obj1.a) / / 2
console.log(baz.a) / / 3
Copy the code

We can determine which rule applies to a function at a call location based on its priority, thus determining this:

  1. Is the function called in new (new binding)? If so, this binds to the newly created object.
  2. Is the function called by call, apply (explicit binding), or hard binding? If so, this binds to the specified object.
  3. Is the function called in a context object (implicitly bound)? If so, which context object is bound to this.
  4. If neither, the default binding is used. If in strict mode, the binding is undefined, otherwise it is bound to a global object.

4. Arrow function this

Instead of using the four standard rules for this, arrow functions determine this based on the outer (function or global) scope.

function foo(){
    Return an arrow function
    return (a) = >{
        // This inherits from foo()
        console.log(this.a)
    }
}
var obj1={
    a:1
}
var obj2={
    a:2
}
var bar =foo.call(obj1)
bar.call(obj2) // 1, not 2
Copy the code

The arrow function created inside foo() captures foo() ‘s this when called. Since foo() ‘s this is bound to obj1, and bar(which references the arrow function)’ s this is bound to obj1, the binding of the arrow function cannot be modified. (New doesn’t work either)

If you are wrong, please advise me, your advice is the most valuable experience in my study, thank you for your advice!!