underscore是一个非常实用的javascript库,提供许多编程时需要的功能的支持,在不扩展任何javascript原生对象的情况下提供很多实用的功能。主要涉及对Collection、Object、Array、Function的操作。一共60多个函数。
函数介绍:
一、Collection Functions (Arrays or Objects) 【集合函数】:
1、#each# _.each(list, iterator, [context])
迭代list中的所有元素,按顺序用迭代器输出每个元素。如果传递了context参数,则把iterator绑定到context对象上。每次调用iterator都会传递三个参数:(element, index, list)
。如果list是个JavaScript对象,iterator的参数是(value, key, list)
。存在原生的forEach方法,Underscore就委托给forEach.
_.each([1, 2, 3], function(num){ console.log(num); }); // 1,2,3 _.each({one : 1, two : 2, three : 3}, function(num, key){ console.log(num); }); // 1,2,3 // html:
var p = document.getElementsByTagName(‘p’);
_.each(p , function( value, key, list ){ console.log( value ); // p1,p2,p2 console.log( key ); // 0,1,2 })
2、#map# _.map(list, iterator, [context])
用转换函数把list中的每个值映射到一个新的数组。如果list是个JavaScript对象,iterator的参数是(value, key, list)
,这里的用法和each
一样。 map
和 each
的区别就是map
可以接受返回值。
var r = _.map([1, 2, 3], function(num){ return num * 3; }); console.log(r); // [3, 6, 9] var r = _.map({one : 1, two : 2, three : 3}, function(num, key){ return num * 3; }); console.log(r); // [3, 6, 9]
3、#reduce# _.reduce(list, iterator, memo, [context])
reduce方法把列表中元素归结为一个简单的数值,Memo是reduce函数的初始值,reduce的每一步都需要由iterator返回。
var sum = _.reduce([1, 2, 3], function(memo, num){ return memo + num; }, 0); // 6
这个函数有些浏览器提供了原生的,但是对不知道的童鞋,可能很难通过这个例子明白函数的试用方法,好的,看源码:
// 代码的前面就声明了一个变量,检测是否支持原生reduce: var nativeReduce = ArrayProto.reduce; _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { var initial = arguments.length > 2; if (obj == null) obj = []; if (nativeReduce && obj.reduce === nativeReduce) { // 使用原生的reduce if (context) iterator = _.bind(iterator, context); return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator); } each(obj, function(value, index, list) { if (!initial) { memo = value; initial = true; } else { memo = iterator.call(context, memo, value, index, list); } }); if (!initial) throw new TypeError(‘Reduce of empty array with no initial value‘); return memo; };
解释上面的例子就是:试用迭代器把obj(1,2,3)里面的元素相加,由于设置了初始值(0),那就先加初始值,每次的相加的值都存储在memo里面。所以结果是0+1+2+3=6。
4、#reduceRight# _.reduceRight(list, iterator, memo, [context])
reducRight是从右侧开始组合的元素的reduce函数,如果存在JavaScript 1.8版本的reduceRight,则用其代替。Foldr在javascript中不像其它有懒计算的语言那么有用(lazy evaluation:一种求值策略,只有当表达式的值真正需要时才对表达式进行计算)。
var list = [[0, 1], [2, 3], [4, 5]]; var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []); => [4, 5, 2, 3, 0, 1]
5、#find# _.find(list, iterator, [context])
遍历list,返回第一个通过iterator真值检测的元素值。如果找到匹配的元素立即返回,不会遍历整个list。
var r = _.find([1, 2, 3, 4, 5, 6], function(num){ if(num > 3) return true; }); // r == 4
6、#filter# _.filter(list, iterator, [context])
遍历list,返回包含所有通过iterator真值检测的元素值。如果存在原生filter方法,则委托给filter, 和find不同的是,它返回所有符合条件的值,返回一个数组。
var r = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; }); // r == [2, 4, 6]
7、#reject# _.reject(list, iterator, [context])
返回那么没有通过iterator真值检测的元素数组,filter
的相反函数。
var r = _.reject([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; }); //r == [1, 3, 5]
8、#all# _.all(list, iterator, [context])
如果list中的所有元素都通过iterator的真值检测就返回true。如果存在原生的every方法,则委托给every。
var r = _.all([2, 22, 12, 4, 34, 68], function(num){ return num % 2 == 0; }); // r == true;
9、#any# _.any(list, [iterator], [context])
如果有任何一个元素通过通过 iterator 的真值检测就返回true。如果存在原生的some方法,则委托给some。
var r = _.all([2, 1, 13, 6, 37, 68], function(num){ return num % 2 == 0; }); // r == true;
10、#contains# _.contains(list, value)
如果list包含指定的value则返回true,使用===检测是否相等。如果list 是数组,内部使用indexOf判断。
var r = _.contains([1, 2, 3], 3); // r == true _.contains({one:1,two:2},1); // r == true
11、#invoke#_.invoke(list, methodName, [*arguments])
在list的每个元素上执行methodName方法。如果有额外的参数,则在调用methodName方法的时候传给它。
_.invoke([[5, 1, 7], [3, 2, 1]], ‘sort‘); // [[1, 5, 7], [1, 2, 3]] // 进行排序操作
12、#pluck#_.pluck(list, propertyName)
提取对象中的一个属性,返回一个数组。
var stooges = [{name : ‘moe‘, age : 40}, {name : ‘larry‘, age : 50}, {name : ‘curly‘, age : 60}]; _.pluck(stooges, ‘name‘); // ["moe", "larry", "curly"]
13、#max#_.max(list, [iterator], [context])
返回list中的最大值,迭代器可选,如果有,则以迭代器作为排序依据。
var stooges = [{name : ‘moe‘, age : 40}, {name : ‘larry‘, age : 50}, {name : ‘curly‘, age : 60}]; _.max(stooges, function(stooge){ return stooge.age; }); // {name : ‘curly‘, age : 60};
14、#min#_.min(list, [iterator], [context])
返回list中的最小值,迭代器可选,如果有,则以迭代器作为排序依据。
var numbers = [10, 5, 100, 2, 1000]; _.min(numbers); // 2
15、#sortBy#_.sortBy(list, iterator, [context])
返回一个通过升序排序后的一个数组(新的数组),如果有迭代器,以迭代器作为排序依据。
_.sortBy([1, 2, 3, 4, 5, 6], function(num){ return Math.sin(num); }); // [5, 4, 6, 3, 1, 2]
16、#groupBy#_.groupBy(list, iterator)
通过迭代器返回的值分组,生成一个json对象。迭代器也可以是一个字符串,通过调用元素对应的属性分组。
_.groupBy([1.3, 2.1, 2.4], function(num){ return Math.floor(num); }); // {1: [1.3], 2: [2.1, 2.4]} _.groupBy([‘one‘, ‘two‘, ‘three‘], ‘length‘); // {3: ["one", "two"], 5: ["three"]}
17、#countBy#_.countBy(list, iterator)
对list进行分组,返回一个json对象,对应的键值对是:分组名(在迭代器里面设置)和数量。
_.countBy([1, 2, 3, 4, 5], function(num) { return num % 2 == 0 ? ‘even‘ : ‘odd‘; }); // {odd: 3, even: 2}
18、#shuffle#_.shuffle(list)
返回一个打乱了的list数组副本。
_.shuffle([1, 2, 3, 4, 5, 6]); // [4, 1, 6, 3, 5, 2]
19、#toArray#_.toArray(list)
转换list为数组,对有参数对象的转换很有用。
(function(){ return _.toArray(arguments).slice(1); })(1, 2, 3, 4); // [2, 3, 4]
20、#size#_.size(list)
返回list的长度
_.size({one:1,two:2}); // 2
二、Array Functions【数组函数】:
1、#first# _.first(array, [n])
返回array的第一个元素,设置了参数n,就返回前n个元素。
_.first([5, 4, 3, 2, 1]); // 5 _.first([5,4,3,2,1],3); // [5,4,3]
2、#last# _.last(array,[n])
返回list的最后一个元素,设置参数n,则返回最后n个元素。
_.last([5, 4, 3, 2, 1]); // 1 _.last([5, 4, 3, 2, 1],2); // [2,1]
3、#initial# _.initial(array, [n])
返回除了最后一个元素以外的所有元素。对参数对象特别有用。设置了参数n,就排除最后n个元素。
_.initial([5, 4, 3, 2, 1]); // [5, 4, 3, 2] _.initial([5, 4, 3, 2, 1] , 3); // [5, 4]
4、#rest# _.rest(array, [index])
返回除了第一个元素以外的所有元素。设置了参数n,就排除前n个元素。
_.rest([5, 4, 3, 2, 1]); // [4, 3, 2, 1] _.rest([5, 4, 3, 2, 1],2); // [3, 2, 1]
5、#compact# _.compact(array)
返回一个去除了false值的元素的数组副本。在javascript里,false,null,0,“”,undefined,NaN是false值。
_.compact([0, 1, false, 2, ‘‘, 3]); // [1, 2, 3]
6、#flatten# _.flatten(array, [shallow])
展开一个嵌套数组(可以是任何嵌套级数),如果设置了参数shallow,就只能展开一个等级。
_.flatten([1, [2], [3, [[4]]]]); // [1, 2, 3, 4]; _.flatten([1, [2], [3, [[4]]]], true); // [1, 2, 3, [[4]]];
7、#without# _.without(array, [*values])
返回一个去处了values之后的数组副本。
_.without([1, 2, 1, 0, 3, 1, 4], 0, 1); // [2, 3, 4]
8、#union# _.union(*arrays)
计算传入的 arrays(数组)并集:按顺序返回一个存在于一个或多个 arrays(数组)中独一无二的项目列表。
_.union([1, 2, 3], [101, 2, 1, 10], [2, 1]); // [1, 2, 3, 101, 10]
9、#intersection# _.intersection(*arrays)
计算数组的交集:每个值都出现在每个是数组里。
_.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]); // [1, 2]
10、#difference _.difference(array, *others)
和without差不多,不过它返回的是不在其他数组里面的值。
_.difference([1, 2, 3, 4, 5], [5, 2, 10]); // [1, 3, 4]
11、#uniq# _.uniq(array, [isSorted], [iterator])
去除数组重复,使用===测试。如果你确定数组已经排序,就传递true给isSorted。返回新的数组副本。
_.uniq([1, 2, 1, 3, 1, 4]); // [1, 2, 3, 4]
12、#zip# _.zip(*arrays)
在对应的位置合并每一个数组元素,当你有单独的有用数据源时通过匹配数组索引协调。如果您正在使用嵌套的数组矩阵,zip.apply可以转置矩阵相似的方式。
_.zip([‘moe‘, ‘larry‘, ‘curly‘], [30, 40, 50], [true, false, false]); // [["moe", 30, true], ["larry", 40, false], ["curly", 50, false]]
13、#object# _.object(list, [values])
把数组变成对象,可以传入键值对,也可以传入一个键数组,一个值数组。
_.object([‘moe‘, ‘larry‘, ‘curly‘], [30, 40, 50]); // {moe: 30, larry: 40, curly: 50} _.object([[‘moe‘, 30], [‘larry‘, 40], [‘curly‘, 50]]); // {moe: 30, larry: 40, curly: 50}
14、#indexOf# _.indexOf(array, value, [isSorted])
返回值在数组里面的索引,-1表示找不到。传true给isSorted,表示数组已经排序,可以提高速度。
_.indexOf([1, 2, 3], 2); // 1
15、#lastIndexOf# _.lastIndexOf(array, value, [fromIndex])
返回value在array最后开始的索引值,没有则返回-1。
_.lastIndexOf([1, 2, 3, 1, 2, 3], 2); // 4
16、#sortedIndex# _.sortedIndex(list, value, [iterator])
运用二进制搜索,查找value在list里面可插入的位置,传true给isSorted,表示数组已经排序,可以提高速度。
_.sortedIndex([10, 20, 30, 40, 50], 35); // 3
17、#range# _.range([start], stop, [step])
一个用来创建整数灵活编号的列表的函数,便于each 和 map循环。如果省略start则默认为 0;step 默认为 1.返回一个从start 到stop的整数的列表,用step来增加 (或减少)独占。
_.range(10); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] _.range(1, 11); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] _.range(0, 30, 5); // [0, 5, 10, 15, 20, 25] _.range(0, -10, -1); // [0, -1, -2, -3, -4, -5, -6, -7, -8, -9] _.range(0); // []
三、Functions 【函数】
1、#bind# _.bind(function, object, [*arguments])
绑定一个函数到一个对象上面,不管什么时候调用函数,this指针都是指向对象。也可以为函数绑定参数。
var func = function(greeting){ return greeting + ‘: ‘ + this.name }; func = _.bind(func, {name : ‘moe‘}, ‘hi‘); func(); // ‘hi: moe‘
2、#bindAll# _.bindAll(object, [*methodNames])
把methodNames参数指定的方法绑定到对象上,这些方法就会在对象的上下文环境中执行。绑定函数用作事件处理函数时非常便利,否则函数被调用时this一点用也没有。如果不设置methodNames参数,对象上的所有方法都会被绑定。
var buttonView = { label : ‘underscore‘, onClick : function(){ alert(‘clicked: ‘ + this.label); }, onHover : function(){ console.log(‘hovering: ‘ + this.label); } }; _.bindAll(buttonView); jQuery(‘#underscore_button‘).bind(‘click‘, buttonView.onClick); // When the button is clicked, this.label will have the correct value...
3、#memoize# _.memoize(function, [hashFunction])
记录函数的计算结果。对比较耗时的计算有帮助。如果设置了参数hashFunction,就用hashFunction的返回值作为key存储函数的计算结果。 hashFunction默认使用function的第一个参数作为key.
var fibonacci = _.memoize(function(n) { return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2); });
4、#delay# _.delay(function, wait, [*arguments])
和setTimeout差不多,在wait时间后调用函数,如果设置了参数,就在调用函数时,传递参数。
var log = _.bind(console.log, console); _.delay(log, 1000, ‘logged later‘); // ‘logged later‘
5、#defer# _.defer(function, [*arguments])
延迟执行函数知道当前栈被清空,和delay为0的setTimeout差不多。对HTML无阻赛渲染有帮助。如果设置了参数,就在函数调用时传递进去。
_.defer(function(){ alert(‘deferred‘); }); // Returns from the function before the alert runs.
6、#throttle# _.throttle(function, wait)
创建并返回一个节流版本的函数,当重复调用函数时,就强制间隔wait时段才执行。
var throttled = _.throttle(updatePosition, 100); $(window).scroll(throttled);
7、#debounce# _.debounce(function, wait, [immediate])
创建并返回一个控制函数,当该函数被调用,wait毫秒后才执行,wait毫秒期间如果再次触发则重新计时。
var lazyLayout = _.debounce(calculateLayout, 300); $(window).resize(lazyLayout);
8、#once# _.once(function)
创建返回一个一次性函数。调用之后就不能再调用了。
var initialize = _.once(createApplication); initialize(); initialize(); // Application is only created once.
9、#after# _.after(count, function)
创建返回一个函数,在这个函数别调用了count次之后,才开始运行里面的function。
var a = _.after(5,fun); $(window).click(a);
10、#wrap# _.wrap(function, wrapper)
把第一个函数包裹在包裹器里。
var hello = function(name) { return "hello: " + name; }; hello = _.wrap(hello, function(func) { return "before, " + func("moe") + ", after"; }); hello(); // ‘before, hello: moe, after‘
11、#compose# _.compose(*functions)
返回一个函数列的组合物,其中每个函数的参数是其后跟随函数的返回值。在数学关系上,f() g()和h()函数的组合产生f(g(h()))。
var greet = function(name){ return "hi: " + name; }; var exclaim = function(statement){ return statement + "!"; }; var welcome = _.compose(exclaim, greet); welcome(‘moe‘); // ‘hi: moe!‘
四、Object【对象】
1、#keys# _.keys(object)
返回一个装有object的键的数组
_.keys({one : 1, two : 2, three : 3}); => ["one", "two", "three"]
2、#values# _.values(object)
返回一个装有object的值的数组
_.values({one : 1, two : 2, three : 3}); => [1, 2, 3]
3、#pairs# _.pairs(object)
把对象的键值对转变为一个二维数组,并放到一个大的数组内
_.pairs({one: 1, two: 2, three: 3}); => [["one", 1], ["two", 2], ["three", 3]]
4、#invert# _.invert(object)
复制一个对象,把object的键值反转返回。
_.invert({Moe: "Moses", Larry: "Louis", Curly: "Jerome"}); => {Moses: "Moe", Louis: "Larry", Jerome: "Curly"};
5、#functions# _.functions(object)
返回一个数组,里面装有object的所有函数名称
_.functions(_); => ["all", "any", "bind", "bindAll", "clone", "compact", "compose" ...
6、#extend# _.extend(destination, *sources)
扩展,源对象将覆盖或者创建目标对象的属性
var a = {name : ‘moe‘} _.extend(a, {age : 50}); => a == {name : ‘moe‘, age : 50}
7、#pick# _.pick(object, *keys)
通过keys从object选择出键值对,放到一个新建的object返回
ps:keys也可以是一个包含有效键的数组
_.pick({name : ‘moe‘, age: 50, userid : ‘moe1‘}, ‘name‘, ‘age‘); => {name : ‘moe‘, age : 50} _.pick({name : ‘moe‘, age: 50, userid : ‘moe1‘}, [‘name‘, ‘age‘]); => {name : ‘moe‘, age : 50}
8、#omit# _.omit(object, *keys)
通过keys忽略object里面的键值对,剩下的放入一个新建的对象返回。
ps:keys也可以是一个包含有效键的数组,基本跟pick
相反
_.omit({name : ‘moe‘, age : 50, userid : ‘moe1‘}, ‘userid‘); => {name : ‘moe‘, age : 50}
9、#defaults#
_.defaults(object,*defaults)
为对象设置默认值,如果对象没有设置值,则就调用默认值。
var iceCream = {flavor : "chocolate"}; _.defaults(iceCream, {flavor : "vanilla", sprinkles : "lots"}); => {flavor : "chocolate", sprinkles : "lots"}
10、
#clone# _.clone(object)
浅复制
_.clone({name : ‘moe‘}); => {name : ‘moe‘};
11、
#tap# _.tap(object ,interceptor)
摸索中
_.chain([1,2,3,200]) .filter(function(num) { return num % 2 == 0; }) .tap(alert) .map(function(num) { return num * num }) .value(); => // [2, 200] (alerted) => [4, 40000]
12、
#has# _.has(object, key)
判断object是否含有给出的key
_.has({a: 1, b: 2, c: 3}, "b"); => true
13、
#isEqual# _.isEqual(object, ohter)
深度对比了两个object是否相等
var moe = {name : ‘moe‘, luckyNumbers : [13, 27, 34]}; var clone = {name : ‘moe‘, luckyNumbers : [13, 27, 34]}; moe == clone; => false _.isEqual(moe, clone); => true
14、
#isEmpty#_.isEmpty(object)
object是否为空
_.isElement(jQuery(‘body‘)[0]); => true
15、
#isArray# _.isArray(object)
object是否为数组
(function(){ return _.isArray(arguments); })(); => false _.isArray([1,2,3]); => true
16、
#isObject# _.isObject(object)
object是否为对象
_.isObject({}); => true _.isObject(1); => false
17、
#isArguments# _.isArguments(object)
object是否为参数对象
(function(){ return _.isArguments(arguments); })(1, 2, 3); => true _.isArguments([1,2,3]); => false
18、
#isFunction#_.isFunction(object)
object是否为函数
_.isFunction(alert); => true
19、
#isString# _.isString(object)
object是否为字符串
_.isString("moe"); => true
20、
#isNumber# _.isNumber(object)
object是否为数字
_.isNumber(8.4 * 5); => true
21、
#isFinite# _.isFinite(object)
object是否为有限数
_.isFinite(-101); => true _.isFinite(-Infinity); => false
22、
#isBoolean# _.isBoolean(object)
object是否为布尔值
_.isBoolean(null); => false
23、
#isDate# _.isDate(object)
object是否为日期
_.isDate(new Date()); => true
24、
#isRegExp# _.isRegExp(object)
object是否为正则表达式
_.isRegExp(/moe/); => true
25、
#isNaN# _.isNaN(object)
object是否为NaN
_.isNaN(NaN); => true isNaN(undefined); => true _.isNaN(undefined); => false
26、
#isNull# _.isNull(object)
object是否为Null
_.isNull(null); => true _.isNull(undefined); => false
27、
#isUndefined# _.isUndefined(object)
object是否为undefined
_.isUndefined(window.missingVariable); => true
underscore.js