JavaScript 鏈?zhǔn)浇Y(jié)構(gòu)序列化詳解
一、概述
在JavaScript中,鏈?zhǔn)侥J酱a,太多太多,如下:
if_else:
if(...){
//TODO
}else if(...){
//TODO
}else{
//TODO
}
switch:
switch(name){
case ...:{
//TODO
break;
}
case ...:{
//TODO
break;
}
default:{
//TODO
}
}
疑問(wèn):諸如上述這些鏈?zhǔn)酱a,倘若,我們想將其扁平化鏈?zhǔn)教幚砟兀咳缦拢?/p>
//fn1,f2,f3為處理函數(shù)
_if(fn1)._elseIf(fn2)._else(fn3);
下面我們就來(lái)一起嘗試實(shí)現(xiàn)下唄。
二、鏈?zhǔn)酱a扁平化
假如,現(xiàn)在我們有如下鏈?zhǔn)酱a:
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!');
}
好了,現(xiàn)在我們一步一步將其"扁平化"。
其實(shí)看看上面的代碼,不難發(fā)現(xiàn),if…else這種格式,其實(shí)就是數(shù)據(jù)結(jié)構(gòu)中的單鏈表,那么,初步利用JavaScript實(shí)現(xiàn)單鏈表,如下:
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為判斷函數(shù),并且我們假設(shè),如果諸如f1、f2、f3返回'next'時(shí),就繼續(xù)往下查找,否則,停止往下查找。如下:
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!');
}
好了,這就是鏈表的模式。
但是,我們的最終目的是想實(shí)現(xiàn)如下這樣的呢?
//fn1,f2,f3為處理函數(shù)
_if(fn1)._elseIf(fn2)._else(fn3);
你可能會(huì)說(shuō),將上述代碼改成如下這樣,不就好了嗎???!
thens.push(f1).push(f2).push(f3).resolve();
But,JavaScript的push方法返回的是數(shù)組的新長(zhǎng)度,而不是數(shù)組對(duì)象哦。
So,那我們只能新寫(xiě)一個(gè)add方法,效果和push一樣,但是返回?cái)?shù)組對(duì)象。如下:
thens.add = function(f){
if(typeof f === 'function'){
this.push(f);
return this;
}
}
測(cè)試代碼如下:
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();
但是,這樣有個(gè)缺點(diǎn),我們是將add、resolve方法綁定在全局變量thens中的,總不能每次創(chuàng)建一個(gè)數(shù)組時(shí),都復(fù)制粘貼一遍方法吧,所以重構(gòu)代碼如下:
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這種公共方法,在每次實(shí)例化時(shí),都創(chuàng)建一遍是不科學(xué)的,so,利用prototype在原有的基礎(chǔ)上繼續(xù)變形,如下:
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;
}
}
}
}
測(cè)試代碼如下:
var thens = new Slink();
thens.add(f1).add(f2).add(f3);
thens.resolve();
不錯(cuò),但是這樣,我們每次都得手動(dòng)new一個(gè)Slink,有點(diǎn)麻煩,所以,我們將new Slink這個(gè)過(guò)程,封裝到函數(shù)中,如同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;
}
}
}
}
測(cè)試代碼如下:
$go(f1).add(f2).add(f3).resolve();
好了,大功告成,接下來(lái)就是語(yǔ)法糖滴問(wèn)題咯,整理代碼如下:
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;
}
}
測(cè)試代碼如下:
_if(f1)._elseIf(f2)._else(f3).resolve();
當(dāng)然,除開(kāi)利用數(shù)組這種方式,還可以利用閉包,實(shí)現(xiàn)鏈?zhǔn)奖馄交Ч?,如下?br />
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;
}
}
測(cè)試代碼如下:
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');
三、異步代碼鏈?zhǔn)奖馄交?/strong>
在上面我們討論的都是同步過(guò)程,倘若,鏈?zhǔn)秸{(diào)用函數(shù)中有異步情況呢?
什么意思?如下:
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變成了異步,按照上述代碼的邏輯,應(yīng)該是等f(wàn)1完全執(zhí)行完畢(包括setTimeout執(zhí)行)后,判斷是否執(zhí)行f2,但真的如此嗎?
測(cè)試代碼如下:
_if(f1)._elseIf(f2)._else(f3).resolve();
執(zhí)行代碼的結(jié)果就是,什么也不輸出。
Why?
因?yàn)镴avaScript是單線程嘛。詳情見(jiàn)(here)
那該怎么解決呢?
由于有異步代碼,且必須在異步代碼后處理后續(xù)的鏈,那么我們就等待異步代碼執(zhí)行完畢后,才執(zhí)行后續(xù)的鏈嘛,如下:
function f1(name){
setTimeout(function(){
if(name === 'Monkey'){
console.log('yes, I am Monkey');
}else{
//處理后續(xù)鏈
this.resolve(name, 1);//1代表下一個(gè)需處理函數(shù)在數(shù)組中的位置
}
}.bind(this), 2000);
}
好了,由于在函數(shù)中,我們使用了this,其代表Slink對(duì)象,且改變了resolve方法,固,需細(xì)微調(diào)整Slink構(gòu)造函數(shù)和原型鏈,如下:
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;
}
}
測(cè)試代碼如下:
function f1(name){
setTimeout(function(){
if(name === 'Monkey'){
console.log('yes, I am Monkey');
}else{
//處理后續(xù)鏈
this.resolve(name, 1);//1代表下一個(gè)需處理函數(shù)在數(shù)組中的位置
}
}.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,是不是感覺(jué)這么相似呢。
是的,宗旨都一樣,達(dá)到異步代碼扁平化目的,不過(guò)這里的代碼比Promise要簡(jiǎn)約得多啦。關(guān)于Promise詳情見(jiàn)(here)。
感謝閱讀此文,希望能幫助到大家,謝謝大家對(duì)本站的支持!
- 在jmeter的beanshell中用java獲取系統(tǒng)當(dāng)前時(shí)間的簡(jiǎn)單實(shí)例
- Java簡(jiǎn)單實(shí)現(xiàn)對(duì)一串?dāng)?shù)字采用相應(yīng)的加密策略后傳輸
- java實(shí)現(xiàn)多線程的兩種方式繼承Thread類(lèi)和實(shí)現(xiàn)Runnable接口的方法
- javascript的幾種寫(xiě)法總結(jié)
- JavaScript 對(duì)象詳細(xì)整理總結(jié)
- 輕松掌握J(rèn)ava迭代器模式
- Java 鎖的知識(shí)總結(jié)及實(shí)例代碼
- java 數(shù)據(jù)結(jié)構(gòu)二叉樹(shù)的實(shí)現(xiàn)代碼
- JAVA 獲取系統(tǒng)當(dāng)前時(shí)間實(shí)例代碼
相關(guān)文章
JavaScript的繼承實(shí)現(xiàn)小結(jié)
JavaScript作為面向?qū)ο蟮娜躅?lèi)型語(yǔ)言,繼承也是其非常強(qiáng)大的特性之一。那么如何在JS中實(shí)現(xiàn)繼承呢?本文將給大家揭開(kāi)神秘面紗2017-05-05
前后臺(tái)交互過(guò)程中json格式如何解析以及如何生成
json格式想必大家會(huì)很熟悉;因?yàn)樗赼jax異步應(yīng)用中會(huì)顯得很有魅力,有些新手朋友對(duì)其有點(diǎn)陌生,接下來(lái)介紹前臺(tái)如何解析json格式以及后臺(tái)如何生成json格式等,需要了解的朋友可以參考下2012-12-12
為JS擴(kuò)展Array.prototype.indexOf引發(fā)的問(wèn)題及解決辦法
這篇文章主要介紹了為JS擴(kuò)展Array.prototype.indexOf引發(fā)的問(wèn)題及解決辦法,需要的朋友可以參考下2015-01-01
淺談javascript:兩種注釋,聲明變量,定義函數(shù)
下面小編就為大家?guī)?lái)一篇淺談javascript:兩種注釋,聲明變量,定義函數(shù)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-09-09
JavaScript字符串處理(String對(duì)象)詳解
這篇文章主要介紹了JavaScript字符串處理(String對(duì)象)詳解,本文列出并詳細(xì)講解了String對(duì)象的一些方法,需要的朋友可以參考下2014-10-10
怎樣在JavaScript里寫(xiě)一個(gè)swing把數(shù)據(jù)插入數(shù)據(jù)庫(kù)
在JavaScript里寫(xiě)一個(gè)swing來(lái)實(shí)現(xiàn)確定取消,來(lái)決定是否執(zhí)行這個(gè)功能 控制把數(shù)據(jù)插入數(shù)據(jù)庫(kù),接下來(lái)介紹實(shí)現(xiàn)方法2012-12-12
JavaScript 學(xué)習(xí)初步 入門(mén)教程
看了《21天學(xué)習(xí)JavaScript》的視頻教程,感覺(jué)就是語(yǔ)法好熟悉,和C++類(lèi)似,和C#類(lèi)似,和Java類(lèi)似!幡然悔悟這些語(yǔ)言的語(yǔ)法都是類(lèi)似的,數(shù)據(jù)類(lèi)型,對(duì)象方法(或者稱之為函數(shù),由于我是個(gè)菜鳥(niǎo)所以也數(shù)不清楚到底是什么)。2010-03-03
簡(jiǎn)單總結(jié)JavaScript中的String字符串類(lèi)型
就像其他語(yǔ)言那樣,js中的字符串類(lèi)型可以表示一串字符,由雙引號(hào)包住,這里簡(jiǎn)單總結(jié)JavaScript中的String字符串類(lèi)型的一些基礎(chǔ)知識(shí)2016-05-05

