js中的bind方法并模拟实现自己的bind方法

Js中bind方法使用和实现

前面我们已经模拟实现了call和apply方法,今天来实现下同样可以改变this指向但是又有点不同得方法–> bind方法。

定义

首先来看下bind方法在mdn中得定义,bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。

语法

function.bind(thisArg[, arg1[, arg2[, …]]])

参数

thisArg 调用绑定函数时作为 this 参数传递给目标函数的值。 如果使用new运算符构造绑定函数,则忽略该值。当使用 bind 在 setTimeout 中创建一个函数(作为回调提供)时,作为 thisArg 传递的任何原始值都将转换为 object。如果 bind 函数的参数列表为空,或者thisArg是null或undefined,执行作用域的 this 将被视为新函数的 thisArg。
arg1, arg2, … 当目标函数被调用时,被预置入绑定函数的参数列表中的参数。

返回值

返回一个原函数的拷贝,并拥有指定的 this 值和初始参数。

从上面mdn中得描述中我们看到bind方法和call、apply方法得不同点就是,bind方法同样是将调用函数得this指向第一个参数,但是这个时候不会执行函数,而是会创建一个新的函数并返回出来,除了第一个参数剩下得参数传入新返回得函数使用。并且返回的函数还可以被new操作符进行调用,使用new操作符时bind方法传入得第一个this指向得值就失效了,此时函数this得指向遵循new操作符的this指向原则。(new操作符解析)。

使用

function say(res, res2) {
        this.num = res;
        console.log(this);
        console.log(this.hello);
        console.log(res);
        console.log(res2);
    }
    let obj = {
        hello: 'hello'
    }
    const back = say.bind(obj, 1);
    back(3);
    // {hello: "hello", num: 1}
    // hello
    // 1
    // 3

上述代码由打印值可以看出,利用bind函数将say函数内部的this指向了obj对象,并且为obj对象添加了一个属性num赋值为1,并且bind函数返回的back函数传入的参数在bing函数传入参数的后面进行传入。但是没有使用new操作符,接下来看使用new操作符调用back函数。

    function say(res, res2) {
        this.num = res;
        console.log(this);
        console.log(this.hello);
        console.log(res);
        console.log(res2);
    }
    let obj = {
        hello: 'hello'
    }
    const back = say.bind(obj, 1);
    const b = new back(6);
    console.log(b, 'b')
    // say {num: 1}
    // undefined
    // 1
    // 6
    // say {num: 1} "b"

上述代码将bind函数返回的back函数使用new操作符调用,看打印结果将say函数的this指向了new操作符生成的实力对象b上。下面我们就根据规则实现模拟实现自己的bind操作符。

实现思路

1、 在Function的原型上添加自己的bind方法
2、 返回一个新的函数backFn
3、 判断函数是不是由new操作符调用
4、 是的话将this指向生成的实力对象,不是的话将this指向传入的第一个值
5、 如果原函数存在原型对象,将返回函数backFn的原型指向原来函数的原型对象(因为bind返回的函数相当于原函数的复制)
6、 返回backFn函数

实现

    // 添加bind方法,并传入参数
    Function.prototype.myBind = function (thisArg, ...bindRes) {
        // 将函数保存起来
        const thisFn = this;
        if (typeof thisFn !== 'function') {
            throw new TypeError(this + 'is not a function');
        }
        const backFn = function (...backRes) {
            // 判断是否是new操作符调用,是的话采用生成的实例对象(因此时backFn函数this就指向实例对象所以直接指向this即可)
            // 参数传入如果是es5实现可以使用arguments对象

            // 使用之前自己写好apply方法改变this指向
            if (new.target) {
                return thisFn.apply(this, [...bindRes, ...backRes]);
            } else {
                return thisFn.apply(thisArg, [...bindRes, ...backRes]);
            }
            // 或者也可以这样子写
            // return thisFn.apply(new.target? this: thisArg, [...bindRes, ...backRes]);

        }
        // 采用创建空函数的方法,将bacnFn函数原型指向原函数防止改变bacnFn函数原型对象而影响原函数原型对象
        if (thisFn.prototype) {
            const emptFn = function () {};
            emptFn.prototype = thisFn.prototype;
            backFn.prototype = new emptFn();
        }

        return backFn;
    }

测试

    function say(res, res2) {
        this.num = res;
        console.log(this);
        console.log(this.hello);
        console.log(res);
        console.log(res2);
    }
    say.prototype.str = '内容'
    let obj = {
        hello: 'hello'
    }
    const back = say.myBind(obj, 1);
    back(3);
    // {hello: "hello", num: 1}
    // hello
    // 1
    // 3



    const b = new back(6);
    console.log(b.str, 'b')
    // backFn {num: 1}
    // undefined
    // 1
    // 6
    // 内容 b

测试结果符合期望结果,至此我们自己的bind方法就实现了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值