关于Function.prototype.bind

bind()方法会创建一个新函数,称为绑定函数。当调用这个绑定函数时,绑定函数会以创建它时传入bind()方法的第一个参数作为 this,传入 bind() 方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数。

实际使用中我们经常会碰到这样的问题:

js 代码:
function Person(name){
 this.nickname = name;
 this.distractedGreeting = function() {
 
   setTimeout(function(){
     console.log("Hello, my name is " + this.nickname);
   }, 500);
 }
}
 
var alice = new Person('Alice');
alice.distractedGreeting();
//Hello, my name is undefined

 

这个时候输出的this.nickname是undefined,原因是this指向是在运行函数时确定的,而不是定义函数时候确定的,再因为setTimeout在全局环境下执行,所以this指向setTimeout的上下文:window

以前解决这个问题的办法通常是缓存this,例如:

js 代码:
function Person(name){
  this.nickname = name;
  this.distractedGreeting = function() {
    var self = this; // <-- 注意这一行!
    setTimeout(function(){
      console.log("Hello, my name is " + self.nickname); // <-- 还有这一行!
    }, 500);
  }
}
 
var alice = new Person('Alice');
alice.distractedGreeting();
// after 500ms logs "Hello, my name is Alice"

 

这样就解决了这个问题,非常方便,因为它使得setTimeout函数中可以访问Person的上下文。但是看起来稍微一种蛋蛋的忧伤。

但是现在有一个更好的办法!您可以使用bind。上面的例子中被更新为:

js 代码:
function Person(name){
  this.nickname = name;
  this.distractedGreeting = function() {
  setTimeout(function(){
      console.log("Hello, my name is " + this.nickname);
    }.bind(this), 500); // <-- this line!
  }  
}
 
var alice = new Person('Alice');
alice.distractedGreeting();
// after 500ms logs "Hello, my name is Alice"

 

bind() 最简单的用法是创建一个函数,使这个函数不论怎么调用都有同样的 this 值。JavaScript新手经常犯的一个错误是将一个方法从对象中拿出来,然后再调用,希望方法中的 this 是原来的对象。(比如在回调中传入这个方法。)如果不做特殊处理的话,一般会丢失原来的对象。从原来的函数和原来的对象创建一个绑定函数,则能很漂亮地解决这个问题:

js 代码:
this.x = 9; 
var module = {
  x: 81,
  getX: function() { return this.x; }
};
 
module.getX(); // 81
 
var getX = module.getX;
getX(); // 9, 因为在这个例子中,"this"指向全局对象
 
// 创建一个'this'绑定到module的函数
var boundGetX = getX.bind(module);
boundGetX(); // 81

 

浏览器支持:

BrowserVersion support
Chrome 7
Firefox (Gecko) 4.0 (2)
Internet Explorer 9
Opera 11.60
Safari 5.1.4

很不幸,Function.prototype.bind 在IE8及以下的版本中不被支持,所以如果你没有一个备用方案的话,可能在运行时会出现问题。bind 函数在 ECMA-262 第五版才被加入;它可能无法在所有浏览器上运行。你可以部份地在脚本开头加入以下代码,就能使它运作,让不支持的浏览器也能使用 bind() 功能。

幸运的是,MDN为没有自身实现 .bind() 方法的浏览器提供了一个绝对可靠的替代方案

js 代码:
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 || window,
                               aArgs.concat(Array.prototype.slice.call(arguments)));
        };
 
    fNOP.prototype = this.prototype;
    fBound.prototype = new fNOP();
 
    return fBound;
  };
}

目前,仅有少数人知道:bind 也可以用来为最终的参数列表预设参数值:

var obj = { 
    name: 'A nice demo', 
    fx: function() { 
        alert(this.name + '\n' + $A(arguments).join(', ')); 
    } 
}; 

var fx2 = obj.fx.bind(obj, 1, 2, 3); 
fx2(4, 5); 
// 显示相应的 name 值,及 "1, 2, 3, 4, 5" 

 

 

•apply 、 call 、bind 三者都是用来改变函数的this对象的指向的;

 

•apply 、 call 、bind 三者第一个参数都是this要指向的对象,也就是想指定的上下文;

 

•apply 、 call 、bind 三者都可以利用后续参数传参;

 

•bind 是返回对应函数,便于稍后调用;apply 、call 则是立即调用 。

 

 

参考阅读:

http://www.css88.com/archives/5611

http://manual.51yip.com/prototype/prototype/api/function/bind.htm

posted @ 2017-02-06 15:24  jnpd  阅读(180)  评论(0编辑  收藏  举报