# 由 Underscore 与 Lodash 的差异引发的思考

## 循序渐进

```//=> [4, 8, 15, 16, 23, 42]
_.map(['4', '8', '15', '16', '23', '42'], function (val) {
return Number(val);
});```

```var f = function (val) { return val; };
var g = function (val) { return f(val); };

//=> true
f('stupid') === g('stupid');```

```//=> [4, 8, 15, 16, 23, 42]
_.map(['4', '8', '15', '16', '23', '42'], Number);```

```var first = parseInt('1NO');     //=> 1
var middle = parseInt('2FOOL');  //=> 2
var last = parseInt('3ME');      //=> 3```

It works! 于是以迅雷不及掩耳的速度得出结果：

```//=> [1, 2, 3]
_.map(['1NO', '2FOOL', '3ME'], function (val) {
return parseInt(val);
});```

Perfect！细看一下，咿，这不是和之前那个例子一样的嘛，这次学聪明了，窃喜之下后马上将结果改为如下，也没忘夸奖下自己随机应变的能力：

```//=> [1, NaN, NaN]
_.map(['1NO', '2FOOL', '3ME'], parseInt);```

```var ary = ['1NO', '2FOOL', '3ME'];

//=> [1, NaN, NaN]
_.map(ary, function (val, idx, ary) {
return parseInt(val, idx, ary);
});

var first = parseInt('1NO', 0, ary);     //=> 1
var middle = parseInt('2FOOL', 1, ary);  //=> NaN
var last = parseInt('3ME', 2, ary);      //=> NaN```

`parseInt`调用时可接收可选的第二个参数，元素索引值作为第二个参数无形中传入到`parseInt`，呜呼哀哉！第一个例子为什么没问题？因为 Number 只接收一个参数，而把其后的所有参数都忽略，所以安然无恙。这么看来`Explicit is better than implicit(显优于隐)`的确是真理啊！

```//=> [1, 2, 3]
_.map(['1NO', '2FOOL', '3ME'], _.partial(parseInt, _, 10));```

```function curry2(fun) {
return function (second) {
return function (first) {
return fun(first, second);
};
};
}```

```//=> [1, 2, 3]
_.map(['1NO', '2FOOL', '3ME'], curry2(parseInt)(10));```

```//=> [1, NaN, NaN]
_.map(['1NO', '2FOOL', '3ME'], _.partialRight(parseInt, 10));```

```_.noop = function () {};
_.identity = function (val) { return val; };```

```_.identity('I');                  //=> 'I'
_.identity('I', 'FOOL');          //=> 'I'
_.identity('I', 'FOOL', 'YOU');   //=> 'I'```

```//=> true
_.isEqual( g(f(x)), _.compose(g, f)(x) );```

```//=> [1, 2, 3]
_.map( ['1NO', '2FOOL', '3ME'], _.compose( _.partialRight(parseInt, 10), _.identity ) );```

## 思维发散

```//=> ['left', 'center', 'right']
_.map(['left  ', ' center ', '  right'], function (s) {
return s.trim();
});```

```var str = ' center ';

//=> true
str.trim() === _.result(str, 'trim');```

`_.result`调用像不像此前的`parseInt`？这样，我们之前的方法再次奏效：

```var ary = ['left  ', ' center ', '  right'];

// Underscore v1.6.0
_.map(ary, _.partial( _.result, _, 'trim' ));

// Lodash v2.4.1
_.map(ary, _.compose( _.partialRight( _.result, 'trim' ), _.identity ));

// Underscore & Lodash
_.map(ary, curry2( _.result )( 'trim' ));```

## 延伸拓展

```function take2(first, second) {
return [first, second];
}

//=> ['first', 'second']
take2('first', 'second', 'third');

//=> ['first', 'second']
take2('first', 'second', 'third', 'forth');```

```function max(/* args */) {
return Math.max.apply(Math, arguments);
}

//=> 42
max(8, 4, 15, 42, 23, 16);```

`max`方法很简单，它返回任意输入 Number 型参数的最大值。给它输入的单个单个参数依次是`8, 4, 15, 42, 23, 16`。现在假设我只想知道输入参数的前两个哪个最大。我们脑海里首先闪过的可能是如下答案：

```function max_initial(first, second) {
return max(first, second);
}

//=> 8
max_initial(8, 4, 15, 42, 23, 16);```

```function max_initial2(/* args */) {
return max.apply(null, take2.apply(null, arguments));
}

//=> 8
max_initial2(8, 4, 15, 42, 23, 16);```

```var max_initial3 = _.compose(max, take2);

//=> NaN
max_initial3(8, 4, 15, 42, 23, 16);```

Does it work？Nope！Why？`max_initial3`函数执行实际等价于如下代码：

```//=> [8, 4]
var result = take2(8, 4, 15, 42, 23, 16);

//=> NaN
max(result);```

```function splat(fun) {
return function (array) {
return fun.apply(null, array);
};
}

//=> 8

Looks pretty neat, doesn’t it?有了适配器后，我们再用`_.compose`将它们衔接起来：

```var max_initial4 = _.compose(splat(max), take2);

//=> 8
max_initial4(8, 4, 15, 42, 23, 16);```

```function unsplat(fun) {
return function () {
return fun.call(null, [].slice.call(arguments));
};
}

// 既然我们使用Underscore或Lodash，我们何不写成这样呢！
function unsplat(fun) {
return function () {
return fun.call(null, _.toArray(arguments));
};
}```

`unsplat`能用在什么地方呢？Let’s have a try!

```function take(n, array) {
return array.slice(0, n);
}

//=> [8, 4]
take(2, [8, 4, 15, 42, 23, 16]);```

```var take2 = _.partial(take, 2);
var take3 = _.partial(take, 3);

//=> [8, 4]
take2([8, 4, 15, 42, 23, 16]);

//=> [8, 4, 15]
take3([8, 4, 15, 42, 23, 16]);```

```var take2 = unsplat(_.partial(take, 2));
var take3 = unsplat(_.partial(take, 3));

//=> [8, 4]
take2(8, 4, 15, 42, 23, 16);

//=> [8, 4, 15]
take3(8, 4, 15, 42, 23, 16);```

```var max_revamped = _.compose( splat(max), unsplat( _.partial(take, 3) ) );

//=> 15
max_revamped(8, 4, 15, 42, 23, 16);```

Now everything is under control! 如果我们了解`_.wrap`方法，我们可以做的更疯狂：

```var max_fancy = _.compose(
_.wrap( max, splat )(),
_.wrap( _.partial(take, 3), unsplat )()
);

//=> 15
max_fancy(8, 4, 15, 42, 23, 16);```

## 总结

0 条评论

• ### 社区文章测试 URL 链接合法性

https://en.wikipedia.org/wiki/Rod_Johnson_%28programmer%29

• ### 微信小程序文件上传下载应用场景

微信小程序提供了一套在微信上运行小程序的解决方案，有比较完整的框架、组件以及 API，在这个平台上面的想象空间很大。基于微信小程序轻便、快捷的特点，使用腾讯云简...

• ### Node.js 进程平滑离场剖析

使用 Node.js 搭建 HTTP Server 已是司空见惯的事。在生产环境中，Node 进程平滑重启直接关系到服务的可靠性，它的重要性不容我们忽视。既然是...

• ### python中几个概念汇总

生成器和列表生成式的区别仅在于最外层的 [] 和 () 。[] 表示列表生成式，() 表示生成器。

• ### 手把手教你安装SqlServer

Power BI支持几乎所有主流的数据库。不过，毕竟自己家有亲儿子SqlServer，所以对Directquery和更加神级的增量刷新的支持自然要多加照顾了。

• ### odoo10源码win系统开发环境安装图文教程

odoo10的源码安装教程不太完整或对新手不够友好，本新手再次整合出一份友好的新手教程（老鸟慎入）

• ### Generator函数

JavaScript是单线程的，异步编程对于 JavaScript语言非常重要。如果没有异步编程，根本没法用，得卡死不可。