js手写apply

js手写apply

首先我们知道apply方法是js的内置方法,同时是改变this指向的方法,话不多说,开整

1.新写的方法应该挂在Function的原型对象上,这样所有的函数实例都可以使用该方法

   Function.prototype.newApply=function(){
        //先把结构搭好
    }
2.context可以理解为调用apply(context)时传递进来的对象
3.同时context保证有值,如果调用者没有传递进来,则使用window兜底
  Function.prototype.newApply=function(context){
  //context可以理解为调用apply(context)时传递进来的对象
  //同时context保证有值,如果调用者没有传递进来,则使用window兜底
        context=context||window 
    }
4.通过Symbol生成一个唯一的key值,这里为了理解方便,就叫它fn,这是为了避免context中含有同名属性而导致被覆盖
5.通过读取变量的形式给context[fn]赋值,请思考,这里的this是指的谁呢?这里先按下不表(答案在测试6中)
  Function.prototype.newApply=function(context){
        context=context||window 
        //通过Symbol生成一个唯一的key值,这里为了理解方便,就叫它fn
        //这是为了避免context中含有同名属性而导致被覆盖
        let fn = Symbol()
        //通过读取变量的形式给context[fn]赋值,请思考,这里的this是指的谁呢?这里先按下不表
        context[fn] = this
    }
6.本函数是可以接收参数的,但是不需要写形参,直接用arguments接收实参即可,如果对于arguments有疑惑的,可以先去学习一下函数的内置对象arguments
7.并且参照apply方法的第二个参数为一个数组或者是一个类数组对象,这里调用函数的时候判断有没有参数,有就将参数传递进去
8.接着销毁该变量
9.返回结果
  Function.prototype.newApply=function(context){
        context=context||window 
        let fn = Symbol()
        context[fn] = this
        //本函数是可以接收参数的,但是不需要写形参,直接用arguments接收实参即可
        //并且参照apply方法的第二个参数为一个数组或者是一个类数组对象,这里调用函数的时候判断有没有参数,有就将参数传递进去
        let result = arguments[1]
        ?context[fn](arguments[1]):context[fn]()
        //接着销毁该变量
        delete context[fn]
        //最后将结果返回即可
        return result
    }

测试

1.测试使用两个对象,两个对象分别含有a属性和test方法,同时在test方法中打印测试数据
2.通过 let res1 = obj.fn.newApply(obj1,[1]) 去做测试
  let obj = {
            a: 'obj',
            test() {
                console.log(this.a);
                console.log(arguments);
                return '我是obj'
            }
        }

        let obj1 = {
            a: 'obj1',
            test() {
                console.log(this.a);
                console.log(arguments);
                return '我是obj1'
            }
        }

      let res1 = obj.test.newApply(obj1,[1])  
3.首先查看打印的res1,可以发现输出了obj对象中test函数返回的值,说明obj的test函数调用成功,如果不设置返回值则是undefined(测试图片1)
     Function.prototype.newApply=function(context){
           console.log('context',context);  // {"a": "obj1"}
           context=context||window
           let fn=Symbol()
           context[fn]=this
           console.log(context);
           let result=arguments[1]
           ?context[fn](arguments[1]):context[fn]()
           delete context[fn]
           console.log(context);
           return result
        }



        let obj = {
            a: 'obj',
            test() {
                console.log(this.a);
                console.log(arguments);
                return '我是obj'
            }
        }

        let obj1 = {
            a: 'obj1',
            test() {
                console.log(this.a);
                console.log(arguments);
                return '我是obj1'
            }
        }
        let res1 = obj.test.newApply(obj1,[1])  
        console.log('res1',res1);
测试图片 1

在这里插入图片描述

4.context为传入的obj1对象(测试图片2)
5.添加了Symbol类型的context打印结果(测试图片3)
 Function.prototype.newApply=function(context){
           console.log('context',context);  // {"a": "obj1"}
           context=context||window
           let fn=Symbol()
           context[fn]=this
           console.log(context);
           let result=arguments[1]
           ?context[fn](arguments[1]):context[fn]()
           delete context[fn]
           console.log(context);
           return result
        }



        let obj = {
            a: 'obj',
            test() {
                console.log(this.a);
                console.log(arguments);
                return '我是obj'
            }
        }

        let obj1 = {
            a: 'obj1',
            test() {
                console.log(this.a);
                console.log(arguments);
                return '我是obj1'
            }
        }
        let res1 = obj.test.newApply(obj1,[1])  
        console.log('res1',res1);
测试图片2

在这里插入图片描述

测试图片3

在这里插入图片描述

6.this到底是谁,又是怎样改变this指向的?(测试图片4)
6.1.此时的this是obj的test函数
6.2.this从哪里来,从obj.test.apply,也就是apply前面的那一串来的
6.3.context[fn]=this 相当于将obj对象的test函数赋值给了obj1对象的fn属性,但是并没有调用
6.4.最后result中通过contextfn调用函数,其实就是obj2.fn(arguments),通过对象调用函数,那么函数内部的this应该指向该对象,也就是obj2

6.5**.真相大白**

apply说穿了就是将obj的test拿出来作为obj1的属性,然后再通过obj1来调用该函数,从而达到改变this指向的目的

测试图片4

在这里插入图片描述

7. 其他的一些测试,输出了this.a的值为obj1,在测试6中已经解释过原因,本质上通过obj1.test()调用,此时的this肯定是obj1

在这里插入图片描述

8.输出一下test中的arguments,可以看出之前通过
obj.fn.newApply(obj1,[1])调用传递的第2个参数的值存放到了arguments里面

在这里插入图片描述

扩展

1.MDN文档描述,第二个参数需要是数组或者是类数组,所以再作出一点限制
2.当传递的实参数目大于2个,则抛出异常,此处异常是apply方式调用出现这种情况的异常的仿写
3.限制第二个参数为数组或类数组,此处只做了数组的简单处理,异常抛出同样为apply方法的仿写
 Function.prototype.newApply=function(context){
           if(arguments.length>2) throw new TypeError('CreateListFromArrayLike called on non-object')
           else if(!Array.isArray(arguments[1]))  throw new TypeError('CreateListFromArrayLike called on non-object')
           console.log('context',context);  // {"a": "obj1"}
           context=context||window
           let fn=Symbol()
           console.log(this);
           context[fn]=this
           console.log(context);
           let result=arguments[1]
           ?context[fn](arguments[1]):context[fn]()
           delete context[fn]
           console.log(context);
           return result
        }



        let obj = {
            a: 'obj',
            test() {
                console.log('this.a@@@',this.a);
                console.log(arguments);
                return '我是obj'
            }
        }

        let obj1 = {
            a: 'obj1',
            test() {
                console.log(this.a);
                console.log(arguments);
                return '我是obj1'
            }
        }

        let res1 = obj.test.newApply(obj1,[1,2])  
        console.log('res1',res1);

以上为本人的个人见解,如有问题,烦请指正

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值