JavaScript利用apply和arguments复用集合操作方法
本文介绍如何利用JavaScript的apply方法和arguments对象,将静态工具方法(如each、map)灵活复用至自定义集合类或DOM元素上。通过arguments.shift和apply结合,可改变函数执行上下文与参数,实现类似jQuery或Backbone的链式调用模式,提升代码复用率。
利用apply和arguments复用集合操作方法
首先,存在一个单例对象,其中挂载了多个静态工具方法。其中一个典型方法是each,专门用于遍历数组或对象结构。
相关实现代码如下:
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的方式访问这些方法。
假设现在定义了一个集合类,该类内部维护着实际的集合数据。
相关定义代码如下:
function Collection(data) {
this.data = data || []
// some other property
// this.xxx = yyy
}
Collection.prototype = {
// some method
}
可以非常便捷地将util对象上的方法拷贝到该集合类的原型上,例如:
具体拷贝代码示例如下:
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进行遍历操作。
使用示例代码如下:
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,其$.each/$.map方法便很方便地拷贝到了$().each/$.map中。
再如Backbone,其_.each/_.map/_.every/_.chain(以及更多其他方法)也都拷贝到了Collection的原型上。
Backbone的相关实现代码如下:
// 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版本新增功能)。
具体实现代码如下:
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);
};
}); JS大数值转字符串出现科学计数法怎么办
2026-11-05 17:09:21
JS split切割后出现空字符串怎么过滤
2026-11-05 16:00:30
在 React 或 Vue 项目中封装使用 JS 节流防抖
2026-11-05 15:27:29
JavaScript中怎么将带小数的字符串转为整数?
2026-11-05 14:32:38
怎么用JavaScript策略模式重构电商促销计算逻辑?
2026-11-05 14:01:09
