js手写call、apply、bind方法

call、apply、bind方法的作用

首先这几个方法的作用都是改变this用的,他们都是函数身上的方法,所以可以通过函数点方法的方式去调用

区别:

传参方式:

call跟bind的传参方式是一样的,都是第一个参数为对象(需要指向那个对象),后面接其他任意数量的参数

而apply的传参方式略有不同,第一个参数依然还是需要指向的那个this对象,然后第二个参数是一个数组,只能接收两个参数

执行方式:

call跟apply都是直接函数点方法直接调用,而bind不一样,他不会直接调用,他会返回一个新的函数,然后你需要再次调用这个新的函数才会执行

        function fun(a, b) {
            console.log(this.name, '当前this');
            console.log(a, b, '其余参数');
        }
        // 
        fun.call({
            name: '球'
        }, '篮球', '足球');
        fun.apply({
            name: '球'
        }, ['篮球', '足球']);
        const newFun = fun.bind({
            name: '球'
        }, '篮球', '足球');
        newFun();

手写call:

主要思路是往函数原型上添加一个方法,然后再方法内部利用对象添加属性的方式来改变this

        // 定义一个函数
        function fun(a, b) {
            console.log(this.name, '当前this');
            console.log(a, b, '其余参数');
        }
        // call方法的作用就是改变this,把函数的this变成传入的第一个参数对象,然后后面可以接任意数量的参数
        fun.call({
            name: 'call'
        }, '篮球', '足球');
        // 因为call是函数的方法,所以依照原型链往函数的原型上添加方法,这里我添加一个mycall方法,名字随便取
        Function.prototype.mycall = function mycall(context,...par){
            // call方法的第一个参数为对象,所以这里我们第一个参数不能跟后面的...参数写反,...可以理解为将一堆参数依次展开
            console.log(this);//通过打印我们可以看出这里的this指向是调用mycall的那个函数
            
            let that = Symbol('that')//定义一个symbol,由于传进来的对象可能存在与你添加的属性同名的情况,所以这里利用下symbol
            //所以这里我们可以通过对象.的方式(也就是添加一个属性)来改变this,刚好我们这里有个对象参数context,
            //往他身上添加一个that属性让他等于当前this(调用mycall的函数),this指向就变成了context(传入的对象)
            context[that] = this
            // 然后that呢刚好又是那个调mycall的函数,所以我们直接调用他,把剩余的参数传给他
            context[that](...par);//这里调that方法相当于直接调外面的fun函数,所以直接把剩余参数同普通函数传参一样传进去就行了
            delete context[that]//由于这个context对象原本是没有that属性的,所以用完之后我们得删除了 不能搞乱了别人原本的对象
        }
        fun.mycall({name:'参数this'},'参数一','参数二');//调用自己手写的mycall方法试试

 

手写apply:

主要思路是往函数原型上添加一个方法,然后再方法内部利用对象添加属性的方式来改变this

      // 定义一个函数
        function fun(a, b) {
            console.log(this.name, '当前this');
            console.log(a, b, '其余参数');
        }
        fun.apply({
            name: '球'
        }, ['篮球', '足球']);
        Function.prototype.myapply = function myapply(context,arr){
            const type = Array.isArray(arr)//判断一下第二个参数是否为数组
            if(arr && !type){
                // 存在第二个参数且第二个参数不是数组的情况下抛出错误
                throw new Error(`${arr}is not 'array'`)
            }
            let only = Symbol('that')//定义一个唯一值symbol,symbol名为that
            context[only] = this//改变this指向,使当前this(调用myapply时的函数)指向context
            context[only](arr);//执行下函数
            delete context[Symbol('that')]//删除自己添加的那个属性
        }
        fun.myapply({
            name: 'myapply球'
        },['wewe','dfdfdf'])

 

手写bind:

主要思路是往函数原型上添加一个方法,然后再方法内部利用对象添加属性的方式来改变this,然后返回一个函数

        // 定义一个函数
        function fun(a, b, c) {
            console.log(this.name, '当前this');
            console.log(a, b, c, '其余参数');
        }
        // 
        const bindFun = fun.bind({
            name: '参数name1'
        }, ['篮球', '足球']);

        Function.prototype.myBind = function (context, ...params) {
            // 手写bind的主要区别就是返回一个函数
            //如果是下面这种写法,步骤都写在返回的函数里面那返回的函数必须得是箭头函数,
            // 因为箭头函数没有自己的this,没有他就会往外面找,如果是普通函数,因为外面调用这个函数的时候是在window下,所以this指向window
            return (...params2) => {
                let taht = Symbol('that')
                context[taht] = this//箭头函数下这个赋值可以写在返回函数里面,如果是普通匿名函数就得写返回函数的外面了
                context[taht](...params, ...params2);//可以对参数进行一个拼接,使其二次调用时可以再次传参
                delete context[taht]
            }
        }
        const myBindFun = fun.myBind({
            name: '参数name'
        }, 'sdsdd', 'zzzzz')
        myBindFun('weew');//再次调用时才会执行

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值