This article has participated in the activity of “New person creation Ceremony”, and started the road of digging gold creation together.
preface
In another year of crazy handwriting, let’s implement the call function in JavaScript.
I. Sorting out ideas
Before implementing a handwritten call, let’s review the use of the call function. Usually when we use call, we need two objects (everything is an object 🙈) :
- The function you want to implement (let’s say foo).
- We want to be able to call foo’s object (let’s say obj).
The main breakthrough in implementing the call function is to be able to get foo and obj. So let’s implement the Call method with this in mind.
Second, call method implementation
function jCall(thisArg,... args) {
// This points to window when null and undefined are passed in
thisArg = thisArg ?? window
// Make sure that Object is passed in
thisArg = Object(thisArg)
// Generate a unique key to avoid duplicating the key of the passed object
const key = Symbol()
thisArg[key] = this
// Get the execution result of the function
constresult = thisArg[key](... args)// Remove the manually added attributes to make thisArg back to its original appearance
delete obj[key]
// Returns the result of the function's execution
return result
}
Function.prototype.jCall = jCall
Copy the code
3. Display of test results
function foo(x, y, z) {
console.log(x + y + z, this);
}
const obj = {
name: 'ZJoker',
}
foo.jCall()
foo.jCall(null.1.2.3)
foo.jCall(undefined.1.2.3)
foo.jCall(123.1.2.3)
foo.jCall('123'.1.2.3)
foo.jCall(false.1.2.3)
foo.jCall([],1.2.3)
foo.jCall({},1.2.3)
console.log('--------- I'm divider ----------');
foo.call()
foo.call(null.1.2.3)
foo.call(undefined.1.2.3)
foo.call(123.1.2.3)
foo.call('123'.1.2.3)
foo.call(false.1.2.3)
foo.call([],1.2.3)
foo.call({},1.2.3)
Copy the code
Four, the implementation of detailed explanation
4.1 Get the object to call the target function
ThisArg refers to window when null and undefined are passed in
thisArg = thisArg ?? window
// Make sure that Object is passed in
thisArg = Object(thisArg)
Copy the code
ThisArg = thisArg; thisArg = thisArg; thisArg = thisArg; thisArg = thisArg; thisArg = thisArg
However, we have no control over whether the call method is passed or what type of the first argument is passed, so we have to manually process the arguments passed down.
4.2 Getting the target function to be called
// Generate a unique key to avoid duplicating the key of the passed object
const key = Symbol()
thisArg[key] = this
Copy the code
Normally we use the call method in xxx.call() mode, so the call method is invoked by foo. That is, this in the call method refers to our target function foo.
At this point we have fully retrieved the target function foo and the target object obj. But there’s a boundary case that we have to deal with.
To be able to make obj (parameter thisArg) call our foo, that is, bind foo’s this to obj (the actual meaning of the call method, change the function’s this pointer). We need to execute the target function as obj.foo(). So let’s add a new method to obj which is our foo. However, how to name key is a problem worth considering. We want to avoid the same name as obJ’s original method, so Symbol is used here to ensure the uniqueness of key value.
4.3 Obtaining the target function parameter
// Get the execution result of the function
constresult = thisArg[key](... args)// Remove the manually added method to return thisArg to its original appearance
delete obj[key]
// Returns the result of the function's execution
return result
Copy the code
Normally our foo might have its own arguments, so in the call method, we pass parameters other than the first argument to Foo using the expansion syntax as the arguments foo needs.
Here we use the concept of Rest Parameters in ES6 to accept Parameters other than the first parameter in the call method, which is the parameter in the jCall function… The args.
We also use the concept of Spread syntax in ES6 to pass the remaining parameters (args) to the target function foo in the following line of code… args
thisArg[key](... args)Copy the code
Finally we remove the method foo that was manually added to obj, make thisArg back to its original appearance, and return the execution result of obj.foo().
conclusion
The above is the realization process of handwritten call, a learning record from JS Xiaobai, welcome to correct the wrong place.
————— I’m the splitter —————
Concise code, detailed explanation, each front-end ER will be able to handwritten bind method.
Concise code, detailed explanation, each front-end ER will be able to handwritten apply method.
Concise code, detailed explanation, each front-end ER should be able to handwritten call method