Mind mapping
Hello everyone, I’m Lin Yiyi. Call, apply, bind, call, bind, call, bind, call, bind, call, bind 🧐
Call, apply, and bind can all change the direction of this
Check out this article for this orientation problemInterview | JS, you have to understand this point
[function]. Call ([this], [param]…) In a word:call()
The function of thethis
Assigned to thecall()
The value of the first argument of the
[function].call([this]). Call () binds this to the first argument in function. This in call() refers to [function], which is executed inside the call() function. Call () executes the function by manipulating this. Pass the remaining arguments to [function] as well.
thinking
1
function fn(a, b) {
console.log(this, a, b)
}
var obj = {
name: 'Lin Yiyi'
}
fn.call(obj, 20.23) // {name: "linyiyi "} 20 23
fn.call(20.23) // Number {20} 23 undefined
fn.call() //Window {0: global, Window:... For undefined} undefined undefined | strict mode
fn.call(null) //Window {0: global, Window:... Null} undefined undefined | strict mode
fn.call(undefined) //Window {0: global, Window:... For undefined} undefined undefined | strict mode
Copy the code
Fn calls call, fn’s this points to obj, and fn is executed; Values referred to by this are reference types. In non-strict mode, this refers to window without passing arguments or null/undefined. The raw value is passed, and the raw value is wrapped. In strict mode, one argument to call refers to whoever it is
2
var obj1 = {
a: 10.fn: function(x) {
console.log(this.a + x)
}
}
var obj2 = {
a : 20.fn: function(x) {
console.log(this.a - x)
}
}
obj1.fn.call(obj2, 20) / / 40
Copy the code
In obj1.fn, fn’s this points to obj2, and finally executes the function in obj1.fn.
2. Apply and Call are basically the same
The only difference is that the first argument to apply is the reference to this, and the second argument is the array [arg1, arg2...]. The second argument to call is a list (arg1, arg2...).
var name = '二二'
var obj = {
name: 'Lin Yiyi'.fn: function() {
return `The ${this.name + [...arguments]}`
}
}
obj.fn.apply(window[12.23.34.56]) // "212,23,34,56"
Copy the code
The second argument to apply accepts an array
The interview questions
1. Simulate the implementation of built-in call(), apply() methods.
- A mock implementation of CALL
To simulate the implementation of call, we need to understand the principle of call. 1. The direction of this is changed, and the call function is executed in the call function. The following code reference comes from Amazed Feather
Function.prototype.myCall = function (context, ... args){
context = context || window
// This refers to fn, and we can use this to get fn. Context is our obj, and we can add a function property to obj
context.fn = thiscontext.fn(... args)delete context.fn
return
}
var name = '二二'
var obj = {
name: 'Lin Yiyi',}function fn() {
console.log(this.name, ... arguments) } fn.myCall(null)
fn.myCall(obj, 12.23.45.567)
Copy the code
The above mock call does not take into account the case of primitive types. Native call functions can also handle primitive types such as the above warm-up 1 fn.call(20, 23) output without error. However, myCall will directly report errors, providing a more comprehensive simulation of call can see thoroughly understand the closure, Currified, handwritten code, gold nine silver ten no longer lose points!
- A simulated implementation of Apply
Function.prototype.myApply = function (context, args){
context = context || window
context.fn = thiscontext.fn(... args)delete context.fn
return
}
Copy the code
Similar to the analog call writing above
2. There is a difference between call and apply
The syntax and function of the call method are similar to those of the apply method, except that the call() method accepts a list of arguments, whereas the Apply () method accepts an array of arguments.
var name = '二二'
var obj = {
name: 'Lin Yiyi'
}
function fn(){
console.log(this.name, ... arguments) } fn.apply(obj, [12.34.45.56]) //fn(12, 23, 45, 56) Lin Yiyi 12 34 45 56
Copy the code
Note that the remaining array arguments are passed to the function as a single argument, fn.apply(obj, [12, 34, 45, 56]) ==> fn(12, 23, 45, 56).
Third, the bind
To quote MDN: 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.
- Returns a new function when the new function is executed
this
Didn’t specify thebind
The first argument to bind
Is passed to the new function- The returned function is self-calling and can pass in new arguments
Small thinking
1. What is this new function?
Bind returns a copy of the function that called bind.
A little chestnut
var name = '二二'
var obj = {
name: 'Lin Yiyi'
}
function fn(){
return `The ${this.name} ` + [...arguments]
}
let f = fn.bind(obj, 12.23.45.67.90)
f() // "Lin yiyi 12,23,45,67,90"
Copy the code
The new function above is f(), which is returned by bind’s copy of fn.
2. How can BIND copy FN?
Simply put: Get this and return the function that this gets, as in call.
The interview questions
1. Bind () is different from call() and apply()
The first argument to apply and call is the same as the object to be changed. The second argument, apply, is an array, and call is arg1,arg2… In this form. Changing the this scope through bind returns a new function that will not be executed immediately
2. Mock implementation of the built-in bind() method.
- Simplified version implementation
Function.prototype.myBind = function myBind(context, ... arg) {
var _this = this // Get the function body that calls myBind
function ctor (. otherArg){ // The new function returned is a copy of the call to myBind
// This instanceof ctor is true, indicating that an instance is returned.
// The new keyword is used.
_this.call(this instanceof ctor ? this: context, ... arg.concat(... otherArg))// Use the apply principle to change this pointer and execute the new function returned.
}
// Change the return function's prototype to the binding function's prototype, and the instance inherits the value from the binding function's prototype
ctor.prototype = this.prototype
return ctor
}
var obj = {
name: 'Lin Yiyi'
}
function fn(){
console.log(this.name, ... arguments) }var a = fn.myBind(obj, 12.23.34.56)
a() // Lin Yiyi 12 23 34 56
Copy the code
- For a more comprehensive version, the following code comes from
JavaScript in-depth simulation of bind implementation
Function.prototype.bind2 = function (context) {
if (typeof this! = ="function") {
throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
}
var self = this;
var args = Array.prototype.slice.call(arguments.1);
var fNOP = function () {};
var fBound = function () {
var bindArgs = Array.prototype.slice.call(arguments);
return self.apply(this instanceof fNOP ? this : context, args.concat(bindArgs));
}
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
}
Copy the code
Simulation API implementation, the most important is the thought process, which is not copy.
Four, think about the question
1. Find the maximum and minimum values in the array
-
Find the maximum and minimum values using Max /min of Math
let arr = [12.45.65.3.23.11.76.8.9.56.70] let max = Math.max(... arr)/ / 76 let min = Math.min(... arr)/ / 3 Copy the code
-
Find the maximum and minimum values using the array sort method
let arr = [12.45.65.3.23.11.76.8.9.56.70] let list = arr.sort(function(a, b) { return b - a }) let max = list[0] / / 76 let min = list[list.length - 1] / / 3 Copy the code
-
Use apply to find the maximum and minimum value of the array
let arr = [12.45.65.3.23.11.76.8.9.56.70] let max = Math.max.apply(null, arr) / / 76 let min = Math.min.apply(null, arr) / / 3 Copy the code
2. How to determine an array
Object. The prototype. ToString. Call (), instanceof. Note in particular that Typeof cannot determine array types
let arr = []
Object.prototype.toString.call(arr)
Copy the code
3. The Object. The prototype. ToString. Why call () can be used to determine the type
Because the Object. The prototype. The toString () method returns the Object of type string, output “[Object Object]” the second Object is the constructor of the incoming parameters. So you can use call to specify any value and return the resultant constructor type with toString to determine the type. Apply /bind can do the same thing
Object.prototype.toString.call('str') // "[object String]"
Object.prototype.toString.call(123) // "[object Number]"
Object.prototype.toString.call({}) // "[object Object]"
Object.prototype.toString.call([]) // "[object Array]"
Object.prototype.toString.apply({}) // "[object Object]"
Object.prototype.toString.apply([]) // "[object Array]"
var f = Object.prototype.toString.bind({})
f() // "[object Object]"
var fn = Object.prototype.toString.bind([])
fn() // "[object Array]"
Copy the code
4. Use the Call () implementation to convert the class array to an array
Call (), [].slice/array.prototype.slice ()
let array = [12.23.45.65.32]
function fn(array){
var args = [].slice.call(arguments)
return args[0]
}
fn(array) // [12, 23, 45, 65, 32]
Copy the code
Call was used above to change slice’s this to arguments to iterate over the output.
reference
JavaScript deep simulation of call and apply
JavaScript in-depth simulation of bind implementation
MDN bind
The end of the
Thank you for reading this, if this article can enlighten or help you a little bit, welcomestarThis is Lin Yiyi. See you next time.