js中的apply方法并模拟实现自己的apply方法

apply方法

定义

call()方法,在mdn中的定义:
apply() 方法调用一个具有给定this值的函数,以及以一个数组(或类数组对象)的形式提供的参数。(它的作用和使用和call方法一致,唯一的区别就是call方法传递的是一个个参数的列表,apply方法传递的是参数的数组集合。Call方法详细请看call方法解析

语法

func.apply(thisArg, [argsArray])
apply方法传递两个参数,第一个参数传递的是所要改变指向的值(当该函数处于非严格模式下,则指定为 null 或 undefined 时会自动替换为指向全局对象,原始值会被包装。),第二个参数是所要传递的参数(参数是一个数组集合)。

返回值

返回调用函数的返回值。若该函数没有返回值,则返回 undefined。

使用
    let myName = {
        nameStr: 'dahua'
    }

    function sayName(res, res2) {
        console.log(this);
        console.log(this.nameStr);
        console.log(res);
        console.log(res2);
    }
    sayName.apply(myName, [1,3,'a']);

    // {nameStr: "dahua"}
    // dahua
    // 1
    // 3

上述代码改变this指向指向myName对象,并传入了一个数组参数,在sayName函数执行的时候会把传入的数组展开进行参数传递。还可以像下方这样子使用:

    let array = ['a', 'b'];
    let elements = [0, 1, 2];
    array.push.apply(array, elements);
    console.info(array); // ["a", "b", 0, 1, 2]

上述代码是调用了数组的push方法。并通过apply方法直接传入了数组参数,实现数组的合并。

模拟实现自己的apply方法

第一个参数具体指向的值,在call方法中已经详细验证不在赘述,可以直接查看call方法解析(call方法实现),直接实现自己的apply方法和验证。

思路:

核心就是根据this的指向规则。(this详细指向规则可参考this解析

步骤:

1、 因为是所有函数的方法,所以直接在原型上创建一个方法
2、 先判断传入的第一个参数thisArg的类型,进行分别处理
3、给thisArg添加一个属性,并把this赋值给它
4、调用该方法,并将参数传入进去并展开
5、删除改thisArg创建的属性
6、返回函数调用的返回值
代码如下:

    // 挂在Function的原型上
    Function.prototype.myApply = function(thisArg, res) {
        // 判断第一个参数thisArg是否是undefined或者null,是的话就赋值给window
        if (typeof thisArg === 'undefined' || thisArg === null) {
            thisArg = window;
        }
        // 对传入的值thisArg就行包装
        thisArg = Object(thisArg);
        // 给传入的值thisArg创建属性,为防止thisArg已经有对应的对应进行覆盖,所以使用Symbol创建唯一值
        const keyFn = Symbol('__myKeyFn__');
        // 此时的this指向调用myCall方法的函数,将它指向thisArg[keyFn]。
        // 这里也就是利用了this的指向规则
        thisArg[keyFn] = this;
        // 调用该方法传入参数,并展开
        const reasult = thisArg[keyFn](...res);
        // 删除thisArg创建的属性
        delete thisArg[keyFn];
        // 返回函数的返回值
        return reasult;
    }
测试

上面模拟实现了自己的apply方法,下面就测试一下功能是否正常:

let myName = {
        nameStr: 'dahua'
    }

    function sayName(res, res2) {
        console.log(this);
        console.log(this.nameStr);
        console.log(res);
        console.log(res2);
    }
    sayName.myApply(myName, [1,3,'a']);

    // {nameStr: "dahua", Symbol(__myKeyFn__): ƒ}
    // dahua
    // 1
    // 3

    let array = ['a', 'b'];
    let elements = [0, 1, 2];
    array.push.myApply(array, elements);
    console.info(array); // ["a", "b", 0, 1, 2]

测试结果和自带apply方法一致。

使用call方法实现apply方法

当我们实现了call方法的时候可以直接使用实现的call方法实现apply方法。如:

    Function.prototype.myApply = function (thisArg, res) {
        return this.myCall(thisArg, ...res);
    }
测试
let myName = {
        nameStr: 'dahua'
    }

    function sayName(res, res2) {
        console.log(this);
        console.log(this.nameStr);
        console.log(res);
        console.log(res2);
    }
    sayName.myApply(myName, [1,3,'a']);

    // {nameStr: "dahua", Symbol(__myKeyFn__): ƒ}
    // dahua
    // 1
    // 3

    let array = ['a', 'b'];
    let elements = [0, 1, 2];
    array.push.myApply(array, elements);
    console.info(array); // ["a", "b", 0, 1, 2]

测试结果与自己实现的apply方法一致。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值