Welcome to my Code of Life.

To know that this refers to the problem, you need to know the function call stack, the location of the function call.

Take a look at this example:

function baz() {
    // Current call stack: baz
    // Therefore, the current call location is global scope

    console.log("baz")
    bar(); // Where bar is called
}

function bar() {
    // The current stack is baz -> bar
    // Therefore, the current call location is in baz

    console.log("bar")
    foo(); // foo call location
}

function foo() {
    // Current stack is baz -> bar -> foo
    // Therefore, the current call location is in bar
    console.log("foo")
}

baz() // Call location of baz
Copy the code

Binding rules

Independent function call

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

var a = 10
foo() / / 10
Copy the code

In this case this points to the window global object by default

Why is that?

Because function calls are called without other modifications, the default binding this to the global window object is used.

Implicit binding

In non-strict mode, the function call this points to the caller.

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

Implicit loss

Bind this to a global object or undefined, depending on whether it is in strict mode.

function foo() {
 console.log( this.a );
}
var obj = {
 a: 2.foo: foo
};
var bar = obj.foo; // Function alias!

var a = "oops, global"; // a is an attribute of the global object
bar(); // The "oops, global" call is on the global object, so this refers to the window
Copy the code

A subtler, more common, and more unexpected situation occurs when a callback is passed in:

function foo() {
 console.log( this.a );
}
function doFoo(fn) {
 // fn actually refers to foo
 fn(); // <-- call location!
}
var obj = {
 a: 2.foo: foo
};
var a = "oops, global"; // a is an attribute of the global object
doFoo( obj.foo ); // "oops, global" actually this also refers to window
Copy the code

How about passing the function to the built-in function:

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

var obj = {
    a:2.foo:foo
}

var a = "oops, global"; // a is an attribute on the global object
setTimeout(obj.foo, 100) // "oops, global" also refers to the window
Copy the code

Explicitly bound

Use call,apply,bind

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

The way it’s defined is just like the way it’s defined here, but in a different way

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

var obj = {
  a: 2.foo: foo
}

obj.foo() / / 2
Copy the code

If you pass in a primitive value (string, Boolean, or numeric) as a binding object to this,

The original value is converted to its object form (i.e., new String(..)). , new Boolean (..) Or the new Number (..) ). This is often referred to as “boxing”.

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

Hard binding

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

var obj = {
    a:2
}

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

bar() / / 2

setTimeout(bar, 100) / / 2
Copy the code

A typical use of hard binding is to create a wrapper function that takes 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

Another way to use it is to create a helper function that can be reused:

function foo(something) {
 console.log( this.a, something );
 return this.a + something;
}
// A simple auxiliary binding function
function bind(fn, obj) {
 return function() {
    return fn.apply( obj, arguments );
 };
}
var obj = {
 a:2
};
var bar = bind( foo, obj );
var b = bar( 3 ); / / 2, 3
console.log( b ); / / 5
Copy the code

Es6 provides the bind method

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

var obj = {
    a: 2
}

var bar = foo.bind(obj)

var b = bar(3) / / 2, 3

console.log(b) / / 5
Copy the code

The this binding in the loop

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

var obj = {
    id: "awesome"
}

var arr = [1.2.3]

arr.forEach(foo, obj);

// 1 "awesome"
// 2 "awesome"
// 3 "awesome"
Copy the code

By the way, take a look at the core differentiation of forEach, map:

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

var obj = {
    id: "awesome"
}

var arr = [1.2.3]

var res = arr.map(foo, obj);

console.log("map===>", res)


var eachRes = arr.forEach(foo, obj)

console.log("each===>", eachRes)


// 1 "awesome"
// 2 "awesome"
// 3 "awesome"
// map===> (3) [undefined, undefined, undefined] // Return array
// 1 "awesome"
// 2 "awesome"
// 3 "awesome"
// each===> undefined // undefined
Copy the code

New operation

When a function is called with new, or when a constructor call occurs, the following operations are performed automatically.

  • Create (or construct) a brand new object.
  • The new object will be connected by [[Prototype]].
  • This new object is bound to the function call’s this.
  • If the function returns no other object, the function call in the new expression automatically returns the new object.

The following is the code THAT I implemented according to the above idea

function newOP(fn) {
    var obj = Object.create(null)
    var fnProto = Object.create(fn.__proto__)
    obj.__proto__ = fnProto

    var res = fn.apply(obj, arguments)

    return res ? res : obj
}
Copy the code

This lexical

The arrow function is bound to this during creation. We can consider the following question:

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 instead of 3
Copy the code

Arrow functions are most commonly used in callback functions, such as event handlers or timers:

function foo() {
 setTimeout(() = > {
 // This is morphologically inherited from foo()
 console.log( this.a );
 },100);
}
var obj = {
 a:2
};
foo.call( obj ); / / 2
Copy the code