mackxu
子曰:学而时习之,不亦说乎?

由于方法和值为对象的属性值没什么区别,因此很容易提取对象的方法作为回调函数直接传递给高阶函数。但这也很容易忘记应明确指定方法的接受者。例如,一个字符串缓冲对象使用数组来存储字符串。

var buffer = {
    entries: [],
    add: function(args) {
        this.entries.push(args);
    },
    concat: function() {
        return this.entries.join('');
    }
};

var arr = ['alert', '-', '123'];
// error: entries is undefined
arr.forEach(buffer.add);
buffer.concat();

方法的接受者取决于它是如何被调用的。forEach方法的实现使用全局对象作为默认的接受者。由于全局对象没有entries属性,因此这段代码抛出了一个错误。

在回调函数中执行方法

var arr = ['alert', '-', '123'];
arr.forEach(function() {
    buffer.add(arr);
});
buffer.concat();

该方法创建一个显示地以buffer对象方法的方式调用add()。

使用bind()返回一个指定接受者的函数

创建一个函数用来实现绑定其接受者到一个指定对象是常见的。

arr = ['alert', '-', '123'];
arr.forEach(buffer.add.bind(buffer));
buffer.concat();

注意,bind()返回的是一个新的函数而不是修改buffer.add函数。这意味着bind方法是安全的。

其实forEach()允许调用者提供一个可选的参数作为回调函数的接受者。arr.forEach(buffer.add, buffer)。

兼容没有实现bind()方法的浏览器

if (!Function.prototype.bind) {
  Function.prototype.bind = function (oThis) {
    if (typeof this !== "function") {
      // closest thing possible to the ECMAScript 5
      // internal IsCallable function
      throw new TypeError("Function.prototype.bind - 
           what is trying to be bound is not callable");
    }

    var aArgs = Array.prototype.slice.call(arguments, 1), 
        fToBind = this, 
        fNOP = function () {},
        fBound = function () {
          return fToBind.apply(this instanceof fNOP && oThis
                 ? this
                 : oThis,
                 aArgs.concat(Array.prototype.slice.call(arguments)));
        };

    fNOP.prototype = this.prototype;
    fBound.prototype = new fNOP();

    return fBound;
  };
}

更新 2014/11/07

简化如下代码

Function.prototype.bind = function (oThis) {
  var self = this
    , args = [].slice.call(arguments, 1)
    ;
  return function() {
    return self.apply(oThis, args.concat([].slice.call(arguments)));
  };
};
posted on 2014-05-11 19:23  mackxu  阅读(315)  评论(4编辑  收藏  举报