This point

This points to its caller.

let obj = {
	foo: function () {
    	console.log(this)}}function foo () { console.log(this) }
foo()    // Window object, equivalent to window.foo()
obj.foo()    / / object obj
Copy the code

To put it simply, who passes through “. Call a function, and the function this points to whoever it is (except for the ES6 arrow function). Does this invariably refer to all calls to it?

Js can use apply,call, and bind to change the orientation of this inside a function.

apply

Apply is used to change the reference to this in function objects. The first argument is the object to which you want to change this, and the second argument is an array.

// Foo does not have a myname attribute, nor does the global myname attribute
function foo () {
  console.log(this.myname)
  console.log(this)
}
foo()  // This in foo points to window(in non-strict mode) and prints undefined and window objects
let obj = { myname: 'kricn' }
foo.apply(obj)  // Print out kricn and obj objects
Copy the code

When Foo calls apply, its internal this points to the first argument to apply, which in this case is obj

Obj has a myName property, so print kricn, and this also points to obj

The second argument received by Apply needs to be an array type, and the final argument of this data type is passed to Foo as a single argument

function foo (a, b) {
  console.log(this.myname)
  console.log(this)
  console.log(a)
  console.log(b)
  cosnole.log(arguments)
}
foo.apply({myname: 'kricn'},1.2.3])
Kricn {myName: 'kricn'} 1 2 Arguments(3) */
Copy the code

Passing an array of length three is equivalent to passing three arguments 1,2, and 3 to foo and pointing foo’s this to {myname:’kricn’}

call

Like apply, call accepts a single argument starting with the second argument

foo.call(obj, 1.2.3)
Copy the code

Call for the number of arguments, apply for the number of arguments, push into the array, and loop arguments for all arguments

bind

Bind works just like call and apply, and passes arguments just like call.

Bind differs from call and apply in that it returns a function, whereas apply and call are called immediately.

let fn = foo.bind(obj)  // The pointer in foo points to obj, but foo is not executed
fn()  // This is the actual call to foo
Copy the code

Multiple calls to bind are invalid, i.e. (foo.bind(obj1).bind(obj2).bind(obj3))(); Foo’s this only wants obj1, and the latter two bind are invalid because of how bind is implemented, as shown below.

An implementation of Apply, Call, and bind

The realization of the apply

// Context is the object to point to, which corresponds to obj
Function.prototype.myApply = function (context) {
  // Determine if a function is calling this method
  if(typeof this! = ='function') throw new Error(`The ${this} is not a function`)
  // The function calling this method may have a return value
  let res = undefined;
  // This is a function because it calls myApply, such as foo.myapply ().
  // As mentioned above, who passed. Call a function and the this inside the function points to whoever it is
  // Assign this to a property of the context, and call this from the context
  context.fn = this;
  // Give the context a default value, pointing to window if no parameter is passed, or object in node
  context = context || window
  // Get parameters other than context, which may or may not exist
  let args = arguments[1] // Arguments The first one is context
  if(args) {
    // This is a function in itself, passed to it by an array expansion using ES6 syntax
    // The context is calling the function, so this refers to the object that called it, contextres = context.fn(... args) }else{
    // If there are no other arguments, just call this
    context.fn()
  }
  delete context.fn
  / / returns the res
  return res
} 
Copy the code

The realization of the call

// Context is the object to point to, which corresponds to obj
Function.prototype.myApply = function (context) {
  // Determine if a function is calling this method
  if(typeof this! = ='function') throw new Error(`The ${this} is not a function`)
  // The function calling this method may have a return value
  let res = undefined;
  // This is a function that calls myApply, assigns it to a property of the context, and changes the this reference inside the function
  context.fn = this;
  // Give the context a default value, pointing to window if no parameter is passed, or object in node
  context = context || window
  // Get parameters other than context, which may or may not exist
  // Call passes multiple parameters instead of an array
  let args = [...arguments].slice(1) // Arguments The first one is context
  if(args) {
    // This is a function in itself, passed to it by an array expansion using ES6 syntax
    // The context is calling the function, so this refers to the object that called it, contextres = context.fn(... args) }else{
    // If there are no other arguments, just call this
    context.fn()
  }
  delete context.fn
  / / returns the res
  return res
}
Copy the code

Bind returns a function, so instead of assigning to a variable and executing it or executing it directly, you can use the new operator to instantiate the returned function. So what does new do?

// What does new do
function create(context, ... args){
  // Declare an empty object
  let obj = {}
  // Redirect the __proto__ of the obj object to the prototype of the constructor
  Object.setPrototypeOf(obj, context.prototype)
  // Change the constructor this to point to obj
  let res = context.apply(obj, args)
  If the constructor has a return value and its type is an object, the value returned by the constructor is returned, otherwise the previously declared object is returned
  return res instanceof Object ? res : obj
}
Copy the code

Instantiate a constructor with new, whose this points to the instance with the highest precedence, i.e

let value = 2
let obj = {value: 1}
function foo () {
  console.log(this.value)
}
let fn = foo.bind(obj)
let f = new fn()
Copy the code

This will print undefined because this in foo refers to the variable f, which has no value.

In bind’s implementation, it’s not just a matter of changing the orientation of this and returning it inside a function, it’s also a matter of determining whether the returned function uses the new operator.

Function.prototype.mybind = function (context) {
  // Save a copy of this, which is a function
  const _this = this
  // Get the arguments for calling bind
  const args = [...arguments].slice(1)
  context = context || window
  if(typeof this! = ='function') {throw new Error("error")}const resFn = function () {
    Bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind
    const argus = args.concat([...arguments])
    // Check whether the new operator is used
    // If new is used, this points to its constructor, _this
    // If executed directly, this is window and is normal bind
    return _this.apply(this instanceof _this ? this : context, argus)
  }
  // Inherits the constructor, so the prototype of its return function points to the instance out of the new
  // use an empty function here
  const emptyFn = function () {}
  emptyFn.prototype = this.prototype
  resFn.prototype = new emptyFn()
  return resFn
}
Copy the code

Going back to the previous question, why does binding bind multiple times not work

let obj1 = {value: 1}, obj2 = {value: 2}
function foo () {console.log(this.value)}
let fn = foo.mybind(obj1)
fn()  / / 1
let f = fn.mybind(obj2)
f()  // the 1 function foo does not refer to obj2
Copy the code

Does mybind fail the second time?

No, mybind still works the second time, and it does change the orientation of this, but only the entire function before it

//(foo.mybind(obj1).mybind(obj2).mybind(obj3))(
let first = foo.mybind(obj1)
let two = first.mybind(obj2)
let three = two.mybind(obj3)
three()
// The execution result is still the result of foo's execution
// Two's this refers to obj3, but only to obj3. Instead of executing foo, two is executed
// In the same way, this of first points to obj2 and executes first,
// Execute all the way up to first, foo's this points to obj1, and foo's this points to obj1
// If you call mybind after first, you don't change the orientation of this in foo. Instead, you change the orientation of this in the entire function before it
Copy the code

-end-