国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發 > JS > 正文

JavaScript 鏈式結構序列化詳解

2024-05-06 16:32:12
字體:
來源:轉載
供稿:網友

一、概述

在JavaScript中,鏈式模式代碼,太多太多,如下:

if_else:

if(...){  //TODO}else if(...){  //TODO}else{  //TODO}

switch:

switch(name){  case ...:{    //TODO    break;  }  case ...:{    //TODO    break;  }  default:{    //TODO    }}

疑問:諸如上述這些鏈式代碼,倘若,我們想將其扁平化鏈式處理呢?如下:

//fn1,f2,f3為處理函數
_if(fn1)._elseIf(fn2)._else(fn3);

下面我們就來一起嘗試實現下唄。

二、鏈式代碼扁平化

假如,現在我們有如下鏈式代碼:

if(name === 'Monkey'){  console.log('yes, I am Monkey');}else if(name === 'Dorie'){  console.log('yes, I am Dorie');}else{  console.log('sorry, over for ending!');}

好了,現在我們一步一步將其"扁平化"。

其實看看上面的代碼,不難發現,if…else這種格式,其實就是數據結構中的單鏈表,那么,初步利用JavaScript實現單鏈表,如下:

var thens = [];thens.resolve = function(name){  for(var i = 0, len = this.length; i < len;i++){    if(this[i](name) !== 'next'){      break;    }  }}thens.push(f1, f2, f3);

其中f1,f2,f3為判斷函數,并且我們假設,如果諸如f1、f2、f3返回'next'時,就繼續往下查找,否則,停止往下查找。如下:

function f1(name){  if(name === 'Monkey'){    console.log('yes, I am Monkey');  }else{    return 'next';  }}function f2(name){  if(name === 'Dorie'){    console.log('yes, I am Dorie');  }else{    return 'next';  }}function f3(){  console.log('sorry, over for ending!');}

好了,這就是鏈表的模式。

但是,我們的最終目的是想實現如下這樣的呢?

//fn1,f2,f3為處理函數
_if(fn1)._elseIf(fn2)._else(fn3);

你可能會說,將上述代碼改成如下這樣,不就好了嗎??。?/p>

thens.push(f1).push(f2).push(f3).resolve();

But,JavaScript的push方法返回的是數組的新長度,而不是數組對象哦。

So,那我們只能新寫一個add方法,效果和push一樣,但是返回數組對象。如下:

thens.add = function(f){  if(typeof f === 'function'){    this.push(f);    return this;      }    }

測試代碼如下:

var thens = [];thens.add = function(f){  if(typeof f === 'function'){    this.push(f);    return this;      }    }thens.resolve = function(name){  for(var i = 0, len = this.length; i < len;i++){    if(this[i](name) !== 'next'){      break;    }  }  }thens.add(f1).add(f2).add(f3).resolve();

但是,這樣有個缺點,我們是將add、resolve方法綁定在全局變量thens中的,總不能每次創建一個數組時,都復制粘貼一遍方法吧,所以重構代碼如下:

function Slink(){  this.thens = [];  this.thens.add = function(f){    if(typeof f === 'function'){      this.push(f);      return this;        }      }  this.thens.resolve = function(name){    for(var i = 0, len = this.length; i < len;i++){      if(this[i](name) !== 'next'){        break;      }    }    }}

顯然,add,resolve這種公共方法,在每次實例化時,都創建一遍是不科學的,so,利用prototype在原有的基礎上繼續變形,如下:

function Slink(){  this.thens = [];}Slink.prototype = {  add: function(f){      if(typeof f === 'function'){        this.thens.push(f);        return this;          }      },  resolve: function(name){      for(var i = 0, len = this.thens.length; i < len; i++){        if(this.thens[i](name) !== 'next'){          break;        }      }    }}

測試代碼如下:

var thens = new Slink();
thens.add(f1).add(f2).add(f3);
thens.resolve();

不錯,但是這樣,我們每次都得手動new一個Slink,有點麻煩,所以,我們將new Slink這個過程,封裝到函數中,如同jQuery一樣,如下:

function $go(f){  return new Slink(f);}function Slink(f){  this.thens = [];  this.thens.push(f);}Slink.prototype = {  add: function(f){      if(typeof f === 'function'){        this.thens.push(f);        return this;          }      },  resolve: function(name){      for(var i = 0, len = this.thens.length; i < len; i++){        if(this.thens[i](name) !== 'next'){          break;        }      }    }}

測試代碼如下:

$go(f1).add(f2).add(f3).resolve();

好了,大功告成,接下來就是語法糖滴問題咯,整理代碼如下:

function _if(f){  return new Slink(f);}function Slink(f){  this.thens = [];  this.thens.push(f);}Slink.prototype = {  _elseIf: function(f){      if(typeof f === 'function'){        this.thens.push(f);        return this;          }      },  _else: function(f){      return this._elseIf(f);  },  resolve: function(name){      for(var i = 0, len = this.thens.length; i < len; i++){        if(this.thens[i](name) !== 'next'){          break;        }      }      return this;        }}

測試代碼如下:

_if(f1)._elseIf(f2)._else(f3).resolve();

當然,除開利用數組這種方式,還可以利用閉包,實現鏈式扁平化效果,如下:

var func = Function.prototype;func._else = func._elseIf = function(fn){  var _this = this;  return function(){    var res = _this.apply(this,arguments);    if(res==="next"){ //值為Boolean      return fn.apply(this,arguments);    }    return res;  }}

測試代碼如下:

function f1(name){  if(name === 'Monkey'){    console.log('yes, I am Monkey');  }else{    return 'next';  }}function f2(name){  if(name === 'Dorie'){    console.log('yes, I am Dorie');  }else{    return 'next';  }}function f3(){  console.log('sorry, over for ending!');}f1._elseIf(f2)._else(f3)('Dorie');

三、異步代碼鏈式扁平化

在上面我們討論的都是同步過程,倘若,鏈式調用函數中有異步情況呢?

什么意思?如下:

function f1(name){  setTimeout(function(){    if(name === 'Monkey'){      console.log('yes, I am Monkey');    }else{      return 'next';    }  }, 2000);}function f2(name){  if(name === 'Dorie'){    console.log('yes, I am Dorie');  }else{    return 'next';  }}function f3(){  console.log('sorry, over for ending!');}

我們將f1利用setTimeout變成了異步,按照上述代碼的邏輯,應該是等f1完全執行完畢(包括setTimeout執行)后,判斷是否執行f2,但真的如此嗎?

測試代碼如下:

_if(f1)._elseIf(f2)._else(f3).resolve();

執行代碼的結果就是,什么也不輸出。

Why?

因為JavaScript是單線程嘛。詳情見(here)

那該怎么解決呢?

由于有異步代碼,且必須在異步代碼后處理后續的鏈,那么我們就等待異步代碼執行完畢后,才執行后續的鏈嘛,如下:

function f1(name){  setTimeout(function(){    if(name === 'Monkey'){      console.log('yes, I am Monkey');    }else{      //處理后續鏈      this.resolve(name, 1);//1代表下一個需處理函數在數組中的位置    }  }.bind(this), 2000);}

好了,由于在函數中,我們使用了this,其代表Slink對象,且改變了resolve方法,固,需細微調整Slink構造函數和原型鏈,如下:

function Slink(f){  this.thens = [];  this.thens.push(f.bind(this));}Slink.prototype = {  _elseIf: function(f){      if(typeof f === 'function'){        this.thens.push(f.bind(this));        return this;          }      },  _else: function(f){      return this._elseIf(f.bind(this));  },  resolve: function(name, flag){      for(var i = flag, len = this.thens.length; i < len; i++){        if(this.thens[i](name) !== 'next'){          break;        }      }      return this;        }}

測試代碼如下:

function f1(name){  setTimeout(function(){    if(name === 'Monkey'){      console.log('yes, I am Monkey');    }else{      //處理后續鏈      this.resolve(name, 1);//1代表下一個需處理函數在數組中的位置    }  }.bind(this), 2000);}function f2(name){  if(name === 'Dorie'){    console.log('yes, I am Dorie');  }else{    return 'next';  }}function f3(){  console.log('sorry, over for ending!');}_if(f1)._elseIf(f2)._else(f3).resolve('',0);

哈哈,如果你了解Promise,是不是感覺這么相似呢。

是的,宗旨都一樣,達到異步代碼扁平化目的,不過這里的代碼比Promise要簡約得多啦。關于Promise詳情見(here)。

感謝閱讀此文,希望能幫助到大家,謝謝大家對本站的支持!


注:相關教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 五河县| 漠河县| 南漳县| 大邑县| 通道| 东辽县| 长春市| 曲麻莱县| 任丘市| 大石桥市| 安福县| 托里县| 响水县| 南投县| 洞口县| 凤翔县| 耿马| 成安县| 赣州市| 泸西县| 大同县| 太仓市| 临朐县| 石渠县| 东阳市| 方正县| 克拉玛依市| 九江县| 新民市| 洛浦县| 南康市| 青州市| 龙门县| 台东市| 托里县| 砀山县| 杨浦区| 万山特区| 固阳县| 蕲春县| 那曲县|