一、概述
在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);
你可能会说,将上述代码改成如下这样,不就好了吗?!!
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)。
感谢阅读此文,希望能帮助到大家,谢谢大家对本站的支持!
io 包中定义了下面几个结构体: ByteReader ByteWriter RawReader Reader Writer 它们之间的关系是: +---------------------------------------------------------+ | _ _ _ _ | |
本文向大家介绍详解JavaScript树结构,包括了详解JavaScript树结构的使用技巧和注意事项,需要的朋友参考一下 对于数据结构“树”,想必大家都熟悉,今儿,我们就再来回顾一下数据结构中的二叉树与树,并用JavaScript实现它们。 ps:树结构在前端中,很多地方体现得淋漓尽致,如Vue的虚拟DOM以及冒泡等等。 二叉树 --概念-- 二叉树是一种树形结构,它的特点是每个结点至多只有两棵
本文向大家介绍javascript数据结构之双链表插入排序实例详解,包括了javascript数据结构之双链表插入排序实例详解的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了javascript数据结构之双链表插入排序实现方法。分享给大家供大家参考,具体如下: 数组存储前提下,插入排序算法,在最坏情况下,前面的元素需要不断向后移,以便在插入点留出空位,让目标元素插入。 换成链表时,显然无需
主要内容:链表的节点,头节点,头指针和首元节点,链表的创建(初始化)前面详细地介绍了 顺序表,本节给大家介绍另外一种 线性存储结构—— 链表。 链表,别名 链式存储结构或 单链表,用于存储逻辑关系为 "一对一" 的数据。 与顺序表不同,链表不限制数据的物理存储状态,换句话说,使用链表存储的数据元素,其物理存储位置是随机的。 例如,使用链表存储 ,数据的物理存储状态如图 1 所示: 图 1 链表随机存储数据 我们看到,图 1 根本无法体现出各数据之间的逻辑关系。对
本文向大家介绍Javascript数据结构与算法之列表详解,包括了Javascript数据结构与算法之列表详解的使用技巧和注意事项,需要的朋友参考一下 前言:在日常生活中,人们经常要使用列表,比如我们有时候要去购物时,为了购物时东西要买全,我们可以在去之前,列下要买的东西,这就要用的列表了,或者我们小时候上学那段时间,每次考完试后,学校都会列出这次考试成绩前十名的同学的排名及成绩单,等等这些都是列
本文向大家介绍php中序列化与反序列化详解,包括了php中序列化与反序列化详解的使用技巧和注意事项,需要的朋友参考一下 把复杂的数据类型压缩到一个字符串中 serialize() 把变量和它们的值编码成文本形式 unserialize() 恢复原先变量 eg: 结果:a:3:{i:0;s:3:"Moe";i:1;s:5:"Larry";i:2;s:5:"Curly";} Array ( [0] =