Q: what are the ways to change this point?
Three (I know)
call, apply, bind (not including es6 syntax explanation)
When I reviewed these methods, I read a lot of blogs and discussions. The first two are well understood, but I took a little time to adapt to the customization of bind!
Without much to say, start exploring:
1.call
For call, I only knew how to change this and how to use it, but I didn't consider whether the current environment is a strict mode or a non strict mode. After some learning, I found some interesting knowledge.
First point: (how to use)
The use of call is very simple. Look at the code directly!
let obj = {a:1}; function sayHi(a){ console.log("summer Good boy!"); console.log("this yes",this); console.log(a); } sayHi(); sayHi.call(obj,9999);//The first parameter is the object to which this points, and the following parameters are the parameters passed to the function (multiple parameters can be passed) Output: window undefined obj: {a:1} 9999
Use really easy.
Next, look at the difference between strict mode and non strict mode!
In fact, the difference is that the processing of the first parameter is different (as far as I know, there are other differences, the comment points out, thank you!)
In non strict mode:
function test (val){ console.log("this----",this); console.log("val-----",val); } test.call(1,999); output this---- Number {1} val----- 999
In strict mode:
'use strict' function test1 (val){ console.log("this----",this); console.log("val-----",val); } test1.call(1,888); output this---- 1 val----- 888
The reality tells us:
π In the non strict mode: if an original type of data (Number, String, Boolean, Symbol, etc.) is passed in, its interior will first be wrapped with objects, convert the incoming original type of data into a wrapped object, and then point the function's this to the wrapped object instead of the original data itself
π In strict mode: the function called points to whatever the first parameter of call is passed in! No operation is performed!
I don't understand. You can see the code and diagram above. It's very clear!
2.apply
apply is really similar to call, but the way of passing parameters is different, so I won't talk about it in detail here. Let's introduce the usage:
function test (...args){ console.log("this----",this); console.log("val-----",arguments); } test.apply(true,[1,2,3]);//The parameters passed later use an array Output: this---- Boolean {true} val----- Arguments(3) [1, 2, 3, callee: (...), Symbol(Symbol.iterator): Ζ]
Including the processing of the first incoming parameter, which is also consistent with call
apply___ VS ___ call
call passes parameters (after the first one), either individually or in an array! π²
apply pass parameters (after the first one) can be passed to an array, not a single value! π²
3.bind
Difference from call and apply:
call and apply directly execute the function after changing the this point of the function π‘
After bind changes the this point of the function, it returns a function instead of executing it immediately π‘
See the actual effect:
let obj = {a:1} function test(){ console.log("bind----",this); } let res = test.bind(obj);//After calling bind, a function is returned. The original function is not executed immediately console.log(res); res(); Output: Ζ test(){ console.log("bind----",this); } bind---- {a: 1}
Interestingly, bind, like call and apply, handles the first parameter in the non strict mode ππ
"use strict" function test1(){ console.log("bind-----",this); } test1.bind(1)(); Output: bind----- 1
Do you think it's over here? Of course not!!!
When the function call bind changes the point of this, a function will be returned. Can you change the this of the returned function? π€
let obj = {a:1}; let jbo = {b:1}; function t(){ console.log(this); } let first = t.bind(obj); first(); let second = first.bind(jbo); second(); {a: 1} {a: 1}
The answer is No, π₯ After bind changes this point, it cannot be changed again unless the function calls bind again π₯
4. Customization
I believe that after reading, there will be more or less improvement!
Next, let's take a look at how to implement the call, apply and bind methods ourselves!
myCallπ‘
Function.prototype.myCall = function(context = window, ...args) { let type = typeof context; context = context == null || context == undefined ? window : context; context.fn = null; if (type == "number" || type == "string" || type == "boolean") { switch (type) { case "number": context = new Number(context); break; case "string": context = new String(context); break; case "boolean": context = new Boolean(context); break; } context.fn = this; } else { context.fn = this; } const res = context.fn(...args); delete context.fn; return res; }
myApplyπ‘
Function.prototype.myApply = function(context = window, ...args) { let type = typeof context; context = context == null || context == undefined ? window : context; context.fn = this; const res = context.fn(...args); delete context.fn; return res; }
myBindπ‘
Function.prototype.myBind = function(context) { if (typeof this != "function") { throw new Error("this is not a function"); } let _this = this; let oargs = Array.prototype.slice.call(arguments, 1); let Func = function() { let iargs = Array.prototype.slice.call(arguments); return _this.apply(this instanceof Func ? this : context, oargs.concat(iargs)); // Because a function is returned after calling bind, it may be new as a constructor. Therefore, a judgment should be added here to ensure that things on the prototype are not lost } let Fnull = function() {} Fnull.prototype = this.prototype; Func.prototype = new Fnull(); return Func; }
For the custom methods, I wrote them after my personal study and self summary. If there are mistakes, please correct them!
Well, I've finished introducing the method of changing this (excluding es6). You are welcome to comment, supplement and correct errors!
I think it's useful. Remember to praise it, ha ha π