❝
“This” problem is familiar to every front-end student, and it is often encountered in daily development. Sometimes, because “this” still has a lot of mistakes, and the probability of “this” problem in interview questions is very high. Let’s understand the direction of “this” and call, apply, bind
❞
This point
ES5 in this
“In ES5, this refers to the execution environment in which the function is called, regardless of where the function is defined. It can also be understood that this always refers to the object that last called it.”
- In normal functions this always refers to its ** “direct caller” **, which by default points to global objects (window in browser).
- In strict mode, there is no direct caller in a function
this
forundefined
- Call, apply,bind, this refers to the bound object
- Object function call, this refers to the object that called it
- The constructor this refers to the instance object that comes out of the constructor new
var obj = { a:function(){ console.log(this) console.log(this.b) console.log(this.c) console.log(this.a) }, b:2, C :3} var b = obj. A b() // },undefined,undefined obj. A () {a:.. , 2, b: c:, 2, 3, 3} f () {... } /** * this refers to window * obj. A (). This refers to the object called obj */Copy the code
ES6 in this
“There is a new arrow function in ES6. The arrow function’s this always points to this when it is defined, not when it is executed.”
- The arrow function does not have its own this; its this is inherited and by default points to the object on which it was defined, i.e
This in the arrow function points to this in the outer code
- Cannot be used as a constructor, that is, cannot be used
new
Command, otherwise an error is thrown - Not in the arrow function
arguments
Object, you can userest
Parameters instead of - Unusable
yield
Command, so the arrow function cannot be usedgenerator
function - Arrow functions don’t have their own
this
So it can’t be usedcall
.apply
.bind
These methods change the this point
var obj = { hi: function(){ console.log(this); return ()=>{ console.log(this); } }, sayHi: function(){ return function() { console.log(this); return ()=>{ console.log(this); } } }, say: ()=>{ console.log(this); }} const hi = obj. Hi() //this->obj const sayHi = obj. SayHi () const sayHiBack = sayHi() //this->window sayHiBack() //this->window obj.say() //this->windowCopy the code
“The output is obj object, obj object, window, window, window”
❝
Resolution:
1. The first obj.hi() is easy to understand. Hi is a normal function, and this refers to the object that called it, obj
2. The second function hi(), which is actually the function returned from the previous one, is an arrow function. The arrow function itself does not have this, so we look up its level and we just concluded that this is obj, so this also refers to obj
3. The third one executes obj.sayhi (), which does not print this, but returns a normal function
4. The fourth sayHi() executes the normal function that was just returned, with this referring to the object that called it, and none to the window
5. The fifth execution sa yHiBack() refers to the arrow function returned from the fourth execution. OK, the arrow function is located one level up, also window
Say () is an arrow function. The current block obj does not have this, it can only be found one level up, pointing to the window
❞
Call, apply,bind
We all know that call, apply, and bind can be used to change the direction of this, but these three functions are slightly different.
- The only difference between Call and Apply is the way they pass arguments. Call is passed to functions from the second argument, while Apply has only two arguments. The second argument is an array in which all arguments passed to functions are written
- Call and apply will be executed immediately if they change the this pointer of a function, while bind will change the this pointer of a function and return this
- The return value of call and apply is the result of the function, and the return value of bind is a copy of the function to which this refers
call
❝
The call() method calls a function with a specified this value and one or more arguments given separately. (From MDN)
❞
“Fun. call(thisArg,arg1[,arg2,arg3… )
The “call” method is used to specify this object for a function. The first argument is the object you want to specify, followed by arguments passed to the function, separated by commas
Var person = {name:' nan ', gender: 'boy',} var speak = function(age,hobbit){console.log(' I am ${this. // I am Nanjiu,18 years old this year, love front-end development, welcome excellent you pay attention to ~Copy the code
apply
❝
The “apply()” method calls a function with a given this value and arguments in the form of an array (or array-like object). (From MDN)
❞
Apply (thisArg,[arg1,arg2,arg3… The apply method is basically similar to the call method. The difference is that the parameter form of the call method is that the apply method passes an array of several parameters.
Var person = {name:' nan ', gender: 'boy',} function speak(age,hobbit){console.log(' I am ${this.name}, I am ${this. (person,[18,' play basketball ⛹️']) // I am Nan Jiu, 18 years old this year, like to play basketball ⛹️, welcome excellent your attention ~Copy the code
bind
❝
The bind() method creates a new function. When the new function is called, the first argument to bind() will be this when it runs, and the subsequent sequence of arguments will be passed as its arguments before the arguments passed. (From MDN)
❞
Fun. bind(thisArg,arg1[,arg2,arg3… The bind method is used to specify this for the method and return a new function that takes the same arguments as the call function. “It doesn’t call itself, you have to call it manually.”
Var person = {name:' nan ', gender: 'boy',} function speak(age,hobbit){console.log(' I am ${this.name}, I am ${this. Bind (person,18,' travel ⛱️')() // I am nanjiu,18 years old this year, like traveling ⛱️, welcome excellent your attention ~Copy the code
“Notice that you need to call it again, because bind will only return the function that this points to, it won’t do it itself.”
A. call B. apply C. call D. apply
- If the number of parameters is determined in order, call is used; if the number of parameters is not determined in order, apply is used
- Use call for fewer parameters and apply for more parameters
- When the parameter collection is already an array, it is best to use Apply
Application scenarios of BIND
1. Save the parameters
Let’s start with a classic interview question
for(var i=1; i<6; I++) {setTimeout (() = > {the console. The log (I) / / 6,6,6,6,6}, I * 1000)}Copy the code
I’m sure you all know that there are five 6’s printed here, because I is already a 6 when the setTimeout callback is executed
❝
So how do you get it to print 1,2,3,4,5?
❞
Of course, there are many methods, such as closures, and changing var to let to make it block-level scoped. I won’t cover this here, but I’ll cover closures later
We can also use bind
for(var i=1; i<6; {i++) {setTimeout (function (I) the console. The log (I) / / 1, 2, 3, 4, 5}. The bind (null, I), I * 1000)}Copy the code
2. Missing callback function this
var student = { subject:['JS','VUE','REACT'], study: Function (){setTimeout(function(){console.log(' I am nanjou, Bind (this),0)}} student.study() ${this.subject.join(', ')} ')}.bind(this),0)}} student.study(Copy the code
❝
What would happen if the setTimeout callback were not bound to this?
❞
This should point to a global window. There is no subject in the global window. Calling join will cause an error.
Simulation of the call
“Thought:”
- Set the context object according to the call rules, i.e
this
Pointing to. - By setting the
context
Property to point the function’s this to the context - Functions are executed and arguments are passed by implicit binding.
- Delete temporary attributes and return the result of function execution
Function. The prototype. MyCall = Function (context) {/ / context refers to the wanted to borrow method of object, and specify a default value for it, No pass is window var context = context | | the window / / will use the method of binding in the current object to use the method of fn properties on the context. Fn = this / / This refers to the method you want to borrow, that is, the caller before.myCall (where this refers to a function) console.log(this) // gets the argument, Var args = [...arguments].slice(1) var res = context.fn(... arguments) Args) // delete the method delete context.fn // return the result of execution return res}Copy the code
To simulate the apply
“Thought:”
- Similar to Call, the main difference is the handling of parameters
/* Call is a call with different parameters. Apply to accept a parameter array * / Function in the prototype. MyApply = Function (context) {var context = context | | window context. The fn = this / / Check whether the second argument is an array, Console. log(arguments.length) if(arguments.length > 2){throw new Error(' only two arguments can be passed ')}else if(! (arguments[1] instanceof Array)){throw new Error(' second argument needs to be Array type ')} var res = context.fn(... arguments[1]) delete context.fn return res }Copy the code
To simulate the bind
Function.prototype.myBind = function(context){ var context = context || window var _this = this var args = [...arguments].slice(1) var res = function(){return _this.apply(context,... args) } return res }Copy the code