以前在网上做过一个面试题,在一个有序的数组查找特定值,如果存在返回数组下标,否则将数值插入数组中。我的之前做法在这里!
通过进一步学习underscoreJS,发现可以这么写
var arr = [10,20,30], value = 35;
var location = _.sortIndex( arr, value);
arr[location] == value || arr.splice( location, 0, value);
如上所示,代码简单了很多!那效率究竟怎么样呢?看到underscore的源码发现源码中利用的是二分查找,时间复杂度是logn,而我那个就是n,差了不仅一点点。
为什么underscore这么好?因为它关注重点,功能专一
_.sortedIndex = function(array, obj, iterator, context) { iterator = lookupIterator(iterator); var value = iterator.call(context, obj); var low = 0, high = array.length; while (low < high) { var mid = (low + high) >>> 1; iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;//why? } return low; };
上面的代码为什么这么写?难道是保留上下文才这么写的吗?在上面的代码中至少学到了
1.位运算;
2.函数递归调用与闭包的使用。
第二点 each方法的使用
在underscore.js中很多的函数都是为集合服务的,里面包括很多的迭代操作!
var each = _.each = _.forEach = function(obj, iterator, context) { if (obj == null) return obj; if (nativeForEach && obj.forEach === nativeForEach) {//nativeForEach obj.forEach(iterator, context); } else if (obj.length === +obj.length) {//array for (var i = 0, length = obj.length; i < length; i++) { if (iterator.call(context, obj[i], i, obj) === breaker) return; } } else {//object var keys = _.keys(obj); for (var i = 0, length = keys.length; i < length; i++) { if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return; } } return obj; };
函数中首先定义局部变量,在作用域下方便使用。
1.使用本地的forEach的方法。
2.判断数组的情况
3.判断对象的情况。判断对象的情况的时候特别有意思的一点,它没有像jQuery在对象中为每个对象给出0,1,2,3等属性,而是将属性存为属性数组,
然后遍历‘属性数组’,取出对象中属性对应的值。
_.keys = function(obj) { if (!_.isObject(obj)) return []; if (nativeKeys) return nativeKeys(obj); var keys = []; for (var key in obj) if (_.has(obj, key)) keys.push(key); return keys; };