bind-js原理系列篇

240 阅读2分钟

作用:改变函数this指向,返回一个绑定了this的新函数,你需要再次调用此函数才会执行。

知识储备

bindapply/call一样都能改变函数this指向 ,但bind并不会立即执行函数。

- 对call/apply的实现很清晰。

- 函数柯里化:

函数调用时只传递一部分参数,于是会返回一个新函数去处理剩下的参数,一个经典简单的例子:

//函数柯里化
function fn(x, y) {
    return function (y) {
        console.log(x + y);
    };
};
var fn_ = fn(1);
fn_(2); //3

fn(1)(3) //3

可见 函数柯里化使用了闭包。

实现步骤

  1. 从调用fn._bind(obj)就得知,_bind里的this指的就是它的调用者也就是这个fn函数,所以先缓存起来

  2. 返回一个函数,函数里利用call或是apply把this指向修改掉

代码实现

版本一

Function.prototype._bind = function (obj) {
    var fn = this;
    return function () {
        fn.apply(obj);
    };
};

注意:

  • 程序一上来就要先this保存,否则后续在调用bind时内部this会指向window,var fn = this。
  • 新函数的this无法再次被修改,使用call、apply也不行

测试代码

var obj = {
    num: 1
};
function fn() {
    console.log(this.num);
};

var bound = fn._bind(obj);
bound(); //1

版本一虽然满足了this修改与函数返回,但不支持函数传参,于是:

版本二

Function.prototype._bind= function (obj) {
    //第0位是this,所以得从第一位开始裁剪
    var args = Array.prototype.slice.call(arguments, 1);
    var fn = this;
    return function () {
        fn.apply(obj, args);
    };
}

从官方文档知道bind还支持函数柯里化,在首次调用bind时先传部分参数,再调用返回的bound时可以补全剩余参数。

版本三

Function.prototype._bind = function (obj) {
    //第0位是this,所以得从第一位开始裁剪
    var args = Array.prototype.slice.call(arguments, 1);
    var fn = this;
    return function () {
        //二次调用我们也抓取arguments对象
        var params = Array.prototype.slice.call(arguments);
        //注意concat的顺序
        fn.apply(obj, args.concat(params));
    };
};

测试代码

var obj = {
    num: 1
};

function fn(x, y) {
    console.log(x + y + this.num);
};

var bound = fn._bind(obj, 2);
bound(3); //6