This is the 14th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021
Call, apply, bind, call, bind, call, bind, call, bind, call, bind
If you feel helpful, please click 👍 to encourage you
call/apply
role
To change the orientation of this inside the function.
The characteristics of
Any function can call these two methods, indicating that they are methods added to the function prototype (Function.prototype
).
console.dir(Function.prototype)
Copy the code
callcall
和 apply
The function is executed immediately.
call
和 apply
Is the return value of the function.
var name = A Warbler's Tail
var obj = {
name: 'warbler',}function foo() {
console.log(this.name);
return 'success'
}
foo.call(obj) //=> warbler
console.log(foo.call(obj)); // => success
Copy the code
callcall
和 apply
Point to theundefined
ornull
Will,this
Point to thewindow
.
function foo() {
console.log(this)
}
foo.call(undefined)
foo.call(null)
foo.apply(undefined)
foo.apply(null)
Copy the code
callcall
和 apply
Points to a value type, which willthis
Points to instances created by their constructors.
function foo() {
console.log(this)
}
foo.call(11)
foo.call('11')
foo.call(true)
Copy the code
callcall
和 apply
Points to a reference type, which willthis
Point to this object.
We declare a global variable name and a function foo in the global scope.
var name = A Warbler's Tail
var obj = {
name: 'warbler',}function foo() {
console.log(this.name)
}
foo() //=> a bird
Copy the code
Name is equivalent to window.name, foo() is equivalent to window.foo(), we print this.name, and the current this points to its caller, window, which is window.name, and gets a streamer.
But what if I want to print out Warbler? Define another obj.fn inside obj? Of course not. All we need to do is call Call /apply to redirect this to obj. In this case this.name is equivalent to obj.name, and we get warbler.
foo.call(obj) //=> warbler
foo.apply(obj) //=> warbler
Copy the code
The difference between call and apply
There is no difference except the form of the input.
Parameters passed to fn are written differently:
call
Takes multiple arguments, the first of which is the function context, i.ethis
The following parameters are parameters of the function itself.apply
Receives two arguments, the first of which is the function contextthis
The second argument is a function argument that is simply passed by oneAn array ofIn the form of.
Just remember that apply starts with a and that the argument it passes to fun is Array, which also starts with an A, and you can make a nice distinction between the two functions.
Write a call/apply
Write a call
var name = A Warbler's Tail
var obj = {
name: 'warbler',}function foo() {
console.dir(this);
return 'success'
}
/** * the Object() method returns the instance created by the constructor of the corresponding type if the value type is passed in. * returns the Object itself if the value type is passed in. * Returns an empty Object if undefined or null
Function.prototype._call = function(ctx, ... args) {
// Determine the context type if undefined or null points to window
// Otherwise use Object() to wrap the context as an Object
const o = ctx == undefined ? window : Object(ctx)
// How to refer this of function foo to CTX context
// Assign the function foo to a property of object O and call foo on that object o. This refers to that object O
// This is the function foo that calls _call. When we assign this to fn of object O, we assign foo to o.fin
// Add a unique attribute to the context to avoid overwriting the original attribute
const key = Symbol()
o[key] = this
// Execute immediately
constresult = o[key](... args)// Delete this attribute
delete o[key]
// Assign the return value of the function to the return value of _call
return result
}
Copy the code
To verify
foo._call(undefined) // window
foo._call(null) // window
foo._call(1) // Number
foo._call('11') // String
foo._call(true) // Boolean
foo._call(obj) // {name: 'warbler'}
console.log(foo._call(obj)); // success
Copy the code
You can see that our hand-written _call method yields the same result as the native call method.
Handwritten apply
As mentioned earlier, the only difference between call and apply is the way parameters are passed, so we just need to change the way parameters are handled and everything else is the same as call.
var age = 10
var obj = {
age: 20,}function foo(a, b) {
console.dir(this.age + a + b);
}
// Just change the second argument to an array.
Function.prototype._apply = function(ctx, array = []) {
const o = ctx == undefined ? window : Object(ctx)
// Add a unique attribute to the context to avoid overwriting the original attribute
const key = Symbol()
o[key] = this
constresult = o[key](... array)delete o[key]
return result
}
foo(3.4) / / = > 17
foo._apply(obj, [3.4]) / / = > 27
Copy the code
bind
role
It’s also used to change the orientation of this inside a function.
Bind and call/apply
Whether to execute immediately:
call/apply
Change the delta functionthis
After the contextimmediatelyExecute the function.bind
Is the function that returns the changed context,This function is not executed 。
The difference between return values:
call/apply
returnfun
The execution result of.bind
returnfun
And specifiedfun
的this
Point to, savefun
The parameters.
var name = A Warbler's Tail
var obj = {
name: 'warbler',}// this points to the caller document
document.onclick = function() {
console.dir(this); // => #document
}
// this points to obj
document.onclick = function() {
console.dir(this); // => #Object{name:'warbler}
}.bind(obj)
Copy the code
Write a bind
Function.prototype._bind = function(ctx, ... args) {
// The following this is the function that calls _bind, saved to _self
const _self = this
// bind will return a function, it will not be executed immediately
const newFn = function(. rest) {
// Call call to modify this reference
return_self.call(ctx, ... args, ... rest) }if (_self.prototype) {
// Copy the prototype of the source function to newFn in cases where the function has no prototype, such as the arrow function
newFn.prototype = Object.create(_self.prototype);
}
return newFn
}
Copy the code