在分享之前,先分享一个$通过id的链式调用:
代码语言:javascript复制function Fn(elId) {
this.el = document.getElementById(elId);
return this
}
Fn.prototype.css = function (prop, val) {
this.el.style[prop] = val;
return this
}
Fn.prototype.hidden = function () {
this.css('display', 'none');
return this
}
Fn.prototype.show = function () {
this.css('display', 'block');
return this
}
window.$ = function (el) {
return new Fn(el)
}
$('test').css('width','300px').css('height','300px').css('background', 'red').hidden().show()
之前分享this的链式调用,上面的代码我们其实可以这样使用:
代码语言:javascript复制var fn = new Fn('test');
但是我们不可能每一个id都去创建实例对象,所以这样使用:
代码语言:javascript复制window.$ = function (el) {
return new Fn(el)
}
当然,这个链式调用非常简陋,只是说明一下思路。
回归今天分享的主题,underscore,这个函数库在业界内很出名,但是本人却从来没用过,估计只有那些算法写的多的才会用吧。underscore兼容了低版本浏览器,实现了对json的遍历。Underscore其实不支持链式调用,想要链式调用需要使用chain方法实现链式调用:
代码语言:javascript复制var mapFilter = _.chain([1, 2, 3]).filter(function (a, b, c) {
return a > 1}).map(function (a, b, c) {
return a > 1}).value()
console.log(mapFilter);//[true, true]
先看一下underscore的三个函数源码:
代码语言:javascript复制var _ = function(obj) {
if (obj instanceof _) return obj;
if (!(this instanceof _)) return new _(obj);
this._wrapped = obj;
};
_函数传入一个obj参数,如果是_的实例对象则直接返回,如果不是就返回new _(obj),也就是_实例对象,并且把参数放在wrapped上。
代码语言:javascript复制_.chain = function(obj) {
var instance = _(obj);
instance._chain = true;
return instance;
};
调用chain方法,实例一个_实例对象,并赋值chain = true。
代码语言:javascript复制var chainResult = function(instance, obj) {
return instance._chain ? _(obj).chain() : obj;
};
如果instance里面的chain是true,说明调用了chain方法,就继续调用chain方法,否则直接返回参数obj。
我不知道underscore里面做了什么处理,_(obj).chain() 会报错,因为chain方法是对象_的方法,_(obj)返回的是new _(obj),是实例对象,是没有chain方法的。
这边分享一下,构造函数如果返回的是一个object对象,那么实例对象就是这个object对象,返回基础数据类型都不会。函数其实都有隐式的return undefined:
代码语言:javascript复制function Fn() {
return {}
}
Fn.prototype.name = 'wade';
var fn = new Fn();
没有return {}的时候:
代码语言:javascript复制console.log(fn.name);//wade
有return {}的时候:
代码语言:javascript复制console.log(fn.name);//undefined
console.log(fn);//{}
所以这边的chainResult改成:
代码语言:javascript复制var chainResult = function(instance, obj) {
return instance._chain ? _.chain(obj) : obj;
};
本来想实现map和filter方法,后来发现写不出来,于是就实现push和shift两个最简单的方法。最终代码:
代码语言:javascript复制var _ = function(obj) {
if (obj instanceof _) return obj;
if (!(this instanceof _)) return new _(obj);
this._wrapped = obj;
};
_.prototype.shift = function () {
this._wrapped.shift();
return chainResult(this, this._wrapped)
}
_.prototype.push = function (num) {
this._wrapped.push(num);
return chainResult(this, this._wrapped)
}
_.chain = function(obj) {
var instance = _(obj);
instance._chain = true;
return instance;
};
var chainResult = function(instance, obj) {
return instance._chain ? _.chain(obj) : obj;
};
console.log(_.chain([1, 2, 3]).push(10).shift()._wrapped)//[2, 3, 10]
我这边没有写value方法,value方法其实就是返回_wrapped。看underscore的源码,你会发现没有多少个函数调用了chainResult,其实underscore有一个遍历添加的方法:
代码语言:javascript复制// Add your own custom functions to the Underscore
object._.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 _;
};// Add all of the Underscore functions to the wrapper object._.mixin(_);
把所有的方法都调用chainResult。
这就是简单的underscore链式调用的原理,还是那句话,underscore绝对是更复杂的。可以知道一下,本人研究的时候知道了,但是还是不会用,估计一段时间之后还会忘记。
(完)