一、概述

在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);

下面我们就来一起尝试实现下呗。

该篇博客原文地址:http://www.cnblogs.com/giggle/p/5878285.html

二、链式代码扁平化

假如,现在我们有如下链式代码:

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)。

JavaScript之链式结构序列化的更多相关文章

  1. JavaScript之链式结构序列化1

    一.概述 在JavaScript中,链式模式代码,太多太多,如下: if_else: if(...){ //TODO }else if(...){ //TODO }else{ //TODO } swi ...

  2. JavaScript 链式结构序列化详解

    一.概述 在JavaScript中,链式模式代码,太多太多,如下: if_else: if(...){ //TODO }else if(...){ //TODO }else{ //TODO } swi ...

  3. 深入了解jQuery之链式结构

    本文是在阅读了Aaron艾伦的jQuery源码解析(地址:http://www.imooc.com/learn/172)后的个人体会以及笔记.在这里感谢艾伦老师深入浅出的讲解!! 1 什么是链式? 先 ...

  4. Javascript之链式运动框架1

    第一部分:HTML内容: <script src="6-1.js"></script> <script> window.onload=funct ...

  5. js代码风格之链式结构

    <div class="box"> <ul class="menu"> <li class="level1"& ...

  6. dubbo接口方法重载且入参未显式指定序列化id导致ClassCastException分析

    问题描述&模拟 线上登录接口,通过监控查看,有类型转换异常,具体报错如下图 此报错信息是dubbo consumer端显示,且登录大部分是正常,有少量部分会报类型转换异常,同事通过更换方法名+ ...

  7. [C++][数据结构][算法]单链式结构的深拷贝

    深拷贝(deep-copy),区别于浅拷贝,表示复制所有数据,而不是像浅拷贝一般只复制指针.深拷贝的数据不会因原始数据被delete后而消失. 单链式结构可以实现单链表,栈,队列,树等数据结构.掌握了 ...

  8. C语言 队列 链式结构 实现

    一个C语言链式结构实现的队列 mQueue (GCC编译). /** * @brief C语言实现的链式队列 * @author wid * @date 2013-10-31 * * @note 若代 ...

  9. C语言 栈 链式结构 实现

    一个C语言链式结构实现的栈 mStack (GCC编译). /** * @brief C语言实现的链式结构类型的栈 * @author wid * @date 2013-10-30 * * @note ...

随机推荐

  1. [ 高并发]Java高并发编程系列第二篇--线程同步

    高并发,听起来高大上的一个词汇,在身处于互联网潮的社会大趋势下,高并发赋予了更多的传奇色彩.首先,我们可以看到很多招聘中,会提到有高并发项目者优先.高并发,意味着,你的前雇主,有很大的业务层面的需求, ...

  2. 再讲IQueryable<T>,揭开表达式树的神秘面纱

    接上篇<先说IEnumerable,我们每天用的foreach你真的懂它吗?> 最近园子里定制自己的orm那是一个风生水起,感觉不整个自己的orm都不好意思继续混博客园了(开个玩笑).那么 ...

  3. web前端基础知识

    #HTML    什么是HTML,和他ML...    网页可以比作一个装修好了的,可以娶媳妇的房子.    房子分为:毛坯房,精装修    毛坯房的修建: 砖,瓦,水泥,石头,石子....    精 ...

  4. ASP.NET MVC5+EF6+EasyUI 后台管理系统(71)-微信公众平台开发-公众号管理

    系列目录 思维导图 下面我们来看一个思维导图,这样就可以更快了解所需要的功能: 上一节我们利用了一个简单的代码例子,完成了与微信公众号的对话(给公众号发一条信息,并得到回复) 这一节将讲解公众号如何设 ...

  5. JavaScript之链式结构序列化

    一.概述 在JavaScript中,链式模式代码,太多太多,如下: if_else: if(...){ //TODO }else if(...){ //TODO }else{ //TODO } swi ...

  6. android studio 使用 jni 编译 opencv 完整实例 之 图像边缘检测!从此在andrid中自由使用 图像匹配、识别、检测

    目录: 1,过程感慨: 2,运行环境: 3,准备工作: 4,编译 .so 5,遇到的关键问题及其解决方法 6,实现效果截图. (原创:转载声明出处:http://www.cnblogs.com/lin ...

  7. 【知识必备】一文让你搞懂design设计的CoordinatorLayout和AppbarLayout联动,让Design设计更简单~

    一.写在前面 其实博主在之前已经对design包的各个控件都做了博文说明,无奈个人觉得理解不够深入,所以有了这篇更加深入的介绍,希望各位看官拍砖~ 二.从是什么开始 1.首先我们得知道Coordina ...

  8. Django

    一.Django 简介 Django 是一个由 Python 写成的开放源代码的 Web 应用框架.它最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内容为主的网站的,即是 CMS(内容管理系统) ...

  9. SQLServer 各版本区别

    SQLServer 2012 新特性 通过AlwaysOn实现各种高可用级别 通过列存储索引技术实现超快速的查询,其中星型链接查询及相似查询的性能提升幅度可高达100倍,同时支持超快速的全文查询 通过 ...

  10. MySQL,MariaDB:Undo | Redo [转]

    本文是介绍MySQL数据库InnoDB存储引擎重做日志漫游 00 – Undo LogUndo Log 是为了实现事务的原子性,在MySQL数据库InnoDB存储引擎中,还用Undo Log来实现多版 ...