First, there is a singleton object with many static tool methods attached to it. One of them is each, which is used to traverse arrays or objects.
Copy the code code as follows:
var nativeForEach = [].forEach
var nativeMap = [].map
varutil = {
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, etc. that operate on collections (Array, Hash). Use the util.xx method when using it.
If a collection class is defined, there is collection data inside this class.
Copy the code code as follows:
function Collection(data) {
this.data = data || []
// some other properties
// this.xxx = yyy
}
Collection.prototype = {
// some method
}
You can easily copy the methods on util to the collection class, such as
Copy the code code as follows:
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)
After copying in this way, the Collection instance will have the method on util, and the collection object (first parameter) operated by util is this.data of Collection. You can directly traverse this.data as follows.
Copy the code code as follows:
var coll = new Collection([10, 20, 30])
// traverse
coll.each(function(k) {
console.log(k)
})
// operate
var arr = coll.map(function(k) {
returnk-5
})
console.log(arr) // 5, 15, 25
This pattern is used in many open source libraries, such as jQuery, whose $.each/$.map is conveniently copied to $().each/$().map.
Another example is Backbone, whose _.each/_.map/_.every/_.chain (and many more) are copied to the Collection prototype.
Copy the code code as follows:
// 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);
};
});
In addition, practical methods for operating objects such as _.keys / _.values / _.pairs / _.invert / _.pick are copied to Backbone.Model (new in 1.0)
Copy the code code as follows:
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);
};
});