Javascript USES apply and arguments to reuse methods
- 2020-03-30 00:00:35
- OfStack
First, there's a singleton with a bunch of static utility methods on it. One of them is each, which traverses groups or objects.
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
}
}
There are also utility functions such as every, some, and so on that operate on collections (Array, Hash). Use util. Xx mode.
If a collection class is defined, it contains the collection data inside the class.
function Collection(data) {
this.data = data || []
// some other property
// this.xxx = yyy
}
Collection.prototype = {
// some method
}
It is easy to copy the method on util to the collection class, e.g
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)
When copied, the instance of the Collection has a method on util, and the Collection object of the util operation (the first parameter) is the this.data of the Collection. As follows, you can directly iterate over this.data.
var coll = new Collection([10, 20, 30])
// traverse
coll.each(function(k) {
console.log(k)
})
// operation
var arr = coll.map(function(k) {
return k - 5
})
console.log(arr) // 5, 15, 25
This pattern is used in many open source libraries, such as jQuery, where the $.each/$.map is conveniently copied to $().each/$().map.
Backbone. each/_. Map /_. Every /_. Chain (and many more) is copied to the Collection prototype.
// 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);
};
});
Also, utility methods such as _. Keys / _. Values / _.
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);
};
});