ES5引入的函数对象的bind()方法

函数对象的bind()方法会创建一个新函数,bind()方法返回由指定的this值和初始化参数改造的原函数拷贝。

语法 fun.bind(thisArg[, arg1[, arg2[, ...]]])

比如foo.bind(bar, arg1, arg2),它返回一个新函数,就是说,内存中出现了一个匿名的新函数,暂且叫他newfoo吧,未来newfoo被调用的时候,它的this值指向bar的引用,newfoo的参数是foo的所有参数。

下面是一个最简单的例子,可以看到没啥奇怪的,this.x的this指向的是调用方法的对象,也就是module,module的x属性的值是81,所以输出81。

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

console.log(module.getX()); // 81

然后,一个新手想把module.getX方法赋值给一个新的变量,然后打算以后用这个变量来运行function() { return this.x; },于是他写成了:

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

module.getX(); // 返回 81

var retrieveX = module.getX;
console.log(retrieveX()); // 返回 9

为什么返回9?因为var retrieveX = module.getX相当于var retrieveX = function() { return this.x; },这时候this指向window,所以返回9。

这下是不是傻逼了?怎么避免这种傻逼?给module.getX方法绑定新的this指向就可以了。

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

module.getX(); // 返回 81

var retrieveX = module.getX.bind(module);
console.log(retrieveX()); // 返回 81

也就是说,retrieveX函数的this依然指向module。

bind()的另一个最简单的用法是,使一个函数拥有预设的初始参数。这些参数(如果有的话)作为bind()的第二个参数跟在this(或其他对象)后面,之后它们会被插入到目标函数的参数列表的开始位置,传递给绑定函数的参数会跟在它们的后面。

比如,我们现有一个很简单的做加法的函数叫foo:

function foo(a, b) {
    return a  + b;
}

我开始用这个函数解决各种问题,突然有个场景是,我已知第一个参数是41,第二个参数不确定。那么我是不是要重新写一个几乎一模一样的函数呢?当然No。由于我举例的foo函数特别简单,你当然觉得重写一下也不费什么劲,但如果实践中foo函数很长很复杂呢?现在有bind,就可以一句创建出一个新函数。

function foo(a, b) {
    return a + '--' + b;
}

var bar = foo.bind(null, 41); // 第一个参数是null或者undefined的话,bar的this不改变指向,只是第一个参数永远传入41

console.log(bar(3)); // 41--3,第一个参数是41,第二个是3。

当然你可能说,不用bind()也可以实现,比如下面用高阶函数实现:

function foo(a, b) {
    return a + '--' + b;
}

function bar(b) {
    return foo(41, b);
};

console.log(bar(3)); // 41--3

bind()和高阶函数两种都可以,bind()算是另一套解决方案。

现在我又有新要求,页面有一个按钮,点击之后3秒之后打印按钮上的文字,不注意this指向的话,会是下面这样:

document.getElementById('btn').onclick = function() {
    var foo = function() {
        console.log(this.innerText); // undefined
    };
    setTimeout(foo, 3000);
}

怎么改?foo的bind方法传入的第一个参数就是点击事件的回调函数,回调函数的this指向按钮DOM对象,所以foo能输出按钮上的文字。

document.getElementById('btn').onclick = function() {
    var foo = function() {
        console.log(this.innerText); // undefined
    };
    setTimeout(foo.bind(this), 3000);
}

你可能感兴趣的:(ES5引入的函数对象的bind()方法)