利用apply和arguments复用方法
首先,有个单例对象,它上面挂了很多静态工具方法。其中有一个是each,用来遍历数组或对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | var nativeForEach = [].forEach var nativeMap = [].map var util = { each: function (obj, iterator, context) { if (obj == null ) return if (nativeForEach && obj.forEach === nativeForEach) { obj.forEach(iterator, context) } else if ( obj.length === +obj.length ) { for ( var i = 0; i < obj.length; i++) { if (iterator.call(obj[i] || context, obj[i], i, obj) === true ) return } } else { for ( var k in obj) { if (iterator.call(obj[k] || context, obj[k], k, obj) === true ) return } } }, map: function (obj, iterator, context) { var results = [] if (obj == null ) return results if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context) this .each(obj, function (val, i, coll) { results[i] = iterator.call(context, val, i, coll) }) return results } } |
还有诸如every、some等对集合(Array,Hash)操作的工具函数。使用时采用util.xx方式。
如果定义了一个集合类,这个类内部有集合数据。
1 2 3 4 5 6 7 8 | function Collection(data) { this .data = data || [] // some other property // this.xxx = yyy } Collection.prototype = { // some method } |
可以很方便的把util上的方法拷贝到集合类上,如
1 2 3 4 5 6 7 8 9 10 11 | function copyMethod(clazz, obj) { for ( var method in obj) { clazz.prototype[method] = function () { var args = [].slice.call(arguments) var target = this .data args.unshift(target) obj[method].apply(obj, args) } } } copyMethod(Collection, util) |
这样拷贝后,Collection的实例就有了util上的方法,util操作的集合对象(第一个参数)就是Collection的this.data。如下直接可以遍历this.data了。
1 2 3 4 5 6 7 8 9 10 11 12 | var coll = new Collection([10, 20, 30]) // 遍历 coll.each( function (k) { console.log(k) }) // 操作 var arr = coll.map( function (k) { return k - 5 }) console.log(arr) // 5, 15, 25 |
这种模式在很多开源库中使用,比如jQuery,它的 .map 很方便的拷贝到了 ().map。
又如Backbone,它的 _.each/_.map/_.every/_.chain (还有很多)都拷贝到了 Collection的原型上。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | // Underscore methods that we want to implement on the Collection. // 90% of the core usefulness of Backbone Collections is actually implemented // right here: var methods = [ 'forEach' , 'each' , 'map' , 'collect' , 'reduce' , 'foldl' , 'inject' , 'reduceRight' , 'foldr' , 'find' , 'detect' , 'filter' , 'select' , 'reject' , 'every' , 'all' , 'some' , 'any' , 'include' , 'contains' , 'invoke' , 'max' , 'min' , 'toArray' , 'size' , 'first' , 'head' , 'take' , 'initial' , 'rest' , 'tail' , 'drop' , 'last' , 'without' , 'difference' , 'indexOf' , 'shuffle' , 'lastIndexOf' , 'isEmpty' , 'chain' ]; // Mix in each Underscore method as a proxy to `Collection#models`. _.each(methods, function (method) { Collection.prototype[method] = function () { var args = slice.call(arguments); args.unshift( this .models); return _[method].apply(_, args); }; }); |
又有,把 _.keys / _.values / _.pairs / _.invert / _.pick 等对对象操作的实用方法拷贝了 Backbone.Model上 (1.0新增)
1 2 3 4 5 6 7 8 9 10 | var modelMethods = [ 'keys' , 'values' , 'pairs' , 'invert' , 'pick' , 'omit' ]; // Mix in each Underscore method as a proxy to `Model#attributes`. _.each(modelMethods, function (method) { Model.prototype[method] = function () { var args = slice.call(arguments); args.unshift( this .attributes); return _[method].apply(_, args); }; }); |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端