关于 Underscore 的 mixin 方法。 首先先看个例子:1
2
3
4
5
6
7
8
9
10
function Panel ( ) {
consoe.log(this , this instanceof Panel);
if (this instanceof Panel) {
return this ;
} else {
return new Panel();
}
}
a = Panel();
b = new Panel();
当函数作为构造器使用时,函数内的 this
执行被新建的对象。当函数被调用时,函数内的 this
则为被调用的对象,在这里是 Window
。1
2
3
4
5
var _ = function (obj ) {
if (obj instanceof _) return obj;
if (!(this instanceof _)) return new _(obj);
this ._wrapped = obj;
};
同样的,如果我们使用下面方法调用:
第二个条件成立,所以新建一个 _
对象后返回,注意这里是再次调用这个函数。 如果我们这样调用:
就好像上面第二次调用一样,这时候就构造了 under
这个对象,如果传入了参数 obj
,则把 obj
存入 under
这个对象的 _wrapped
属性中。Underscore
提供了一个 OO 的调用方法,即:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var chainResult = function (instance, obj ) {
return instance._chain ? _(obj).chain() : obj;
};
_.mixin = function (obj ) {
_.each(_.functions(obj), function (name ) {
var func = _[name] = obj[name];
_.prototype[name] = function ( ) {
var args = [this ._wrapped];
push.apply(args, arguments );
return chainResult(this , func.apply(_, args));
};
});
return _;
};
_.mixin(_);
当然我们还可以把自己写的方法通过 mixin
加入到 Underscore
对象中。 在这段代码后面还把原生的一些操作方法也添加到这个 _
上面,这样我们就可以直接在 _
上调用这些方法。例如:1
2
3
4
5
6
7
8
9
10
_.each(['pop' , 'push' , 'reverse' , 'shift' , 'sort' , 'splice' , 'unshift' ], function (name ) {
var method = ArrayProto[name];
_.prototype[name] = function ( ) {
var obj = this ._wrapped;
method.apply(obj, arguments );
if ((name === 'shift' || name === 'splice' ) && obj.length === 0 ) delete obj[0 ];
return chainResult(this , obj);
};
});
上面这些方法并不是 Underscore 新建的,不存在于 Underscore 对象的原型链上,所以我们要把他们加进去。和上面 mixin
方法类似,下面这段代码是为了兼容 IE 而采取的操作:1
if ((name === 'shift' || name === 'splice' ) && obj.length === 0 ) delete obj[0 ];
jdalton commented on 6 Dec 2011 IE bugs with splice() and shift(), failing to remove the 0 indexed value, when using an array-like-object with _(…). IE compatibility mode and IE < 9 have buggy Array shift() and splice() functions that fail to remove the last element, object[0], of array-like-objects even though the length property is set to 0.
通过上面这些方法把 Underscore 转化为可面向对象编程,调用更加优雅,我们可以有以下两种使用方法:1
2
_.map([1 , 2 , 3 ], function (n ) { return n * 2 ; });
_([1 , 2 , 3 ]).map(function (n ) { return n * 2 ; });
至于选择哪一种就看你的喜好了~