作者:Soaring_Tiger 转载请注明出处
前情提要: lodash中文学习拾零之Array篇
可以说是 lodash 中最为重要的部件,想要用lodash进行复杂的多步操作都离不开chain的帮助。
首先说说Chain的调用方式有两种:一种是显式调用(Explicit Chaining),一种是隐式调用(Implicit Chaining)。
//下面的例子采用了ECMAScript2015的语法:
//显式调用例子如下:
let numbers = [1, 2, 3, 4, 5];
let sumOfEvenSquares = _.chain(numbers) //注意numbers放置的位置
.filter(n => n % 2 === 0)
.map(n => n * n)
.sum()
.value();
//sumOfEvenSquares: 20
//特别要注意结尾的那个.value()
//隐式调用例子如下:
let sumOfEvenSquares = _(numbers) //注意numbers的位置,不需要显式的使用chain关键字
.filter(n => n % 2 === 0)
.map(n => n * n)
.sum()
let isEven = n => n % 2 === 0;
let square = n => n * n;
let sumOfEvenSquares = _(numbers).filter(isEven).map(square).sum();
从上面例子可以看出,隐式调用比显式调用更加简洁方便。
为什么要多出来一个 .value(),而不是直接出结果呢?那是因为可能要等待延时(Deferred execution)数据的到来,再执行取值。这就是我们常说的Lazy evaluation (延迟计算/惰性求值)
//如下面的例子:首先生成链式表达式
var wallet = _(assets).filter(ownedBy('me'))
.pluck('value')
.reduce(sum);
$json.get("/new/assets").success(function(data) {
assets.push.apply(assets, data); // 然后更新数据
wallet.value(); // 最后求值
});
听起来好乱!看看 lodash的API怎么说:
_(value) Creates a lodash object which wraps value to enable implicit chaining. Methods that operate on and return arrays, collections, and
functions can be chained together. Methods that retrieve a single
value or may return a primitive value will automatically end the chain
returning the unwrapped value. Explicit chaining may be enabled using
.chain. The execution of chained methods is lazy, that is, execution is deferred until #value is implicitly or explicitly called.
大意如下:
_(value)建立了一个隐式链对象,可以把那些能操作并返回 arrays(数组)、collections(集合)、functions(函数)的”.Methods”(lodash的函数)串起来。 那些能返回“唯一值(single value)”或者可能返回原生数据类型(primitive value)会自动结束链式反应。
而显式链则用_.chain. 的方式实现延迟计算,即:求值操作等到 _value()被调用时再执行。
Lazy evaluation allows several methods to support shortcut fusion. Shortcut fusion is an optimization strategy which merge iteratee calls; this can help to avoid the creation of intermediate data structures and greatly reduce the number of iteratee executions.
延迟计算允许一些方法支持shortcut fusion 。由于执行被延后了,因此lodash可以进行shortcut fusion这样的优化,通过合并链式iteratee大大降低迭代的次数。
另外,lodash wrappers 还支持Array和String的一些方法:
The wrapper Array methods are(支持wrapper的Array方法有):
concat, join, pop, push, reverse,shift, slice, sort, splice, unshift
The wrapper String methods are(支持wrapper的String方法有):
replace,split
The wrapper methods that support shortcut fusion are(支持shortcut fusion的方法有):
compact, drop, dropRight, dropRightWhile, dropWhile, filter, first, initial, last,map, pluck, reject, rest, reverse, slice, take, takeRight, takeRightWhile, takeWhile, toArray, where
The chainable wrapper methods are(可以链式反应的wrapper方法有):
after, ary, assign, at, before, bind, bindAll, bindKey, callback, chain, chunk, commit, compact,concat, constant, countBy, create, curry, debounce, defaults,defaultsDeep, defer, delay, difference, drop, dropRight, dropRightWhile, dropWhile, fill, filter, flatten, flattenDeep, flow, flowRight, forEach, forEachRight, forIn, forInRight, forOwn, forOwnRight, functions, groupBy, indexBy, initial, intersection,
invert, invoke, keys, keysIn, map, mapKeys, mapValues, matches,
matchesProperty, memoize, merge, method, methodOf, mixin, modArgs, negate, omit, once, pairs, partial, partialRight, partition, pick,
plant, pluck, property, propertyOf, pull, pullAt, push, range, rearg,
reject, remove, rest, restParam, reverse, set, shuffle, slice, sort,
sortBy, sortByAll, sortByOrder, splice, spread, take, takeRight,
takeRightWhile, takeWhile, tap, throttle, thru, times, toArray,
toPlainObject, transform, union, uniq, unshift, unzip, unzipWith,
values, valuesIn, where, without, wrap, xor, zip, zipObject, zipWith
The wrapper methods that are not chainable by default are(缺省情况下不能加在”链条”中间的wrapper方法有):
add, attempt, camelCase, capitalize, ceil, clone, cloneDeep, deburr, endsWith, escape,escapeRegExp, every, find, findIndex, findKey, findLast,findLastIndex, findLastKey, findWhere, first, floor, get, gt, gte, has, identity, includes, indexOf, inRange, isArguments, isArray,isBoolean, isDate, isElement, isEmpty, isEqual, isError, isFinite, isFunction, isMatch, isNative, isNaN, isNull, isNumber, isObject, isPlainObject, isRegExp, isString, isUndefined, isTypedArray, join, kebabCase, last, lastIndexOf, lt, lte, max, min, noConflict, noop, now, pad, padLeft, padRight, parseInt, pop, random, reduce, reduceRight, repeat, result, round, runInContext, shift, size, snakeCase, some, sortedIndex, sortedLastIndex, startCase, startsWith, sum, template, trim, trimLeft, trimRight, trunc, unescape, uniqueId, value, words
//举个例子:
var wrapped = _([1, 2, 3]);
// 隐式链中,reduce是属于不能直接加在"链条中间"(not chainable)的,所以能立即执行计算
wrapped.reduce(function(total, n) {
return total + n;
});
// → 6
// 而map是chainable的
var squares = wrapped.map(function(n) {
return n * n;
});
//所以不调用value()时返回的并不是一个Array而是一个wrapper
_.isArray(squares);
// → false
//调用了value后返回的就是一个wrapper了
_.isArray(squares.value());
// → true
拦截器,拿tap来干嘛?你可以在链条当中插它一下,可以对数据进行处理,可以返回值也可以不返回值,也可以仅仅是打印一下中间的过程,拿tap来debug 链式反应的过程是不错的选择。
_([1, 4, 3, 5])
.tap(function(array) {
array.pop(); //对array进行操作
console.log(array); //打印
return array.reverse(); //返回值,也可以不返回值
})
.value(); //取值
// → [3,4,1]
和 tap非常相似,但是必须有返回值,否则会报错!
_(' abc ')
.chain()
.trim()
.thru(function(value) {
return '处理后:[' + value + ']'; //必须有返回值
})
.value();
// → 处理后:[abc]
允许wrapper对象使用显式链。这样就允许隐式链可以切换为显式链。
var users = [
{ 'user': '阿帕奇', 'age': 36 },
{ 'user': '弗雷德', 'age': 40 }
];
//第一个例子没用显式链,注意first()在缺省情况下是只能被加在反应链尾部的
//参看前面的 ***not chainable***
_(users).first();
// → { 'user': '阿帕奇', 'age': 36 }
// 第二个例子启用了显式链,在启用了chain后,first就可以加到链条中间了
_(users).chain()
.first()
.pick('user')
.value();
// → { 'user': '阿帕奇' }
Executes the chained sequence and returns the wrapped result.
Returns
(Object): Returns the new lodash wrapper instance.
执行链条并返回wrapped instance;
要注意与.prototype.value()的区别,commit()与value()都会触发链式反应,但是返回的值不同。
var array = [1, 2];
var wrapped = _(array).push(3);
console.log(array);
// → [1, 2] 这个时候 array的值还没有发生变化
wrapped = wrapped.commit();
console.log(wrapped);
//{ __wrapped__: [ 1, 2, 3 ], __actions__: [], __chain__: false }
console.log(array);
// → [1, 2, 3] 在commit之后 array的值发生变化了
wrapped.last();
// → 3
Executes the chained sequence to extract the unwrapped value.
Returns
(*): Returns the resolved unwrapped value.
执行链条,并且返回unwrapped后的值,注意与上边.commit()的比较
别名:
.prototype.run, .prototype.toJSON, _.prototype.valueOf
_([1, 2, 3]).value();
// → [1, 2, 3]
新建一个数组,将原始数组与新加入的值合并起来。
var array = [1];
var wrapped = _(array).concat(2, [3], [[4]]);
console.log(wrapped.value());
// → [1, 2, 3, [4]]
console.log(array);
// → [1] 注意:原数组并未发生改变
克隆一个已有的操作链
var array = [1, 2];
var wrapped = _(array).map(function(value) {
return Math.pow(value, 2);
});
var other = [3, 4];
var otherWrapped = wrapped.plant(other);
otherWrapped.value();
// → [9, 16]
wrapped.value();
// → [1, 4]
反转数组元素的次序:注意改方法会改变被操作的数组。
var array = [1, 2, 3];
_(array).reverse().value()
// → [3, 2, 1]
console.log(array);
// → [3, 2, 1]
将unwrapped 的值转为字符串。
_([1, 2, 3]).toString();
// → '1,2,3'