Function.prototype.call2 = function(context) {
context.fn = this;
var args = [];
for(var i = 1, len = arguments.length; i < len; i++) {
args.push('arguments[' + i + ']');
}
eval('context.fn(' + args +')');
delete context.fn;
}
is to simulate the implementation of call. Why do you need to push a string and then use eval next? Why not directly pass in arguments[i] and then use context.fn(args)?
Here I believe you have already understood the principle of
call
. Here I will briefly explain the principle. I also refer to the instructions of theJavaScript
authoritative guide and then implement it with code.First, let’s take a look at the syntax and definition of
call
, from the Chinese version of the ECMAScript specification:Let’s give a simple example:
Then look at the output after using
call
:Let me answer your questions based on chestnuts:
First of all, you need to understand the relationship between the functions simulated above and the variables in the chestnut:
Notice this step, we just gave the reference address of
jawil.sayHello
tolulin.sayHello
Original
jawil.sayHello.call(context,arg1,arg2,arg3,arg4)
Eliminate
context
your way to getargs=[arg1,arg2,arg3,arg4]
Then execute
lulin.sayHello([arg1,arg2,arg3,arg4])
Haha, it’s very confusing, isn’t it? It looks fine, but in fact it has changed. It turns out that there are four parameters, and now they are gathered together An array is an array parameter, and here's the problem.So how to solve this problem? The idea is as above, put all the parameters into strings, and then use
eval
to execute.The effect we want is
Similar to this: "lulin.sayHello(arg1,arg2,arg3,arg4)" This is the way we want, notlulin.sayHello(arg1, arg2, arg3, arg4)
like this, becauselulin.sayHello
needs to reorganize the parameters, you can’t get a parameter and execute the function once , or Let’s save the parameters together and execute them once. The only way I can think of is to spell all the parameters into strings, and then use evalto execute them,
lulin.sayHello([arg1,arg2,arg3,arg4])
What is eval? Let me briefly explain it here. I will pretend that you don’t know anything., nor
lulin.sayHello(arg1),
lulin.sayHello(arg2)...
eval
Syntax:function
definition and usageThe
eval(string)
To put it simply, it uses JavaScript's parsing engine to parse the contents of this bunch of strings. Let's put it this way, you can understand it this way, you regard
eval
as a<script>
tag.It’s equivalent to this
Okay, let’s look at the above code again. In fact, there are still pitfalls. Let’s take a look at the modal intuitive point of view. Below is the complete debugging code:
Look at the output of args:
["arguments[1]", "arguments[2]"]
Then look at the output of 'context.fn(' + args + ')':
"context.fn(arguments[1],arguments[2])"Isn’t it a bit confusing
In fact, implicit conversion is involved here. Here is an example:
What is the value of'jawil'+[1,2]+[3,4]+3
?is equal to
"jawil1,23,43"
In fact, this is equivalent to
'jawil'+[1,2].toString()+[3,4].toString()+3
The space is limited, for more implicit conversions, please refer to my article: From ++[[]][+[]]+[+[]]==10? An in-depth explanation of implicit conversions in weakly typed JS
Speaking of this, I have said all the core things. You can understand it yourself. The original author probably consulted others when writing this. Many things were not explained clearly. I guess due to the limited space, I just mentioned it in one stroke. It seems to be a very short paragraph. The code actually contains a lot of knowledge points.
args is an array,
context.fn(args)
has only one parameter. Under normal circumstances, you can use apply to convert the array into parameters, but here to simulate call, using apply is meaningless. So it uses the array's toString() to move parameters other than context to context.fn.Because arguments[0] is context
Didn’t you see that the loop variable starts from 1?