// Underscore.js 1.3.3 // (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc. // Underscore is freely distributable under the MIT license. // Portions of Underscore are inspired or borrowed from Prototype, // Oliver Steele's Functional, and John Resig's Micro-Templating. // For all details and documentation: // http://documentcloud.github.com/underscore (function() { // 创建一个全局对象, 在浏览器中表示为window对象, 在Node.js中表示global对象 var root = this; // 保存"_"(下划线变量)被覆盖之前的值 // 如果出现命名冲突或考虑到规范, 可通过_.noConflict()方法恢复"_"被Underscore占用之前的值, 并返回Underscore对象以便重新命名 var previousUnderscore = root._; // 创建一个空的对象常量, 便于内部共享使用 var breaker = {}; // 将内置对象的原型链缓存在局部变量, 方便快速调用 var ArrayProto = Array.prototype, // ObjProto = Object.prototype, // FuncProto = Function.prototype; // 将内置对象原型中的常用方法缓存在局部变量, 方便快速调用 var slice = ArrayProto.slice, // unshift = ArrayProto.unshift, // toString = ObjProto.toString, // hasOwnProperty = ObjProto.hasOwnProperty; // 这里定义了一些JavaScript 1.6提供的新方法 // 如果宿主环境中支持这些方法则优先调用, 如果宿主环境中没有提供, 则会由Underscore实现 var nativeForEach = ArrayProto.forEach, // nativeMap = ArrayProto.map, // nativeReduce = ArrayProto.reduce, // nativeReduceRight = ArrayProto.reduceRight, // nativeFilter = ArrayProto.filter, // nativeEvery = ArrayProto.every, // nativeSome = ArrayProto.some, // nativeIndexOf = ArrayProto.indexOf, // nativeLastIndexOf = ArrayProto.lastIndexOf, // nativeIsArray = Array.isArray, // nativeKeys = Object.keys, // nativeBind = FuncProto.bind; // 创建对象式的调用方式, 将返回一个Underscore包装器, 包装器对象的原型中包含Underscore所有方法(类似与将DOM对象包装为一个jQuery对象) var _ = function(obj) { // 所有Underscore对象在内部均通过wrapper对象进行构造 return new wrapper(obj); }; // 针对不同的宿主环境, 将Undersocre的命名变量存放到不同的对象中 if( typeof exports !== 'undefined') {// Node.js环境 if( typeof module !== 'undefined' && module.exports) { exports = module.exports = _; } exports._ = _; } else {// 浏览器环境中Underscore的命名变量被挂在window对象中 root['_'] = _; } // 版本声明 _.VERSION = '1.3.3'; // 集合相关的方法(数据和对象的通用处理方法) // -------------------- // 迭代处理器, 对集合中每一个元素执行处理器方法 var each = _.each = _.forEach = function(obj, iterator, context) { // 不处理空值 if(obj == null) return; if(nativeForEach && obj.forEach === nativeForEach) { // 如果宿主环境支持, 则优先调用JavaScript 1.6提供的forEach方法 obj.forEach(iterator, context); } else if(obj.length === +obj.length) { // 对<数组>中每一个元素执行处理器方法 for(var i = 0, l = obj.length; i < l; i++) { if( i in obj && iterator.call(context, obj[i], i, obj) === breaker) return; } } else { // 对<对象>中每一个元素执行处理器方法 for(var key in obj) { if(_.has(obj, key)) { if(iterator.call(context, obj[key], key, obj) === breaker) return; } } } }; // 迭代处理器, 与each方法的差异在于map会存储每次迭代的返回值, 并作为一个新的数组返回 _.map = _.collect = function(obj, iterator, context) { // 用于存放返回值的数组 var results = []; if(obj == null) return results; // 优先调用宿主环境提供的map方法 if(nativeMap && obj.map === nativeMap) return obj.map(iterator, context); // 迭代处理集合中的元素 each(obj, function(value, index, list) { // 将每次迭代处理的返回值存储到results数组 results[results.length] = iterator.call(context, value, index, list); }); // 返回处理结果 if(obj.length === +obj.length) results.length = obj.length; return results; }; // 将集合中每个元素放入迭代处理器, 并将本次迭代的返回值作为"memo"传递到下一次迭代, 一般用于累计结果或连接数据 _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { // 通过参数数量检查是否存在初始值 var initial = arguments.length > 2; if(obj == null) obj = []; // 优先调用宿主环境提供的reduce方法 if(nativeReduce && obj.reduce === nativeReduce && false) { if(context) iterator = _.bind(iterator, context); return initial "" + i); // 返回的结果是一个二维数组 return results; }; // 搜索一个元素在数组中首次出现的位置, 如果元素不存在则返回 -1 // 搜索时使用 === 对元素进行匹配 _.indexOf = function(array, item, isSorted) { if(array == null) return -1; var i, l; if(isSorted) { i = _.sortedIndex(array, item); return array[i] === item " ' _.escape = function(string) { return ('' + string).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''').replace(/\//g, '/'); }; // 指定一个对象的属性, 返回该属性对应的值, 如果该属性对应的是一个函数, 则会执行该函数并返回结果 _.result = function(object, property) { if(object == null) return null; // 获取对象的值 var value = object[property]; // 如果值是一个函数, 则执行并返回, 否则将直接返回 return _.isFunction(value) "'" : "'", 'r' : '\r', 'n' : '\n', 't' : '\t', 'u2028' : '\u2028', 'u2029' : '\u2029' }; // 遍历所有特殊字符字符串, 并以特殊字符作为key记录字符串形式 for(var p in escapes) escapes[escapes[p]] = p; // 定义模板中需要替换的特殊符号, 包含反斜杠, 单引号, 回车符, 换行符, 制表符, 行分隔符, 段落分隔符 // 在将字符串中的特殊符号转换为字符串形式时使用 var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; // 在将字符串形式的特殊符号进行反转(替换)时使用 var unescaper = /\\(\\|'|r|n|t|u2028|u2029)/g; // 反转字符串中的特殊符号 // 在模板中涉及到需要执行的JavaScript源码, 需要进行特殊符号反转, 否则如果以HTML实体或字符串形式出现, 会抛出语法错误 var unescape = function(code) { return code.replace(unescaper, function(match, escape) { return escapes[escape]; }); }; // Underscore模板解析方法, 用于将数据填充到一个模板字符串中 // 模板解析流程: // 1. 将模板中的特殊符号转换为字符串 // 2. 解析escape形式标签, 将内容解析为HTML实体 // 3. 解析interpolate形式标签, 输出变量 // 4. 解析evaluate形式标签, 创建可执行的JavaScript代码 // 5. 生成一个处理函数, 该函数在得到数据后可直接填充到模板并返回填充后的字符串 // 6. 根据参数返回填充后的字符串或处理函数的句柄 // ------------------- // 在模板体内, 可通过argments获取2个参数, 分别为填充数据(名称为obj)和Underscore对象(名称为_) _.template = function(text, data, settings) { // 模板配置, 如果没有指定配置项, 则使用templateSettings中指定的配置项 settings = _.defaults(settings || {}, _.templateSettings); // 开始将模板解析为可执行源码 var source = "__p+='" + text.replace(escaper, function(match) { // 将特殊符号转移为字符串形式 return '\\' + escapes[match]; }).replace(settings.escape || noMatch, function(match, code) { // 解析escape形式标签 <%- %>, 将变量中包含的HTML通过_.escape函数转换为HTML实体 return "'+\n_.escape(" + unescape(code) + ")+\n'"; }).replace(settings.interpolate || noMatch, function(match, code) { // 解析interpolate形式标签 <%= %>, 将模板内容作为一个变量与其它字符串连接起来, 则会作为一个变量输出 return "'+\n(" + unescape(code) + ")+\n'"; }).replace(settings.evaluate || noMatch, function(match, code) { // 解析evaluate形式标签 <% %>, evaluate标签中存储了需要执行的JavaScript代码, 这里结束当前的字符串拼接, 并在新的一行作为JavaScript语法执行, 并将后面的内容再次作为字符串的开始, 因此evaluate标签内的JavaScript代码就能被正常执行 return "';\n" + unescape(code) + "\n;__p+='"; }) + "';\n"; if(!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; source = "var __p='';" + "var print=function(){__p+=Array.prototype.join.call(arguments, '')};\n" + source + "return __p;\n"; // 创建一个函数, 将源码作为函数执行体, 将obj和Underscore作为参数传递给该函数 var render = new Function(settings.variable || 'obj', '_', source); // 如果指定了模板的填充数据, 则替换模板内容, 并返回替换后的结果 if(data) return render(data, _); // 如果没有指定填充数据, 则返回一个函数, 该函数用于将接收到的数据替换到模板 // 如果在程序中会多次填充相同模板, 那么在第一次调用时建议不指定填充数据, 在获得处理函数的引用后, 再直接调用会提高运行效率 var template = function(data) { return render.call(this, data, _); }; // 将创建的源码字符串添加到函数对象中, 一般用于调试和测试 template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; // 没有指定填充数据的情况下, 返回处理函数句柄 return template; }; // 支持Underscore对象的方法链操作, 可参考 wrapper.prototype.chain _.chain = function(obj) { return _(obj).chain(); }; // Underscore对象封装相关方法 // --------------- // 创建一个包装器, 将一些原始数据进行包装 // 所有的undersocre对象, 内部均通过wrapper函数进行构造和封装 // Underscore与wrapper的内部关系: // -内部定义变量_, 将Underscore相关的方法添加到_, 这样就可以支持函数式的调用, 如_.bind() // -内部定义wrapper类, 将_的原型对象指向wrapper类的原型 // -将Underscore相关的方法添加到wrapper原型, 创建的_对象就具备了Underscore的方法 // -将Array.prototype相关方法添加到wrapper原型, 创建的_对象就具备了Array.prototype中的方法 // -new _()时实际创建并返回了一个wrapper()对象, 并将原始数组存储到_wrapped变量, 并将原始值作为第一个参数调用对应方法 var wrapper = function(obj) { // 原始数据存放在包装对象的_wrapped属性中 this._wrapped = obj; }; // 将Underscore的原型对象指向wrapper的原型, 因此通过像wrapper原型中添加方法, Underscore对象也会具备同样的方法 _.prototype = wrapper.prototype; // 返回一个对象, 如果当前Underscore调用了chain()方法(即_chain属性为true), 则返回一个被包装的Underscore对象, 否则返回对象本身 // result函数用于在构造方法链时返回Underscore的包装对象 var result = function(obj, chain) { return chain ? _(obj).chain() : obj; }; // 将一个自定义方法添加到Underscore对象中(实际是添加到wrapper的原型中, 而Underscore对象的原型指向了wrapper的原型) var addToWrapper = function(name, func) { // 向wrapper原型中添加一个name函数, 该函数调用func函数, 并支持了方法链的处理 wrapper.prototype[name] = function() { // 获取func函数的参数, 并将当前的原始数据添加到第一个参数 var args = slice.call(arguments); unshift.call(args, this._wrapped); // 执行函数并返回结果, 并通过result函数对方法链进行封装, 如果当前调用了chain()方法, 则返回封装后的Underscore对象, 否则返回对象本身 return result(func.apply(_, args), this._chain); }; }; // 将内部定义的_(下划线, 即Underscore方法集合对象)中的方法复制到wrapper的原型链中(即Underscore的原型链中) // 这是为了在构造对象式调用的Underscore对象时, 这些对象也会具有内部定义的Underscore方法 _.mixin(_); // 将Array.prototype中的相关方法添加到Underscore对象中, 因此在封装后的Underscore对象中也可以直接调用Array.prototype中的方法 // 如: _([]).push() each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { // 获取Array.prototype中对应方法的引用 var method = ArrayProto[name]; // 将该方法添加到Underscore对象中(实际是添加到wrapper的原型对象, 因此在创建Underscore对象时同时具备了该方法) wrapper.prototype[name] = function() { // _wrapped变量中存储Underscore对象的原始值 var wrapped = this._wrapped; // 调用Array对应的方法并返回结果 method.apply(wrapped, arguments); var length = wrapped.length; if((name == 'shift' || name == 'splice') && length === 0) delete wrapped[0]; // 即使是对于Array中的方法, Underscore同样支持方法链操作 return result(wrapped, this._chain); }; }); // 作用同于上一段代码, 将数组中的一些方法添加到Underscore对象, 并支持了方法链操作 // 区别在于上一段代码所添加的函数, 均返回Array对象本身(也可能是封装后的Array), concat, join, slice方法将返回一个新的Array对象(也可能是封装后的Array) each(['concat', 'join', 'slice'], function(name) { var method = ArrayProto[name]; wrapper.prototype[name] = function() { return result(method.apply(this._wrapped, arguments), this._chain); }; }); // 对Underscore对象进行链式操作的声明方法 wrapper.prototype.chain = function() { // this._chain用来标示当前对象是否使用链式操作 // 对于支持方法链操作的数据, 一般在具体方法中会返回一个Underscore对象, 并将原始值存放在_wrapped属性中, 也可以通过value()方法获取原始值 this._chain = true; return this; }; // 返回被封装的Underscore对象的原始值(存放在_wrapped属性中) wrapper.prototype.value = function() { return this._wrapped; }; }).call(this);
免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件!
如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
桃源资源网 Design By www.nqtax.com
暂无“Underscore.js 1.3.3 中文注释翻译说明”评论...