Home  >  Q&A  >  body text

javascript - Implementation of call method in js

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)?

PHP中文网PHP中文网2685 days ago819

reply all(3)I'll reply

  • 给我你的怀抱

    给我你的怀抱2017-06-12 09:32:07

    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 the JavaScriptauthoritative 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:

    var jawil = {
        name: "jawil",
        sayHello: function (age) {
             console.log("hello, i am ", this.name + " " + age + " years old");
         }
    };
    
    var  lulin = {
        name: "lulin",
    };
    
    jawil.sayHello(24);
    
    // hello, i am jawil 24 years old

    Then look at the output after using call:

    jawil.sayHello.call(lulin, 24);// hello, i am lulin 24 years old
    

    Let me answer your questions based on chestnuts:

    is to simulate the implementation of call. Why do you need to push a string and use eval next? Pass in arguments[i] directly, and then use context.fn(args)Why not?

    First of all, you need to understand the relationship between the functions simulated above and the variables in the chestnut:

    context  => lulin
    
    context.fn => jawil.sayHello

    Notice this step, we just gave the reference address of jawil.sayHello to lulin.sayHello

    Original jawil.sayHello.call(context,arg1,arg2,arg3,arg4)

    Eliminate context your way to get args=[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 lulin.sayHello(arg1, arg2, arg3, arg4) like this, because lulin.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 eval to execute them,

    Similar to this: "lulin.sayHello(arg1,arg2,arg3,arg4)" This is the way we want, not

    lulin.sayHello([arg1,arg2,arg3,arg4]), nor lulin.sayHello(arg1),lulin.sayHello(arg2)...

    What is eval? Let me briefly explain it here. I will pretend that you don’t know anything.

    Let’s take a brief look at the

    eval functiondefinition and usage
    The

    eval() function can calculate a string and execute the JavaScript code in it.

    Syntax:


    eval(string)

    string required. A string to evaluate that contains a JavaScript expression to evaluate or a statement to execute. This method only accepts a raw string as parameter, if the string parameter is not a raw string, then the method will return unchanged. Therefore please do not pass String objects as arguments to the eval() function.

    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.

    eval('function Test(a,b,c,d){console.log(a,b,c,d)};
    Test(1,2,3,4)')

    It’s equivalent to this

    <script>
    function Test(a,b,c,d){
    console.log(a,b,c,d)
    };
    Test(1,2,3,4)
    </script>

    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:

    Function.prototype.call2 = function(context) {
        context.fn = this;
        var args = [];
        for (var i = 1, len = arguments.length; i < len; i++) {
            args.push('arguments[' + i + ']');
        }
    
        console.log(args)
    
        var star = 'context.fn(' + args + ')'
    
        console.log(star)
        
        eval('context.fn(' + args + ')');
    
        delete context.fn;
    }
    
    
    var jawil = {
        name: "jawil",
        sayHello: function(age) {
            console.log("hello, i am ", this.name + " " + age + " years old");
        }
    };
    
    var lulin = {
        name: "lulin",
    };
    
    
    jawil.sayHello.call2(lulin, 24, 25);
    

    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.

    reply
    0
  • 曾经蜡笔没有小新

    曾经蜡笔没有小新2017-06-12 09:32:07

    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.

    reply
    0
  • 淡淡烟草味

    淡淡烟草味2017-06-12 09:32:07

    Because arguments[0] is context
    Didn’t you see that the loop variable starts from 1?

    reply
    0
  • Cancelreply