js bind方法

MDN上的解释是: bind()函数会创建一个新绑定函数,当绑定函数被调用时,会以bind()的第一个参数作为运行时的this,之后的一系列参数加上绑定函数运行时本身的参数按顺序作为原函数的参数。

1.bind方法绑定对象,并且返回一个函数

var module = {
  x: 42,
  getX: function() {
    return this.x;
  }
}

var unboundGetX = module.getX;
console.log(unboundGetX()); // 此时的this指的是window
// undefined

var boundGetX = unboundGetX.bind(module);
console.log(boundGetX());
// expected output: 42

在上面代码里, 通过bind()方法创建了一个绑定函数之后,它被执行时,它的this会被设置成module, 所以第二个输出为module.x的值42.

我们可以简单的模拟实现:

Function.prototype.bind2 = function(context){
	var self = this;  // 保存this,即调用bind方法的目标函数
	return function () {
	  return self.apply(context);
	}
}

2.bind()方法支持在绑定的时候传参数

function list() {
  return Array.prototype.slice.call(arguments);
}

function addArguments(arg1, arg2) {
    return arg1 + arg2;
}

var bindList = list.bind(null, 37);
var result = bindList(1, 2);
console.log(result);  // [37, 1, 2]

除了在bind时可以只传部分参数外, 还可以在执行返回函数时再接着传参数(即函数柯里化)。我们可以通过arguments来解决:

Function.prototype.bind2 = function(context){
	var self = this,   // 保存this,即调用bind方法的目标函数
		 args = Array.prototype.slice.call(arguments, 1); // 获取第二个参数到最后一个参数
	return function () {
		var innerArgs =  Array.prototype.slice.call(arguments); // 获取的是bind返回的函数传入的参数
		var finalArgs = args.concat(innerArgs); // 按照顺序拼接起来
	    return self.apply(context, finalArgs);
	}
}

当然我们可以采用es6:

Function.prototype.bind2 = function(context) {
	var self= this;
	var args = [...arguments].slice(1);
	// 返回一个函数
	return function () {
	  return self.apply(context, args.concat(...arguments));
	}
}

3.作为构造函数使用的绑定函数
MDN上说明: 绑定函数自动适应于使用 new 操作符去构造一个由目标函数创建的新实例。当一个绑定函数是用来构建一个值的,原来提供的 this 就会被忽略。不过提供的参数列表仍然会插入到构造函数调用时的参数列表之前。

function Point(x, y) {
  this.x = x;
  this.y = y;
}

Point.prototype.toString = function() { 
  return this.x + ',' + this.y; 
};

var p = new Point(1, 2);
p.toString(); // '1,2'

var emptyObj = {};
var YAxisPoint = Point.bind(emptyObj, 0);

// 以下这行代码在 polyfill 不支持,
// 在原生的bind方法运行没问题:
//(译注:polyfill的bind方法如果加上把bind的第一个参数,即新绑定的this执行Object()来包装为对象,Object(null)则是{},那么也可以支持)
var YAxisPoint = Point.bind(null, 0);

var axisPoint = new YAxisPoint(5);
axisPoint.toString(); // '0,5'

axisPoint instanceof Point; // true
axisPoint instanceof YAxisPoint; // true
new Point(17, 42) instanceof YAxisPoint; // true

我们可以模拟下(这里注意bind的第一个参数):

Function.prototype.bind2 = function (context) {
    var self = this,   // 保存this,即调用bind方法的目标函数
		args = Array.prototype.slice.call(arguments, 1), // 获取第二个参数到最后一个参数
		fNOP = function() {}, // 作为中转构造函数
		fBound = function() {
	 		var innerArgs =  Array.prototype.slice.call(arguments); // 获取的是bind返回的函数传入的参数
			var finalArgs = args.concat(innerArgs); // 按照顺序拼接起来
			context = typeof context != 'object' ? Object(context): context; // 简单处理
			// 作为构造函数调用时this表示的是新产生的对象, 不作为构造函数用的时候传递context
		    return self.apply(this instanceof fNOP ? this : context, finalArgs);
		};
	fNOP.prototype = self.protype; // 使绑定后的函数与调用bind()的函数处于同一原型链上
	fBound.prototype = new fNOP();
  	return fBound;
}

参考资料: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值