# 面向对象 - bind

bind 方法用于将函数体内的 this 绑定到某个对象，然后返回一个新函数

```javascript
var d = new Date()
d.getTime() // 1578380274914

var print = d.getTime
print() // TypeError: this is not a Date object.
```

上面代码中，我们将 `d.getTime` 方法赋给变量 `print`，然后调用 `print` 就报错了。这是因为 `getTime` 方法内部的 `this`，绑定 `Date` 对象的实例，赋给变量 `print` 以后，内部的 `this` 已经不指向 `Date` 对象的实例了

`bind` 方法可以解决这个问题

```javascript
var print = d.getTime.bind(d)
print() // 1578380274914
```

上面代码中，`bind` 方法将 `getTime` 方法内部的 `this` 绑定到 `d` 对象，这是就可以安全地将这个方法赋值给其他变量了

`bind` 方法的参数就是所要绑定 `this` 的对象，下面是一个更清晰的例子

```javascript
var counter = {
  count: 0,
  inc: function() {
    this.count++
  }
}

var func = counter.inc.bind(counter)
func()
counter.count // 1
```

上面代码中，`counter.inc` 方法被赋值给变量 `func`。这时必须用 `bind` 方法将 `inc` 内部的 `this`，绑定到 `counter`，否则就会出错

`this` 绑定到其他对象也是可以的

```javascript
var counter = {
  count: 0,
  inc: function () {
    this.count++
  }
}

var obj = {
  count: 100
}

var func = counter.inc.bind(obj)
func()
obj.count // 101
```

上面代码中，`bind` 方法将 `inc` 方法内部的 `this`，绑定到 `obj` 对象。结果调用 `func` 函数以后，递增的就是 `obj` 内部的 `count` 属性

`bind` 还可以接受更多的参数，将这些参数绑定原函数的参数

```javascript
var add = function (x, y) {
  return x * this.m + y * this.n
}

var obj = {
  m: 2,
  n: 2
}

var newAdd = add.bind(obj, 5)
newAdd(5) // 20
```

上面代码中，bind  方法除了绑定 this 对象，还将 add 函数的第一个参数 x 绑定成 5，然后返回一个新函数 newAdd，这个函数只要再接受一个参数 y 就能运行了

&#x20;如果 bind 方法的第一个参数是 null 或 undefined，等于将 this 绑定到全局对象，函数运行时 this 指向顶层对象（浏览器为 window）

```javascript
function add (x, y) {
  return x + y
}

var plus5 = add.bind(null, 5)
plus5(10) // 15
```

代码上面中，函数 `add` 内部并没有 `this`，使用 `bind` 方法的主要目的是绑定参数 `x`，以后每次运行新函数 `plus5`，就只需要提供另一个参数 `y` 就能运行了

如果 `bind` 方法的第一个参数是 `null` 或者 `undefined`，等于将 `this` 绑定到全局对象，函数运行时 `this` 指向顶层对象（浏览器为 `window`）

```javascript
function add(x, y) {
 return x + y
}

var plus5 = add.bind(null, 5)
plus5(10) // 15
```

上面代码中，函数 `add` 内部并没有 `this`，使用 `bind` 方法的主要目的是绑定参数 `x`，以后每次运行新函数 `plus5`，就只需要提供另一个参数 `y` 就足够了。而且因为 `add` 内部没有 `this`，所以 `bind` 的第一个参数是 `null`，不过这里如果是其他对象，也没有影响

`bind` 方法有一些使用注意点

### 每一次返回一个新函数

bind 方法没运行一次，就返回一个新函数，这会产生一些问题。比如，监听事件的时候，不能写成下面这样

```javascript
element.addEventListener('click', o.m.bind(o))
```

上面代码中，`click` 事件绑定 `bind` 方法生成的一个匿名函数。这样会导致无法取消绑定，所以，下面的代码时无效的。

```javascript
element.removeEventListener('click', o.m.bind(o))
```

正确的方法时写成下面这样：

```javascript
var listener = o.m.bind(o)
element.addEventListener('click', listener)
// ...
element.removeEventListener('click', listener)
```

### 结合回调函数使用

回调函数时 `JavaScript` 最常用的模式之一，但是一个常见的错误是，将包含 `this` 的方法直接当作回调函数。解决方法就是使用 bind 方法，将 `counter.inc` 绑定 `counter`&#x20;

```javascript
var counter = {
  count: 0,
  inc: function () {
    'use strict'
    this.count++
  }
}

function callIt(callback){
  callback()
}

callIt(counter.inc.bind(counter))
counter.count // 1
```

上面代码中，`callIt` 方法会调用回调函数。这是如果直接把 `counter.inc` 传入，调用时 `counter.inc` 内部的 `this` 就会指向全局对象。使用 `bind` 方法将 `counter.inc` 绑定 `counter` 以后，就不会有这个问题，`this` 总是指向 `counter`
