JS中call、apply、bind的简单实现

280 阅读1分钟
       
        
       /* call 第一个参数改变调用函数this的指向,第2-n个参数向调用的函数传参
        模拟call:调用call的必须是一个函数 不是函数 return
        当调用call而不穿this时,被调用函数中的this也被重定向了,指向window
        将调用函数赋值给传进去的context
        然后在context中调用这个函数
        最后保证context前后统一,删除fn
        */
        const obj={
            a:1
        }
        Function.prototype.mycall=function(context,...arg){
            if(typeof(this)!=='function') return;
            context=context || window;
            const key=Symbol();
            context[key]=this
            context[key](...arg)
            delete context[key];
        }
        function callTest(...dos){
            console.log(this)  //obj
        }
        callTest.mycall(obj)




        /*
        apply和call的用法基本一样 但有一点不同的是
        使用apply向调用函数传参 参数类型一定要是数组类型
        否则报错
        */
        Function.prototype.myapply=function(context,arg){
            context=context || window;
            if(arg){
                if(Object.prototype.toString.call(arg)!=='[object Array]'){
                    throw new Error('')
                }
            }
            const key=Symbol();
            context[key]=this
            context[key](arg)
            delete context.fn;
        }
        function applyTest(arg){
            console.log(this)  //obj
        }
        applyTest.myapply(obj,[1,2,3])

        /*
            bind与apply call最大的区别就是
            被调用函数与bind绑定了之后不会被立即调用
            而是返回了一个代理函数 当代理函数被调用时,bind才会执行
            传的参数也是依次传参
        */

        Function.prototype.mybind=function(){
            const self=this
            const context=[].shift.call(arguments) || window;
            const agr=[].slice.call(arguments)
            return function(){
                return self.apply(context,[].concat.call(agr,[].slice.call(arguments)))
            }

        }
        function bindTest(){
            console.log(this)  
        }
        bindTest.mybind(null,1,2,3)() //this指向window
        bindTest.mybind(obj,1,2,3)() //this指向obj