javascript中bind知多少

我们经常将apply, call和bind放在一起来对比他们的区别和用法。提到这三个,很容易想到他们可以改变函数中this的指向。对于bind方法,我们最常见的使用方式如下:

1
var otherFn = fn.bind(this);

其实,bind还有一个被我们忽略了的非常好用的特性——传参

bind参数

当绑定函数被调用时,这些参数加上绑定函数本身的参数会按照顺序作为原函数运行时的参数。

来个栗子:

1
2
3
4
5
6
7
var fn1 = function (arg1, arg2, arg3) {
console.log(arg1);
console.log(arg2);
console.log(arg3);
}
var fn2 = fn1.bind(null, 'first');
fn2('second', 'third'); // 输出为: first second third

为什么说好用

bind的参数可以和绑定函数本身的参数进行拼接,利用这一特性可以实现一些自定义的包装。看下面的使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 原始函数
var fn = function(customizer, a, b) {
var customResult = customizer(a, b); // 使用自定义方式对a,b,key进行处理
if (!customResult) {
// 默认的处理
customResult = a + b
}
return customResult;
}
var decoratoredFn = fn.bind(null, function(a, b) {
// 自定义的处理方法
return a*2 + b;
});
decoratoredFn(1, 2); // 结果为 4;

在原始的函数中,自定义的函数仅仅是一个参数,而具体的实现是在bind的时候确定的。这样,fn可以认为是一个通用的抽象的模板。额,有点拗口,让我们想象一下map方法:

1
2
3
4
var numbers = [1, 4, 9];
var roots = numbers.map(Math.sqrt);
// roots is now [1, 2, 3]
// numbers is still [1, 4, 9]

map方式实现了一个抽象的模板,将一个array转化为另一个array,然后输出。中间具体转化成什么map是不关心的,留给我们来自定义。用bind来搞一搞array的map呢?通用的逻辑:挨个对array中的每一个进行处理得到一个值,这些值组成一个新的array,然后最终输出。具体每一个怎么处理,留给bind了。

1
2
3
4
5
6
7
8
9
10
11
12
13
// 原始函数
var fn = function(customizer, a) {
var resultArray = [];
for(var i=0, len=a.length; i < len; i++) {
resultArray.push(customizer(a[i]));
}
return resultArray;
}
var customizerFn = fn.bind(null, function(item) {
// 自定义的处理方法
return item*2;
});
decoratoredFn([1, 2]); // 结果为 [2, 4];

贴合点实际的栗子——单位转换

对于一维的单位转化,我们可以容易的得出一个通用的公式: 原单位*比例 + 起始偏差值 用代码描述一下:

1
2
3
4
function converter(toUnit, factor, offset, input) {
offset = offset || 0;
return [((offset+input)*factor).toFixed(2), toUnit].join(" ");
}

基于converter函数,借用bind的可以包装出各种单位转化的方法:

1
2
3
4
5
6
var milesToKm = converter.bind(undefined, 'km', 1.60936, 0);
var poundsToKg = converter.bind(undefined, 'kg', 0.45460, 0);
var farenheitToCelsius = converter.bind(undefined, 'degrees C',0.5556, -32);
milesToKm(10); // returns "16.09 km"
poundsToKg(2.5); // returns "1.14 kg"
farenheitToCelsius(98); // returns "36.67 degrees C"

该栗子来源戳这里