Underscore鏈式調用

在分享以前,先分享一個$經過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絕對是更復雜的。能夠知道一下,本人研究的時候知道了,可是仍是不會用,估計一段時間以後還會忘記。

相關文章
相關標籤/搜索