手写bind

251 阅读2分钟
//bind特点

1.函数调用改变this;
2.返回一个绑定this的函数
3.接受多个参数
4.支持柯里化形式传参 fn(1)(2)
5.一个绑定的函数也能使用new操作法创建对象,且提供的this会被忽略。
  1. 可以通过call,apply可以实现bind函数
	Function.prototype.mybind = function(context) {
		if(typeof this !== 'function') {
			throw new TypeError('Error')
		}
		let _this = this;
		let arg = [...arguments].slice(1)
		return function F() {
			//处理函数使用new的情况
			if(this instanceof F) {
				return new _this(...arg, ...arguments)
			} else {
				return _this.apply(context,arg.concat(...arguments))
			}
			
		}
	}
// 2.简易版的实现
	Function.prototype.mybind2 = function(context, ...preArgs) {
		return (...args) => this.call(context,...preArgs, ...args);
	}
	Function.peototype.bind3 = function(context) {
		let self = this;
		//支持柯里化传参,保存参数
		let arg = [...arguments].slice(1)
		return function() {
			//同样因为支持科利华形式传参,我们需要再次获取存储参数
			let newArg = [...arguments]
			console.log(newArg)
			//返回函数绑定的this,传入两次保存的参数
			//考虑返回函数有返回值做了return
			return self.apply(context, arg.concat(newArg))
		}
	}

4.推荐写法

Function.prototype.bind4 = function(context) {
    if(typeof this !== "function") {
        throw new Error(
            "Error"
        );
    }
    var self = this;
    var args = Array.prototype.slice.call(arguments,1)
    
    var fBound = function() {
        var innerArgs = Array.prototype.slice.call(arguments);
        return self.apply(
            this instanceof fNOP ? this : context,
            args.concat(innerArgs)
        );
    };
    var fNOP = function() {};
    fNOP.prototype = this.prototype;
    fBound.prototype = new fNOP();
    return fBound;
}










Function.prototype.bind2 = function(context) {
  // 1. 判断调用bind的是不是一个函数
  if (typeof this !== "function") {
    throw new Error(
      "error"
    );
  }
  // 2. 外层的this指向调用者(也就是调用的函数)
  var self = this;
  // 3. 收集调用bind时的其它参数
  var args = Array.prototype.slice.call(arguments, 1);

  // 4. 创建一个返回的函数
  var fBound = function() {
    // 6. 收集调用新的函数时传入的其它参数
    var innerArgs = Array.prototype.slice.call(arguments);
    // 7. 使用apply改变调用函数时this的指向
    // 作为构造函数调用时this表示的是新产生的对象, 不作为构造函数用的时候传递context
    return self.apply(
      this instanceof fNOP ? this : context,
      args.concat(innerArgs)
    );
  };
  // 5. 创建一个空的函数, 且将原型指向调用者的原型(为了能用调用者原型中的属性)
  // 下面三步的作用有点类似于 fBoun.prototype = this.prototype 但有区别
  var fNOP = function() {};
  fNOP.prototype = this.prototype;
  fBound.prototype = new fNOP();
  // 8. 返回最后的结果
  return fBound;
};

个人比较推荐最后一种写法。 欢迎加群。