bind 常见应用情形主要有两种:
- 改变 this 指向;
- 参数固化(又叫偏函数,可理解为函数柯里化的简单应用)。
第一种情形很简单,demo如下:
const cat = {
name: 'xiaoJu',
say: function () {
console.log(this.name)
}
}
cat.say(); // xiaoJu
const otherCat = {
name: 'daHuang'
};
cat.say.bind(otherCat)() // daHuang
cat.say()
很简单,遵循 this 的“谁调用指向谁”的大法,打印出 cat 的 name, 即“xiaoJu”。
cat.say.bind(otherCat)()
是什么意思呢?bind() 会创建一个新函数,当这个新函数被调用时,它的 this 值是传给它的第一个参数。所以,这段代码等同于:
let newSay = cat.say.bind(otherCat);
newSay();
bind() 创建了 newSay ,其内容和 cat.say 一模一样,只是它的 this 指向 bind() 的第一个参数,也就是 otherCat。
实际案例如下:
路由实现中有这么一段代码:
Router.prototype.init = function () {
window.addEventListener('load', this.refresh.bind(this))
window.addEventListener('hashchange', this.refresh.bind(this))
}
如果不是很了解 bind,这段代码中的 this.refresh.bind(this)
将不会使人很明白,当换个写法,就比较好理解:
Router.prototype.init = function () {
const _this = this;
window.addEventListener('load', function () {
_this.refresh()
})
window.addEventListener('hashchange', function () {
_this.refresh()
})
}
这样就明白很多了,其实就是监听两个事件,然后都执行 Router 实例原型上的 refresh() 方法,为了使this 指向正确,用了 const _this = this;
的写法,当然,以下这样当然也是可以的:
Router.prototype.init = function () {
window.addEventListener('load', () => {
this.refresh()
})
window.addEventListener('hashchange', () => {
this.refresh()
})
}
既然作用只是执行一个方法,如下写法为什么不行呢?
Router.prototype.init = function () {
window.addEventListener('load', this.refresh)
window.addEventListener('hashchange', this.refresh)
}
因为这样 refresh 里面的 this 就和Router 实例没关系了,指向就是指向 window 了,为了把 this 指向纠正过来,bind 就派上用场了:
Router.prototype.init = function () {
window.addEventListener('load', this.refresh.bind(this))
window.addEventListener('hashchange', this.refresh.bind(this))
}
demo 和实际案例解释完毕,来看第二种情形:
function print(name, day, where, doSomething) {
console.log(`${name} 于 ${day} 在 ${where} ${doSomething}`)
}
print('小明', '昨天', '操场', '打篮球'); // 小明 于 昨天 在 操场 打篮球
print('小明', '昨天', '田径场', '跑步'); // 小明 于 昨天 在 田径场 跑步
print('小明', '昨天', '林荫小道', '散步'); // 小明 于 昨天 在 林荫小道 散步
print 函数被调用多次,但是每次调用,前两个参数都是固定的,但是也不能写死在函数内部,因为或许下几次这两参数就会变了。那么有不有一个方法,能暂时的固定这两个参数呢,答案是有的,就是用 bind() 来实现:
const print2 = print.bind(null, '小明', '昨天');
print2('操场', '打篮球'); // 小明 于 昨天 在 操场 打篮球
print2('田径场', '跑步'); // 小明 于 昨天 在 田径场 跑步
那如果前面参数变了呢?重新 bind() 一次就好:
const print3 = print.bind(null, '小红', '前天');
print3('图书馆', '看书'); // 小红 于 前天 在 图书馆 看书
print3('音乐厅', '唱歌'); // 小红 于 前天 在 音乐厅 唱歌
类似的实际案例常见于 ajax 请求中,具体不贴代码了,小小一个改造,代码会简洁很多,这可以理解为函数柯里化思想的一个简单应用。
一句话日记:但愿如今不停歇的努力,能弥补大学浪费的那几年