手写实现call、apply、bind

首先明白call、apply、bind的作用与异同

1、相同点

1.三个都是用于改变this指向;
2.接收的第一个参数都是this要指向的对象,若不传入则默认指向window;
3.都可以利用后续参数传参。

2、不同点

1.call和bind传参相同,多个参数依次传入的;
2.apply只有两个参数,第二个参数为数组;
3.call和apply都是对函数进行直接调用,而bind方法不会立即调用函数,而是返回一个修改this后的函数

手写call、apply、bind代码

手写call:

		// 手写 call 方法
        Function.prototype.myCall = function (context) {
            // 首先判断myCall的调用者是不是一个函数
            // 若myCall的调用者不是一个函数则直接抛出异常
            if (typeof this !== 'function') {
                throw new TypeError('Error');
            }
            // 调用myCall时没有传参,那就默认篡改上下文对象为window
            context = context || window;
            // 保存this
            context.fn = this;
            // 保存参数 (保留索引为1至最后的元素,因为第一个元素是传入的this)
            let args = Array.from(arguments).slice(1)
            // 调用方法
            let result = context.fn(...args);
            delete context.fn;
            return result;
        }

手写apply(与call类似,主要区别在于传参方式的处理):

		// 手写 apply 方法
        Function.prototype.myApply = function (context) {
            // 首先判断myApply的调用者是不是一个函数
            // 若myApply的调用者不是一个函数则直接抛出异常
            if (typeof this !== 'function') {
                throw new TypeError('Error');
            }
            // 调用myApply时没有传参,那就默认篡改上下文对象为window
            context = context || window;
            // 保存this
            context.fn = this;
            // 定义result用于保存函数调用的结果
            // 根据传递参数与否,决定如何调用函数(注意传入第二个参数为一个参数列表)
            if (arguments[1]) {
                result = context.fn(...arguments[1])
            } else {
                result = context.fn()
            }
            // 调用方法
            delete context.fn;
            return result;
        }

验证myCall和myApply的正确性:

		// 验证myCall和myApply的正确性
        function sayAge(name = "wll", age = 21) {
            this.name = name;
            this.age = age;
            console.log(this.age);
        }
        let obj = {
            name: "haha",
            age: 99
        }
        sayAge.myCall(obj, "haha", 88)  //88
        sayAge.myApply(obj, ["haha", 88]) //88

手写bind(判断是否是返回函数的实例这一点不好理解):

		// 手写bind
        Function.prototype.myBind = function (context) {
            // 首先判断myBind的调用者是不是一个函数
            // 若myBind的调用者不是一个函数则直接抛出异常
            if (typeof this !== 'function') {
                throw new TypeError('Error');
            }
            // 保存this
            let _this = this;
            // 保存参数
            let args = Array.prototype.slice.call(arguments, 1)
            // 返回函数(调用bind方法应该返回一个函数)
            return function F() {
                // 判断this是否属于F的实例
                if (this instanceof F) {
                    // 无需篡改上下文,直接调用
                    return new _this(...args, ...arguments)
                } else {
                    // 篡改上下文并调用
                    return _this.apply(context, args.concat(...arguments))
                }
            }
        }

验证myBind的正确性:

		//验证myBind的正确性:
		function foo(name) {
            this.name = name;
        }
        let obj1 = {};
        let bar = foo.myBind(obj1);
        bar('Jack');
        console.log(obj1.name);  // Jack
        let alice = new bar('Rose');
        console.log(obj1.name);  // Jack
        console.log(alice.name); // Rose
这就是javascript中篡改this上下文call,apply,bind的实现方法,如果觉得有帮助的话,点个赞再走吧。

Alt

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

WongLeer

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

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

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

打赏作者

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

抵扣说明:

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

余额充值