First, what is this?
This refers to the environment object on which the function is executed. That is to say, this of the function points to the execution environment of the calling function.
function a(){ return this } console.log( a() === window) //true
The function's this keyword behaves slightly differently in JavaScript, and there are also some differences between strict and non-strict modes.
function a(){ 'use strict' return this } console.log( a() === undefined) //true
2. Where does this point to?
this is the key word of the function and points to the calling object of the function.
The general direction can be summarized as follows:
1. When a function is called as a global environment
var name = 'window'; function a(){ return this.name } a() ==='window' //true
2. When a function is called as an object method
var obj = { name:'obj', sayName:function(){ return this.name } } console.log( obj.sayName() === 'obj') //true //Make a slight change; add the following code. var sayName = obj.sayName; console.log( sayName() === 'obj') //false //At this point, this in the sayName function points to window. //It needs to be clear here that the function name is only a variable containing pointers, and the function is a complex data type, so the function name is only a pointer, pointing to the memory address in the heap! So sayName just copies the pointer address at this point, so it's clear that the code above is rewritten to the following. var sayName = function(){ return this.name } var obj = { name:'obj', sayName:sayName } console.log( obj.sayName() === 'obj') //true console.log( sayName() === 'obj') //false
3. When a function is called as a dom node event
var container3 = document.getElementById('container3') container3.onclick = function(){ //Point to the node itself console.log(this) //<div id="container3">container3</div> }
4. As a constructor strength method
function A(name){ this.name = name; this.sayName = function(){ console.log(this.name)//Point to instance object } } var a = new A('aa'); a.sayName(); //aa
5. this in the arrow function
var name = 'window' var obj = { name:'obj', fn:function(){ (function (){ console.log(this.name) })() } } obj.fn() //window //Ordinary functions, because closure functions are executed by windows, this points to windows. //this of the arrow function points to the scope at which the function was created. var name = 'window' var obj = { name:'obj', fn:function(){ (()=>{ //Change to arrow function console.log(this.name) })() } } obj.fn() //Change to the arrow function, and you can see that the scope of creation is the scope of obj.fn function execution, that is, obj.
3. How to change the direction of this
js provides some ways to change the scope of function execution. Because if a normal function changes the context of this execution by the above writing, the writing is too cumbersome.
Application, call, bind usage
apply:
fn.apply(thisObj, array parameter)
Definition: Applying one method of an object to replace the current object with another
Note: If the parameter is not of array type, a TypeError error is reported.
call:
fn.call(thisObj, arg1, arg2, argN)
The only difference between apply and call is the format of the received parameters.
bind:
fn.bind(thisObj, arg1, arg2, argN)
The bind() method creates a new function. When the bind() is called, this of the new function is specified by the first parameter of the bind, and the rest of the parameters are used as parameters of the new function.
Implementation of apply, call and bind
apply Realization: Function.prototype.myApply= function(context){ context.fn = this;//1. Mount the function to the incoming object var arg = [...arguments].splice(1)[0];//2. Taking parameters if(!Array.isArray(arg)) { throw new Error('apply The second parameter must be an array') //3. Restrict parameter types to arrays } context.fn(arg) //4. Method of executing objects delete context.fn; //5. Method of removing objects } var obj = { name:'obj' } function sayName(arr){ console.log(this.name,arr) } sayName.myApply(obj,[1,2,3]) //obj [1, 2, 3]
call Achieve: apply The only difference is that the parameter formats are different. Function.prototype.myCall= function(context){ context.fn = this;//1. Mount the function to the incoming object var arg = [...arguments].splice(1);//2. Taking parameters context.fn(...arg) //3. Method of executing objects delete context.fn; //4. Method of removing objects } var obj = { name:'obj1' } function sayName(){ console.log(this.name,...arguments) } sayName.myCall(obj,1,2,3,5) //obj1 1,2,3,5
bind stay mdn Realization on: Function.prototype.myBind = function(oThis){ if(typeof this !== 'function'){ throw new TypeError('The bound object needs to be a function') } var self = this var args = [].slice.call(arguments, 1) fBound = function(){ //When this instance of fBound ==== true, it means that the returned fBound is called as a new constructor return self.apply(this instanceof fBound ? this : oThis, args.concat([].slice.call(arguments))) } var func = function(){} //Maintaining prototype relationships if(this.prototype){ func.prototype = this.prototype } //Make fBound.prototype an instance of func. If the returned fBound is the constructor of new, the _proto_ of the new object is the instance of func. fBound.prototype = new func() return fBound }