concept
apply call and bind allow assignment and invocation of functions/methods belonging to one object for different objects.They can also change the direction of this within the function.
Difference
-
apply and call receive parameters in different forms
-
Both apply and call call call call functions directly and get the result of their execution, while bind returns the function to be executed and needs to be called again
Usage demonstration
Let's first create an object parent
const parent = { name: 'parent', sayPerson (age, addr) { return { name: this.name, age, addr } } }
Obviously it has the name attribute and the method sayPerson, which we can now output through parent.sayPerson().
const person = parent.sayPerson(60, 'shenzhen'); // {name: "parent", age: 60, addr: "shenzhen"}
Now let's create another object, son
const son = { name: 'son' }
We also want information about son now, but what if the son object does not have the sayPerson function?With the existing parent object and call method, we can write
const person = parent.sayPerson.call(son, 26, 'shenzhen'); // {name: "son", age: 26, addr: "shenzhen"}
As you can see, by calling the call function, we assign and call the sayPerson method to the son object.Implements an object that can call a method that does not belong to it, and this within the function points to the object.The apply method is actually used the same way, but there are some differences in passing parameters
const person = parent.sayPerson.call(son, [26, 'shenzhen']); // {name: "son", age: 26, addr: "shenzhen"}
Instead of calling the function directly, the bind function returns the function to be called
const sayPersonFn = parent.sayPerson.bind(son, 26, 'shenzhen'); const person = sayPersonFn(); // {name: "son", age: 26, addr: "shenzhen"}
That's how they work and how they differ. Let's see how they work
Realization
Implementation of call
The idea is to add the method you need to call for the object obj, then call it (where this points to obj), then delete the method after the call
Simple Edition
Object.prototype.callFn = function (...args) { // The first parameter is the target object const context = args[0]; args.shift(); // Assigning an object to a method that needs to be called context.fn = this; // Call this method context.fn(...args); // Delete Method delete context.fn; }
Add Return Value
Object.prototype.callFn = function (...args) { // The first parameter is the target object const context = args[0]; args.shift(); // Assigning an object to a method that needs to be called context.fn = this; // Call this method const result = context.fn(...args); // Delete Method delete context.fn; return result; }
In the test, we found that we called call, and if the first parameter is null or undefined, the call will call the method with the global window, where this also points to the window.If the first parameter is not an object type, the method is called with an empty object {}.
Object.prototype.callFn = function (...args) { // The first parameter is the target object let context = args[0]; // undefined and null point to window if (context === null || context === undefined) { context = window; } // Create an empty object if it is not an object type if (typeof context !== 'object') { context = {}; } args.shift(); // Assigning an object to a method that needs to be called context.fn = this; // Call this method const result = context.fn(...args); // Delete Method delete context.fn; return result; }
So far, we have implemented a complete call method.
Implementation of apply
Since there is only a parameter difference between call and call, we only need to modify the implemented call method.
Object.prototype.applyFn = function (...args) { let context = args[0]; if (context === null || context === undefined) { context = window; } if (typeof context !== 'object') { context = {}; } args.shift(); context.fn = this; // What's different from call const result = context.fn(...args[0]); delete context.fn; return result; }
Implementation of bind
On the premise of implementing apply and call, the implementation of bind is relatively simple.
Object.prototype.bindFn = function (...args) { // The reality is that there are multiple bundled layers of functions to execute return () => { return this.applyFn(args[0], (args || []).slice(1)); } }
For problems with creating objects using functions returned by the bind method as constructors, see Simulated implementation of JavaScript in-depth bind.
summary
call apply bind is actually a more common function in your work, especially in the source code of some frameworks or libraries, but their usage is often confused.I hope you can thoroughly understand their roles and differences through this article, and know how they work, and why they work.
Reference resources
Welcome to Front End Learning Card Group to study together~516913974