Function.prototype.bind方法指南

目录
  1. 导读
  2. bind
    1. 基本用法
    2. 分离参数
    3. 绑定参数
    4. 快捷调用

导读

ES5新增了 Function.prototype.bind 方法, 该方法不同于jquery的bind 方法, 它主要用于固定 this 作用域, 避免各种由于上下文切换造成的语义问题. 常用在 setTimeout, for循环等内部.

bind

语法: func.bind(thisArg, arg1, arg2, ….)

bind() 方法会返回一个新函数, 又叫绑定函数, 当调用这个绑定函数时, 绑定函数会以创建它时传入 bind() 方法的第一个参数作为当前的上下文, 即this, 传入 bind() 方法的第二个及之后的参数加上绑定函数运行时自身的参数按照顺序作为原函数的参数来调用原函数.

绑定函数也能使用new操作符创建对象; 这就好比把原函数当做构造器. 此时提供的this将被忽略, this之后的参数将依然前置到运行时的参数列表中.

基本用法

下面我们来看看bind 的基本用法.

var x = 8;
var o = {
  x: 10,
  getX: function(){
      console.log(this.x);
  }
};
var f = o.getX;
f();//8, 由于没有绑定执行时的上下文, this默认指向window, 打印了全局变量x的值
var g = f.bind(o);
g();//10, 绑定this后, 成功的打印了o对象的x属性的值.

分离参数

bind() 方法还可以设置函数拥有的初始参数. 这些参数作为bind() 的第2,3…个参数跟在this(或其他对象的后面), 调用绑定函数时, 这些参数将插入到参数列表的最开始位置, 而传递给绑定函数的参数将跟在他们后面.

//打印十个斐波那契数
var f = function(n1, n2, length){
  if(arguments.length<3) console.log('参数不够...');
  var array = [n1, n2];
  for(var i=2;i<length;i++){
      array[i] = array[i-2] + array[i-1];
  }
  return array;
}
var g = f.bind(null, 1, 1);
console.log(g(10));//[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

绑定参数

如果使用new 操作符去构造绑定函数的实例时, 原来提供的this 将被忽略, this之后的参数将依然前置到构造函数的参数列表中. 此时 bind() 方法便具备了保留参数的能力, 我们可以此达到类似柯里化的效果.

var f = function(){
  if(arguments.length!=0)
      this.sum = Array.prototype.reduce.call(arguments,function(prev,item){//对传入参数求和
         return prev + item;
    });
  return Array.prototype.join.call(arguments);// 返回传入参数的字符串形式
}
f.prototype.toString = function(){
  return this.sum;
}
var g = f.bind(null,2);
var x = new g(8);
console.log(x.toString());//10, 可见x被绑定了2+8=10
console.log(g(8));//2,8 这告诉我们绑定的两个参数正是2和8

console.log(x instanceof g);//true, 可见通过new创建的x继承了g
console.log(x instanceof f);//true, 可见x也继承了f
console.log(g instanceof Function);//true, 可见bind f()方法之后, 返回了一个新的函数g
//函数g可用于求和,如下:
console.log(g(1,3,5,7,9));//27 2+1+3+5+7+9=27

快捷调用

使用Array.prototype的方法处理类数组对象时(鸭式辨型), 不可避免的需要借用call 或者 apply 方法, 使用 bind() 方法, 我们可以简化这个过程. 如下:

var _slice = Array.prototype.slice;
var slice = Function.prototype.call.bind(_slice);
function f(){
  return slice(arguments,1);
}
f(1,2,3,4,5);//[2, 3, 4, 5]

下面的实例将解释 bind() 方法做了一件什么事情:

var _slice = Array.prototype.slice;
var slice = function(){
  return _slice.apply(arguments[0],_slice.call(arguments,1));
};
function f(){
  return slice(arguments,1);
}
f(1,2,3,4,5);//[2, 3, 4, 5]

如下, 是bind() 方法的简单实现.

Function.prototype.bind = function(thisArg,argN){
  var _this = this;
  var _arg = _slice.call(arguments,1);
  return function(){
       var arg = _slice.call(arguments);
    arg = _arg.concat(arg);
      return _this.apply(thisArg,arg);
  }
}

可以看出来, 使用 bind() 方法后, 代码优雅得多.

注: 作为ES5标准加入的bind方法显然不支持 IE9之前的低版本IE, 如需使用, 请参考Polyfill.


本文就讨论这么多内容,大家有什么问题或好的想法欢迎在下方参与留言和评论.

本文作者: louis

本文链接: http://louiszhai.github.io/2016/01/11/bind/

参考文章

Fork me on GitHub