1. Basic Concepts

  • Neither to itself nor to lexical scope
  • This is actually bound when the function is called, what does it refer to depending on where the function is called

Such as:

// call directly from the global scope
var name = 'hello world'
function foo() {
    consoel.log(this.name)
}
foo() // 'hello world' this refers to window because function foo() is called in the global scope equivalent to window.foo().

// as a method call
function foo() {
    console.log(this.name)
}
var obj = {
    name: 'Ming'.foo: foo
}
obj.foo() // 'xiao Ming ', this refers to object obj, because foo() is called as a method of object obj
Copy the code

2. Call location

Before we understand the binding process for this, we need to understand the call location: the call location is where the function is called in code (not declared). Look at the following code:

function baz() {
    // Current call stack: baz
    // Function call location: global scope
    console.log('baz')
    bar() // where bar() is called
}
function bar() {
    // Current call stack: baz > bar
    // Function call location: scope of baz
    console.log('bar')
    foo() // where foo() is called
}
function foo() {
    // Current call stack: baz > bar > foo
    // Function call location: scope of bar
    console.log('foo')
}
baz() // Call location of baz

Copy the code

3. Binding rules

3.1 Default Binding

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

Foo () is called directly in the global scope, this refers to the global scope, and there is a declared variable a in the global scope, so this.a accesses variable A in the global scope

3.2 Implicit binding

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

When a function references a context object, the implicit binding rule binds this in the function call to another context object. In the code above, when foo() is called, this is bound to obj, so this.a and obj.a are the same

Only the top or last level in the object attribute reference chain affects the call location, for example:Copy the code
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

3.2.1 Implicit Loss

One of the most common problems with this binding is that implicitly bound functions lose the binding object, meaning that it applies the default binding, binding this to global 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 = 'hello world'
bar() // 'hello world'
Copy the code

Although bar is a reference to obj.foo, it actually refers to the foo function itself, so bar() at this point is really an undecorated function call, so it applies the default binding.

When a callback function 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"
Copy the code

Argument passing is also an implicit assignment, so when we pass in a function we get an implicit assignment, so the result is the same as in the previous example

3.3 Displaying Binding

Bind this using call(), apply(), and bind().

function foo() {
    console.log(this.a)
}
var obj = { a:2 }
foo.call( obj ) / / 2
Copy the code
  • throughfoo.call(...)We can force this to point to Obj when calling foo
  • If a raw value is passed in (String, number, bolean) as the binding object for this, and the raw value is converted to object form. Often referred to as “boxing”

3.3.1 hard binding

Use call and apply

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

Bind this using the bind() function

function foo(something) {
    console.log(this.a, something)
    return this.a + something
}
var obj = {
    a: 2
}
var bar = foo.bind(obj)
bar(3)
Copy the code

3.3.2 rainfall distribution on 10-12 new binding

Calling a constructor with the new operator goes through the following four steps:

  • Create a new object
  • Assigns the constructor’s scope to the new object (this refers to the new object)
  • Execute the code in the constructor (add properties and methods for the new object)
  • Return this new object
function foo(a) {
    this.a = a
}
var bar = new foo(2)
console.log(bar.a) / / 2
Copy the code

When foo() is called with new, the this in foo() is bound to the bar object, so bar.a is actually this.a in foo()

4. Binding priority

Which has higher priority, implicit binding or explicit binding?

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

As you can see from the code above, showing bindings takes precedence

Five, the summary

If you want to determine a running this binding with eucalyptus, you need to find where the function is called directly. Once found, we can apply the following four rules in sequence to determine the object bound to this

  • bynewCall? Bind to the newly created object
  • Called by call or apply(or bind)? Binds to the specified object
  • Called by a context object? Bind that context object
  • Default: in strict mode bound toundefinedOtherwise, bind to the global object