首先,有个单例对象,它上面挂了很多静态工具方法。其中有一个是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,它的 .each/ .map 很方便的拷贝到了 ().each/ ().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);
};
});
|