在分享以前,先分享一個$經過id的鏈式調用:css
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的鏈式調用,上面的代碼咱們其實能夠這樣使用:算法
var fn = new Fn('test');json
可是咱們不可能每個id都去建立實例對象,因此這樣使用:瀏覽器
window.$ = function (el) {
return new Fn(el)
}
複製代碼
固然,這個鏈式調用很是簡陋,只是說明一下思路。bash
迴歸今天分享的主題,underscore,這個函數庫在業界內很出名,可是本人卻歷來沒用過,估計只有那些算法寫的多的纔會用吧。underscore兼容了低版本瀏覽器,實現了對json的遍歷。Underscore其實不支持鏈式調用,想要鏈式調用須要使用chain方法實現鏈式調用:app
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的三個函數源碼:函數
var _ = function(obj) {
if (obj instanceof _) return obj;
if (!(this instanceof _)) return new _(obj);
this._wrapped = obj;
};
複製代碼
_函數傳入一個obj參數,若是是_的實例對象則直接返回,若是不是就返回new _(obj),也就是_實例對象,而且把參數放在wrapped上。ui
_.chain = function(obj) {
var instance = _(obj);
instance._chain = true;
return instance;
};
複製代碼
調用chain方法,實例一個_實例對象,並賦值chain = true。this
var chainResult = function(instance, obj) {
return instance._chain ? _(obj).chain() : obj;
};
複製代碼
若是instance裏面的chain是true,說明調用了chain方法,就繼續調用chain方法,不然直接返回參數obj。spa
我不知道underscore裏面作了什麼處理,(obj).chain() 會報錯,由於chain方法是對象_的方法,(obj)返回的是new _(obj),是實例對象,是沒有chain方法的。
這邊分享一下,構造函數若是返回的是一個object對象,那麼實例對象就是這個object對象,返回基礎數據類型都不會。函數其實都有隱式的return undefined:
function Fn() {
return {}
}
Fn.prototype.name = 'wade';
var fn = new Fn();
複製代碼
沒有return {}的時候:
console.log(fn.name);//wade
有return {}的時候:
console.log(fn.name);//undefined
console.log(fn);//{}
因此這邊的chainResult改爲:
var chainResult = function(instance, obj) {
return instance._chain ? _.chain(obj) : obj;
};
複製代碼
原本想實現map和filter方法,後來發現寫不出來,因而就實現push和shift兩個最簡單的方法。最終代碼:
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有一個遍歷添加的方法:
// 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絕對是更復雜的。能夠知道一下,本人研究的時候知道了,可是仍是不會用,估計一段時間以後還會忘記。