手写call(),apply(),bind()方法

目录

知识储备:

一:手写call方法

1、思路

 2、实现

3、Symbol调优

二:手写apply方法

1、思路

2、实现

三:手写bind方法

1、思路

2、实现

 四:总结

知识储备:

所有的方法都可以调用我们手写的方法,因此需要挂载在原型上,因此我们使用以下代码进行挂载

Function.prototype.myCall = function () { console.log(' 方法执行 ') }

一:手写call方法

        call方法是改变this指向的一个常用方法,其写法是 func.call(thisArg,att1,att2,...) 。在这里第一个参数是我们要将this改变到哪个实例上,从第二个属性开始,就是我们要传递的参数。因为是直接传递的,所以我们这里不确定有几个参数,因此在重写的时候需要使用 ...args 来进行接收。同时在使用这个参数的时候需要 ...args 来进行结构。下面我们来整理一下思路以及实现吧。

1、思路

  • 定义myCall方法
  • 设置this并调用原函数
  • 接收剩余参数并返回结果

 2、实现

    <script>
        // 1. 定义myCall方法
        Function.prototype.myCall = function (thisArg,...args) {
            // 2. 设置this为原函数
            // thisArg 传入的设置为this的对象
            // 这里的this就是原函数  因为是  原函数.myCall()
            thisArg.f = this
            // 3. 接受剩余参数并返回结果
            const res =  thisArg.f(...args)
            // 因为添加了f属性所以要删掉
            delete thisArg.f
            return res
        }
        
        // ------------- 测试代码 ----------------
        const person = {
            name : '张三'
        }
        function func(numA,numB){
            console.log(this);
            console.log(numA,numB);
            return numA + numB
        }
        const res = func.myCall(person, 1, 2)
        console.log('返回的值为:' + res);
    </script>

3、Symbol调优

         在上面的代码中,我们可以看到,是使用的 thisArg.f 指向了 this 。但是这样有一个弊端,即你无法确定在 thisArg 中是否存在 f 方法,因此我们使用Symbol进行调优。将myCall()中的代码替换如下:

            //Symbol调优
            // 2. 设置this为原函数
            // thisArg 传入的设置为this的对象
            // 这里的this就是原函数  因为是  原函数.myCall()
            // 4. Symbol调优
            const key = Symbol('key')
            //这里是动态解析key
            thisArg[key] = this
            // 3. 接受剩余参数并返回结果
            const res =  thisArg[key](...args)
            // 因为添加了f属性所以要删掉
            delete thisArg[key]
            return res

        这里就不附加运行图了,最终的效果也是一样的哦!而且更为的安全可靠,推荐使用这种方法。

二:手写apply方法

        apply方法是另一种比较常见的改变this指向的方法,这个方法和call方法一样,都是在调用时改变this的指向,但是 apply 与 call 不同的地方在于,apply接收的第一个参数是thisArg(需要指向的对象),而第二个参数则是一个数组。apply只有这两个参数,这一点是区别于 call 方法的。其余的地方基本上是一样的。下面是实现思路以及具体代码。 

1、思路

  • 定义myApply方法
  • 设置this并调用原函数
  • 接收参数并返回结果

2、实现

        这个实现方法其实和myCall的实现方法很相近,不同的是接收参数的时候因为已经传的是数组了,所以我们不需要使用  ...  来接收不确定数量的参数,直接使用args就可以了。

    <script>
        // 1. 定义myCall方法
        Function.prototype.myApply = function (thisArg,args) {
            // 2. 设置this为原函数 直接使用Symbol调优
            // thisArg 传入的设置为this的对象
            // 这里的this就是原函数  因为是  原函数.myCall()
            // 4. Symbol调优
            const key = Symbol('key')
            //这里是动态解析key
            thisArg[key] = this
            // 3. 接受剩余参数并返回结果
            const res =  thisArg[key](...args)
            // 因为添加了f属性所以要删掉
            delete thisArg[key]
            return res
        }

        // ------------- 测试代码 ----------------
        const person = {
            name : '张三'
        }
        function func(numA,numB){
            console.log(this);
            console.log(numA,numB);
            return numA + numB
        }
        const res = func.myApply(person, [1, 2])
        console.log('返回的值为:' + res);
    </script>

三:手写bind方法

        bind 方法是直接区别于 call 方法和 apply 方法的,该方法是在创建时就改变了this的指定,同时返回的是一个新的方法,在调用新方法的时候同样可以传参,这样会和之前方法的参数进行一个拼接合并。该方法不会改变原方法的this指向,具体思路以及实现见下。 

1、思路

  • 定义myBind方法
  • 返回绑定this的新函数
  • 合并绑定和新传入的参数

2、实现

    <script>
        // 1. 定义myBind方法
        Function.prototype.myBind = function (thisArg,...args) {
            // 2. 返回绑定this的新函数
            return (...reArgs) => {
                // this :原函数(原函数.myBind)
                //3. 合并绑定和新传入的参数,注意先后顺序
                return this.call(thisArg,...args,...reArgs)
            }
        }

        // ------------- 测试代码 ----------------
        const person = {
            name : '张三'
        }
        function func(numA,numB,numC,numD){
            console.log(this);
            console.log(numA,numB,numC,numD);
            return numA + numB + numC + numD
        }
        const bindFunc = func.myBind(person, 1, 2)
        const res = bindFunc(3,4)
        console.log('返回的值为:' + res);
    </script>

 四:总结

        call、apply、bind三个方法是改变this指向的重要方法,熟练的使用以及掌握其源码实现原理,能够帮助我们更好地理解和使用这三个方法。同时可以让我们在项目开发过程中规避掉很多不应该的错误,并且提高我们的逻辑思维能力。

        因此,学习这三个方法是很有必要性的。希望本文能够对各位小伙伴有所帮助哦~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

暴怒的代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值