In most common programming languages, this is the keyword (self is used in Objective-C)

But this in JavaScript is more flexible, both in terms of where it appears and what it stands for

role

This makes writing code much easier

There is no this

const info = {
  name: 'Klaus'.eatting() {
    console.log(`${info.name} eatting`)},running() {
    console.log(`${info.name} running`)},playing() {
    console.log(`${info.name} playing`)}}Copy the code

If, at this point, we change the name of the object to preson

const person = {
  name: 'Klaus'.eatting() {
    console.log(`${person.name} eatting`)},running() {
    console.log(`${person.name} running`)},playing() {
    console.log(`${person.name} playing`)}}Copy the code

At this point, all the places where info is used need to be changed to Person, which is very cumbersome.

Using this, however, makes it easier for us to refer to our own objects within objects

/ / use this
const person = {
  name: 'Klaus'.eatting() {
    console.log(`The ${this.name} eatting`)},running() {
    console.log(`The ${this.name} running`)},playing() {
    console.log(`The ${this.name} playing`)}}Copy the code

If you need to change the object name again, you only need to change one part

Point to the

global

Browser - The browser

<! DOCTYPEhtml>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
  <title>Document</title>
</head>
<body>
  <script>
    console.log(this) // => window
  </script>
</body>
</html>
Copy the code

Node -- module.exports object

exports.name = 'Klaus'

// Node actually compiles the module into an IIFE and executes it
// The call method is used to change the module's global this object to module.exports
console.log(this) // => { name: 'Klaus' }

exports.age = 24
Copy the code
function foo() {
  console.log(global= = =this) // => true
}

// Note that only this refers to module.exports globally within modules
// This inside the function is a global object, not module.exports
foo()

console.log(global= = =this) // => false
console.log(this) / / = > {}
Copy the code

Function of the internal

All functions create an execution context when they are called

In this execution context, in addition to the AO object, the scope chain, there is a special attribute this

Note: Unlike a function whose scope is determined at compile time (bound at compile time),

The function’s this is dynamically bound, meaning that the function’s this is determined only when the function is called (runtime binding), so there is no way to know which value this is at compile time

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

foo() // => // globalThis

const bar = {
  foo
}

bar.foo() // => The calling object in this case is the bar object

foo.call('coderwxf') // => String wrapper class corresponding to the String 'coderwxf'
Copy the code

Binding rules

  1. The default binding
  2. According to the binding
  3. Implicit binding
  4. The new binding

The default binding

Default bindings, also known as independent function calls

  • An independent function call can be understood as a function that is not bound to an object to be called or the caller calling the independent function is a global object
  • So the value of this for the standalone function call isglobalThis
function foo() {
  console.log(this)
}

foo() // => globalThis
Copy the code
const info = {
  foo() {
    console.log(this)}}const fn = info.foo
fn() // => globalThis
Copy the code
function bar() {
  return function() {
    console.log(this)}}const fn = bar()

fn() // => globalThis
Copy the code

Implicit binding

An implicit binding is a call made from an object, called as a method, where this refers to the calling object

const info = {
  name: 'info'.foo() {
    console.log(this)
  }
}

info.foo() // => Info object
Copy the code
const info = {
  name: 'info'.foo() {
    console.log(this)}}const bar = {
  name: 'bar'.foo: info.foo
}

bar.foo() // => bar object
Copy the code

According to the binding

Using the Call, apply, and bind methods, the thSI reference of the function is displayed manually

Call and apply
const info = {
  foo() {
    console.log(this)}}const fn = info.foo

// When call or apply is used directly, the function is executed immediately. There is no difference between call and apply
// Call and apply are defined on function. prototype, so they can be called by all Function instances
fn() // => globalThis
fn.call() // => globalThis
fn.apply() // => globalThis
Copy the code
const info = {
  foo() {
    console.log(this)}}const fn = info.foo

fn() // => globalThis
fn.call(info) // => Info object
fn.apply(info) // => Info object
Copy the code
function sum(num1, num2) {
  console.log(this)
  console.log(num1 + num2)
}

// Call passes arguments using residual arguments
sum.call('call'.10.20)

// Apply passes all parameters globally in an array
sum.apply('apply'[10.20])
Copy the code
bind
function foo() {
  console.log(this)}// Bind differs most from call/apply
// call/apply -- Modify this inside the function and execute it immediately
// bind returns a function with this corrected, leaving the user to decide when to call the function
const fn = foo.bind('Klaus')

// This should be globalThis by default
// But the bind method was used to fix this before the function was actually called
// When both the display binding and the default binding exist, the display binding takes precedence over the default binding
fn()
Copy the code
function sum(num1, num2) {
  console.log(this)
  console.log(num1 + num2)
}

const fn = sum.bind('foo')

// Parameter passing
fn(20.30)
Copy the code

The new binding

When you call a function with the new keyword, that is, when you call a function as a constructor,

This in the constructor is the object created and processed when the constructor is called

Or this in the constructor is actually the instance object that is generated

Calling a function with the new keyword does the following:

  1. Create a brand new object (actually an instance object)

  2. This new object will be executed prototype link

  3. The new object is bound to the function call’s this

  4. If the function returns no other object, the expression returns the new object

function Person(name, age) {
  // This inside the constructor is actually an instance object of Person, in this case, per
  // The print instance object is empty because no property assignment has been done until line 4
  console.log(this)
  this.name = name
  this.age = age
}

const per = new Person('Klaus'.23)
Copy the code

This in the built-in function

The timer

setTimeout(function() {
  // setTimeout/setInterval this value
  // 1, the browser is the window object
  // 2. Node is a Timeout object
  console.log(this)},2000)
Copy the code

Dom events

const btnElem = document.createElement('button')
btnElem.innerHTML = 'click me'
document.body.appendChild(btnElem)


btnElem.onclick = function() {
  console.log(this) // => btnElem object (the DOM object that triggers the click)
}

btnElem.addEventListener('click'.function() {
  console.log(this) // => btnElem object (the DOM object that triggers the click)
})
Copy the code

A higher-order function of an array

// forEach as an example
[1.2.3].forEach(function() {
  console.log(this) // => globalThis
})
Copy the code
// All array higher-order functions take a second argument that corrects the value of this in the first function
/ / including but not limited to map/forEach/filter/map/reduce/find/findIndex, etc
[1.2.3].forEach(function() {
  console.log(this) // If a second argument is specified, the value of this is the second argument
}, 'Klaus')
Copy the code

priority

The default rule has the lowest priority

  • Of course, the default rule has the lowest priority, because when there are other rules, this will be bound by other rules

Shows that binding takes precedence over implicit binding

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

foo() // => globalThis

foo.call('abc') // => String{ 'abc' }
foo.apply('abc') // => String{ 'abc' }

foo.bind('abc') ()// => String{ 'abc' }
Copy the code
function foo() {
  console.log(this)}// Bind takes precedence over call and apply
foo.bind('Klaus').call('abc') // => String{ 'Klaus }
foo.bind('Klaus').apply('abc') // => String{ 'Klaus }
Copy the code

The new binding takes precedence over the implicit binding

const info = {
  foo: function() {
    console.log(this)}}const f = new info.foo() // => foo object
Copy the code
const info = {
  foo() {
    console.log(this)}}const f = new info.foo() // => error If the value of the object's attribute is a function and ES6 shorthand is used
// At compile time V8 knows that foo is used as a method of info, not as a constructor, so going to new info.foo is an error
Copy the code

The new binding has a higher priority than bind

The new binding is not allowed to be used together with call and apply, so there is no higher priority

So we use the new keyword and the bind method for comparison

function foo() {
  console.log(this)}const newFoo = foo.bind('abc')

const f = new newFoo() // => foo object
Copy the code
function foo() {
  console.log(this)}// V8 found that you used bind to fix this
// So the function returned by the modified this is mostly called as a function
// An error will be reported
const f = new foo.bind('abc') ()/ / = > an error
Copy the code

New > Show bind (apply/call/bind) > Implicit bind (as method call) > Default bind (direct call)

rules

Ignoring to show bindings

function foo() {
  console.log(this)}// Manually specify this if this is set to null or undefined
// This is automatically ignored and the default this pointer is used
foo.apply(undefined) // => globalThis
foo.call(undefined) // => globalThis

foo.apply(null) // => globalThis
foo.call(null) // => globalThis

foo.bind(null) ()// => globalThis
foo.bind(undefined) ()// => globalThis

// if each line of code does not end with a semicolon and the code begins with parentheses (including braces, braces, and brackets)
// In order to avoid V8 lexical parsing cannot accurately distinguish the beginning and end of each line of code, and reported strange errors
// A semicolon is required at the beginning of the current line or at the end of the previous line to make a valid and visible distinction between the two lines; [1.2.3].forEach(function() {
  console.log(this) // => globalThis
}, null)

;[1.2.3].forEach(function() {
  console.log(this) // => globalThis
}, undefined)
Copy the code

Indirect function reference

const bar = {
  name: 'bar'.foo: function() {
    console.log(this)}}const baz = {
  name: 'baz'
}

// Returns the value bar.foo points to, so the actual output is foo
console.log(baz.foo = bar.foo) // => foo function object

// The following code is actually equivalent to const foo = bar.foo; foo();
// So the output is globalThis; (baz.foo = bar.foo)()// => globalThis
Copy the code

Arrow function

Arrow functions are a new way of writing functions since ES6, and are much more concise than function expressions:

  • Arrow functions are not bound to the this and arguments attributes
    • If this is used inside the arrow function, the value of this is found in the upper scope along the scope chain
  • Arrow functions cannot be used as constructors
    • That is, the arrow function, which cannot be used with new, will throw an error
The use of arrow functions

The basic use

const foo = () = > {
  console.log('foo') // => 'foo'
}

foo()
Copy the code

shorthand

  • If only one argument () can be omitted
const foo = v= > {
  console.log(v) // => 'foo'
}

foo('foo')
Copy the code
  • If there is only one line of code in the function body, the curly braces can be omitted, and the return value of that line of code will be the return value of the entire function
console.log([1.2.3.4].filter(item= > item % 2= = =0)) / / = > [2, 4]
Copy the code
  • If the body of the function returns only one object, add to that object(a)To declare that the returned result is a whole
const foo = () = > ({
  name: 'Klaus'.age: 23
})

console.log(foo())
Copy the code
Get this in the arrow function

Instead of using the four standard rules for this (i.e., not binding this), the arrow function determines this based on its outer scope

Do not use arrow functions

const foo = {
  data: [].fetchData() {
    // Common variables that hold this are named _this, that, self, etc
    var _this = this

    setTimeout(function() {
      _this.data = [1.2.3.4]},2000)
  }
}

foo.fetchData()
Copy the code

After using the arrow function

const foo = {
  data: [].fetchData() {
    setTimeout(() = > data = [1.2.3.4].2000)
  }
}

foo.fetchData()
Copy the code

Stage of practice

var name = "window";

var person = {
  name: "person".sayName: function () {
    console.log(this.name); }};function sayName() {
  var sss = person.sayName;
  sss(); // => window
  
  person.sayName(); // => person

  // V8 automatically removes the first parentheses (person.sayname)() at compile time equivalent to person.sayname ()
  (person.sayName)(); // => person
  
  (b = person.sayName)(); // => window
}

sayName();
Copy the code
var name = 'window'

var person1 = {
  name: 'person1'.foo1: function () {
    console.log(this.name)
  },
  foo2: () = > console.log(this.name),
  foo3: function () {
    return function () {
      console.log(this.name)
    }
  },
  foo4: function () {
    return () = > {
      console.log(this.name)
    }
  }
}

var person2 = { name: 'person2' }

person1.foo1(); // => person1
person1.foo1.call(person2); // => person2

// When defining objects, no scope is created, so the upper scope in person1.foo() is the global execution context
person1.foo2(); // => window
// The arrow function has no this inside, so no matter how the binding is displayed, the actual call will ignore it
person1.foo2.call(person2); // => window

person1.foo3()(); // => window
person1.foo3.call(person2)(); // => window
person1.foo3().call(person2); // => person2

// the arrow function returned from the person1.foo4 call has the upper scope of person1.foo4, not the global scope
person1.foo4()(); // => person1
person1.foo4.call(person2)(); // => person2
person1.foo4().call(person2); // => person1
Copy the code
var name = 'window'

function Person (name) {
  this.name = name
  this.foo1 = function () {
    console.log(this.name)
  },
  this.foo2 = () = > console.log(this.name),
  this.foo3 = function () {
    return function () {
      console.log(this.name)
    }
  },
  this.foo4 = function () {
    return () = > {
      console.log(this.name)
    }
  }
}

// Each time the constructor is called, a new instance object is generated
// The value of this inside the constructor is different each time it is called
var person1 = new Person('person1')
var person2 = new Person('person2')

person1.foo1() // => person1
person1.foo1.call(person2) // => person2

// person1.foo2 is the arrow function, so it goes to the upper scope to find the corresponding this
// The scope of js is determined when the function is compiled
// So person1.foo2's this is actually an instance object of Person, in this case person1
In short, a function has its own scope, whether it is a normal function or an arrow function
person1.foo2() // => person1
person1.foo2.call(person2) // => person1

person1.foo3()() // => window
person1.foo3.call(person2)() // => window
person1.foo3().call(person2) // => person2

person1.foo4()() // => person1
person1.foo4.call(person2)() // => person2
person1.foo4().call(person2) // => person1
Copy the code
var name = 'window'

function Person (name) {
  this.name = name
  // The curly braces used to define objects do not create a new scope
  this.obj = {
    name: 'obj'.foo1: function () {
      return function () {
        console.log(this.name)
      }
    },
    foo2: function () {
      return () = > {
        console.log(this.name)
      }
    }
  }
}

var person1 = new Person('person1')
var person2 = new Person('person2')

person1.obj.foo1()() // => window
person1.obj.foo1.call(person2)() // => window
person1.obj.foo1().call(person2) // => person2

// Foo2 returns an arrow function with no this inside
This function returns a listener function that needs to use this internally after the call
// It goes up to the level above it (in this case, foo2)
// In the next line of code, foo2 is called by person1.obj
// So this in foo2 is now the person1.obj object
person1.obj.foo2()() // => person1.obj
person1.obj.foo2.call(person2)() // => person2
person1.obj.foo2().call(person2) // => person1.obj
Copy the code