zoukankan      html  css  js  c++  java
  • 怎么模拟实现JavaScript的call和apply功能

    call

    简单的介绍call的作用:

    我们可通过call()方法在指定this指向和传递若干个参数的条件下调用某个函数(function)。

    举个简单的例子:

    var obj = {
        val: '2021'
    }
    function testCall(){
        console.log(this.val);
    }
    testCall.call(obj);
    // 2021
    

    两点:

    1.testCall函数中的this指向了obj

    2.testCall函数执行了

    模拟实现(第一步)

    那么我们该怎么模拟实现这两个效果呢?

    试想当调用 call 的时候,把 obj 对象改造成如下:

    var obj = {
        val: '2021',
        testCall: function() {
            console.log(this.val)
        }
    };
    
    obj.testCall(); // 2021
    

    这个时候 this 就指向了 obj,是不是很简单呢?

    但是这样却给 obj 对象本身添加了一个属性,这可不行呐!

    不过也不用担心,我们用 delete 再删除它不就好了~

    所以我们模拟的步骤可以分为:

    1. 将函数设为对象的属性
    2. 执行该函数
    3. 删除该函数
    Function.prototype.call2 = function(context){
        context.fn = this;
        context.fn();
        delete context.fn;
    }
    

    测试一下:

    var obj = {
        val: '2021'
    }
    function testCall(){
        console.log(this.val);
    }
    testCall.call2(obj);
    
    // PS C:\GitHub\Blog\demos\call&&apply模拟实现> node .\0301.js
    // 2021
    // PS C:\GitHub\Blog\demos\call&&apply模拟实现> 
    

    测试通过了。

    模拟实现(第二步)

    call还支持传递若干个函数参数来执行函数,而且传入的参数不定长。

    比如:

    function testCall1(name, age){
        console.log(this.val, 'name ' + name, 'age ' + age);
    }
    testCall1.call(obj, '小明', '18');
    // 2021 name 小明 age 18
    

    处理参数,然后有了第二版的代码:

    Function.prototype.call2 = function(context){
        context.fn = this;
        var args = [];
        for(var i = 1; i < arguments.length; i++){
            args.push('arguments[' + i + ']');
        }
        eval('context.fn(' + args +')');
        delete context.fn;
    }
    

    模拟实现(第三步)

    注意下两个小细节:

    1. this可以传入null,并且此时this指向window
    2. 函数是有返回值的

    第三版代码:

    Function.prototype.call2 = function(context, firstParam){
        var context = Object(context) || window;
        var result;
        context.fn = this;
        if (!firstParam) {
            result = context.fn();
        } else {
            var args = [];
            for(var i = 1; i < arguments.length; i++){
                args.push('arguments[' + i + ']');
            }
            result = eval('context.fn(' + args +')');
        }
        delete context.fn;
        return result;
    }
    

    测试一下:

    var obj = {
        val: '2021'
    }
    function testCall(name, age){
        console.log(this.val, 'name' + name, 'age' + age);
        return this.val;
    }
    console.log(testCall.call2(obj, '小明', '18'));
    // PS C:\GitHub\Blog\demos\call&&apply模拟实现> node .\0301.js
    // 2021 name小明 age18
    // 2021
    // PS C:\GitHub\Blog\demos\call&&apply模拟实现> 
    

    哈哈,就很完美!

    apply

    apply和call的作用类似,只不过传递参数时,apply要将所有参数放到一个数组中。

    举个例子:

    var obj = {
        val: '2021'
    }
    function testCall(name, age){
        console.log(this.val, 'name' + name, 'age' + age);
        return this.val;
    }
    console.log(testCall.apply(obj, ['小明', '18']));
    

    实现几乎一致,直接粘代码了

    Function.prototype.apply2 = function(context, paramArr){
        var context = Object(context) || window;
        var result;
        context.fn = this;
        if (!paramArr || !Array.isArray(paramArr)) {
            result = context.fn();
        } else {
            var args = [];
            for(var i = 0; i < paramArr.length; i++){
                args.push('paramArr[' + i + ']');
            }
            result = eval('context.fn(' + args +')');
        }
        delete context.fn;
        return result;
    }
    
  • 相关阅读:
    2021软工-提问回顾与个人总结
    2021软工-调研作业-Notion
    2021年软工-个人阅读作业2
    tester
    tableau学做两个集合的维恩图(文氏图)Venn diagram 二维文氏图
    python学习
    pv操作是否会造成死锁呢?
    提问的正确姿势
    【BUAA OO Unit3】史上最全OpenJML摸索实录
    MVC和三层架构的区别
  • 原文地址:https://www.cnblogs.com/lvzl/p/14467341.html
Copyright © 2011-2022 走看看