Underscore.js的源码和适合第一次看源码的人,因为文件比较小,而且没有依赖,读起来比较轻松。代码写的还很是很简练的。
我看的是1.7的源码,下面说说我觉得比较有意思的几个地方
1.
_.isUndefined = function(obj) { return obj === void 0; };
代码里好几个地方都用到了void 0,而不是undefined判断一个object是不是undefined。据说这样是因为有些浏览器允许改变undefined的值。比如undefined = 1
2.
以前用jQuery的时候就用到过noConflict,一直在好奇是怎么实现的。原来Underscore.js里的实现这么简单
var root = this; var previousUnderscore = root._; _.noConflict = function() { root._ = previousUnderscore; return this; };
3.
Underscore.js支持两种方式调用,一种是直接用_.func(params)调用,还有以类似oop的方式调用
_.each([‘a‘, ‘b‘, ‘c‘], function(element, index){ console.log(element); }); _([‘a‘, ‘b‘, ‘c‘]).each(function(element, index){ console.log(element); });
这是怎么做到的呢?
首先,定义了_下面的函数,比如
_.each = _.forEach = function(obj, iteratee, context) { if (obj == null) return obj; iteratee = createCallback(iteratee, context); var i, length = obj.length; if (length === +length) { for (i = 0; i < length; i++) { iteratee(obj[i], i, obj); } } else { var keys = _.keys(obj); for (i = 0, length = keys.length; i < length; i++) { iteratee(obj[keys[i]], keys[i], obj); } } return obj; };
如果把javascript中的对象看作类,这样的定义就类似定义了类 ‘_’的static成员函数,直接通过 _.func就可以调用。但是 类‘_‘的实例 new _(),是不能调用的。
只是oop主要靠下面的两个函数
var _ = function(obj) { if (obj instanceof _) return obj; if (!(this instanceof _)) return new _(obj); this._wrapped = obj; }; // Add your own custom functions to the Underscore object. _.mixin = function(obj) { _.each(_.functions(obj), function(name) { var func = _[name] = obj[name]; _.prototype[name] = function() { var args = [this._wrapped]; push.apply(args, arguments); return result.call(this, func.apply(_, args)); }; }); }; // Add all of the Underscore functions to the wrapper object. _.mixin(_);
先看第一个函数,当调用_([‘a‘, ‘b‘, ‘c‘])的时候,第一个函数会执行。它做的事情就是把一个obj变成了‘_‘的一个实例(new _()),并且把obj存到该实例的_wrapped中。
该函数的实现也很有意思。当调用_[‘a‘, ‘b‘, ‘c‘]的时候,第一次执行到第二句,this是全局的window, 因此if(!(this instanceof _)) 成立,所以执行new _(obj),这时候第二次进入该函数,此时的this已经是新的_ instance实例,因此直接执行到了第三行,即把this_wrapped赋值为obj。
TBC...
时间: 2024-10-07 06:26:01