Underscore是一个JavaScript函数库,在不修改原生对象的基础上提供了很多支持函数式编程的工具。官方文档已经详细的介绍了使用方法,还有大量的栗子。还有加了注释的源代码
Underscore有80多个函数,使用Backbone.js时发现了这个精巧的函数库。这里的javascript templating
可以单独拿出来用到别的小项目中,快速生成前端页面。其它还有forEach
、map
、indexOf
等Array操作中常用但是原生js中没有的功能。最近的新版本中还增加了函数绑定等新功能。
阅读源码时发现我的js基础不是一般的差,下面就是记录我看不懂到看懂的过程。
each _.each(list, iterator, [context]) Alias: forEach
遍历List,用其中的每个值生成一个iterator对象。如果传入了context,则把iterator绑定到context对象上。每次调用iterator对象都会传入三个参数:(element, index, list)
,如果List是一个JavaScript对象,则传入参数:(value, key, list)
。如果有原生的forEach(ECMAScript 5)方法,则会调用原生方法。
var each = _.each = _.forEach = function(obj, iterator, context) { if (obj == null) return; if (nativeForEach && obj.forEach === nativeForEach) { //【1】 obj.forEach(iterator, context); } else if (obj.length === +obj.length) { // 【2】【3】 for (var i = 0, l = obj.length; i < l; i++) { if (iterator.call(context, obj[i], i, obj) === breaker) return; // 【4】【5】 } } else { for (var key in obj) { if (_.has(obj, key)) { if (iterator.call(context, obj[key], key, obj) === breaker) return; } } } };
【1】//nativeForEach = Array.prototype.forEach
【2】 一元运算符+
1. Let expr be the result of evaluating UnaryExpression. 2. Return ToNumber(GetValue(expr)).
【3】这里只检查length属性,这样会有问题的吧,不只是Array,argument才有length属性,如果用户自己构造了一个带length属性的对象,
这样的结果会很意外吧:
function show(val,key,o){ console.log(val); console.log(key); console.log(o); console.log('----'); } var obj = { "length":3, "var1":"one", "var4":"four" }; _.each(obj,show);
执行结果见jsbin:
undefined 0 Object {length: 3, var1: "one", var4: "four"} ---- undefined 1 Object {length: 3, var1: "one", var4: "four"} ---- undefined 2 Object {length: 3, var1: "one", var4: "four"} ----
【4】Function.prototype.call
Function.prototype.call(thisArg [ , arg1 [ , arg2, … ] ] )
call将指定函数Function
作为thisArg
对象的方法来调用,将参数args
传递给Function
,返回值为Function
的返回值。
【5】神秘的breaker
关于underscore.js中断枚举Github有好长的讨论,
Stackoverflow有个回答是简略版
用一个秘密的变量来中断each循环,这个变量是underscore的内部变量。
不暴露在外的原因是原生方法中(目前)没有这个特性,如果这样做了,
就会导致(用户写的代码中的)中断特性只有在原生函数不支持的时候才能用
不过看源码是先尝试用原生的forEach方法,既然原生不支持,那执行到这里的时候就不能中断了?
待续……