2

关于一个JS功能实现的思维方式

 3 years ago
source link: https://www.zhangxinxu.com/wordpress/2011/10/js%e7%ae%97%e6%b3%95%e4%b8%8e%e6%80%9d%e7%bb%b4%e6%96%b9%e5%bc%8f/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

by zhangxinxu from http://www.zhangxinxu.com
本文地址:http://www.zhangxinxu.com/wordpress/?p=1997

一、关于功能情境

先来简单的,页面上一个“兑换礼品”的按钮,这个按钮上有如下些逻辑判断:

1. 用户是否已经登录,如果没有登录,则弹出登录框,让其执行登录操作(无刷新),登录成功后执行2;否则直接执行2.
2. 如果用户已经登录或登录成功,弹出选择礼品数目的弹框,让用户进行数目设置。

2011-10-26_212300.png

上面的逻辑功能该如何实现?

二、现实世界的映射

我们习惯于将现实世界的思维方式映射到程序逻辑的实现中,这是很正常。我们很自然会想到如下的逻辑处理(大家一般都熟悉的jQuery的写法,下同):

var funDLogin = function(callback) { /* ... */},
    funDoNumberChange = function() { /* ... */ };
    
button.click(function() {
    if (isLogin) {
        //如果登录,弹框
        funDoNumberChange();
    } else {
        //如果非登录,执行登录弹框,成功后执行数目设置弹框
        doLogin(function() {
            //登录成功的回调
            funDoNumberChange();
        });    
    }
});

现实生活的经验告诉我们,尽量不要走重复的路程,不要做重复的事情,尽量避免从头再来,因为这意味着你付出的辛劳(某种意义上)都白费了。

举简单的例子,我们要去美国,结果兴冲冲赶到机场,发现签证没带,我想谁都不愿理再重新赶回去拿签证。
再举个例子,我们玩网游,比如魔兽,辛辛苦苦打了几个月,好不容易升了几十级,结果号被人盗了,你要重头开始练级,估计是谁都会气得吐血三升而亡的。

上面两个例子可能与主题还不够贴切,再举两个例子吧:
不知大家走迷宫的游戏,如果我们走一条路发现不通,怎么半?是退出到之前一个岔路口重新走呢?还是从起点重新走呢?
美女茜茜认识了个男生,如果这个男生很有钱,茜茜会跟他结婚;如果这个男的现在还是很寒酸,则茜茜可以等两年这个男的有钱了再和他结婚。结果两年后,这个男的果然有钱了,你说茜茜是跟他直接结婚呢,还是要重新认识?

很明显的,按照我们正常的生活经验的思维:迷宫不应该出错了就从头开始走,男的达到女方要求可以直接结婚,而没必要从头开始再走恋爱,熟悉之类的流程了。

在现实世界中,我们的时间总是很宝贵,很有限的,于是,往往总是避免“重头再来”这样子的事情发生(节省时间)。

于是,难免的,我们将这种现实世界的认识映射到程序代码中(如上面代码的逻辑)。这看似OK,例如在随机的N次点击事件中,上面的逻辑所消耗的总时间是最小的,而且看上去也不复杂。但是,如果情况再复杂点……

三、复杂的功能情境

还是那个“兑换礼品”的按钮,现在关联逻辑和判断多了点:

1. 用户是否已经登录,如果没有登录,则弹出登录框,让其执行登录操作(无刷新),登录成功后执行2;否则直接执行2.
2. 如果用户已经登录或登录成功,判断用户是否已经绑定手机,如果用户已经绑定手机,执行3;否则,弹出绑定手机的弹框,有一些绑定的Ajax操作,绑定成功后执行3;
3. 如果用户已经是登录状态,同时手机已经绑定,弹出选择礼品数目的弹框,让用户进行数目设置。

复杂点的逻辑 张鑫旭-鑫空间-鑫生活

如果我们还是完全按照现实世界的经验去处理上面的功能,则就会是下面这个样子:

var funDoLogin = function(callback) { /* ... */ },
    funDoBind = function(callback) { /* ... */ },
    funDoNumberChange = function() { /* ... */ };

button.click(function() {
    if (isLogin) {
        //如果已经登录
        if (isBind) {
          //如果已经绑定
          //则打开数目修改弹框
         funDoNumberChange();
        } else {
            //如果未绑定
            //打开绑定弹框
            funDoBind(function() {
                //绑定成功的回调
                funDoNumberChange();
            });
        }
    } else {
        //如果未登陆,打开登录弹框
        funDoLogin(function() {
            if (isBind) {
              //如果已经绑定
              //则打开数目修改弹框
             funDoNumberChange();
            } else {
                //如果未绑定
                //打开绑定弹框
                funDoBind(function() {
                    //绑定成功的回调
                    funDoNumberChange();
                });
            }
        });
    }
});

代码的逻辑判断结果出现了几个级别的增加。上面的代码虽然看上去有些啰嗦,但是,基本上每种情况都有一条路可以走到底,很符合我们现实世界的处理,想好出现的各种可能的情况,当问题出现的时候总能从容应对。

好吧,我想不用我说,你也会对上面裹脚布式的code有些意见的——代码冗余啰嗦。现实世界的经验有时候反映在我们程序上就不适合。

四、时间换空间

现实世界我们往往是用空间换时间。但是,在程序的世界里,时间是廉价的,用时间换空间的做法往往更合适。

到底怎么个时间换空间法呢?

很简单,“重头再来”, 具体点就是,碰到什么问题了,解决之,然后从头再来(有别于躲避之,走其他路)。

一有问题就从头再来不是很浪费时间吗?确实,时间损耗要多些,但是,对于目前的计算机而言,你一个眨眼的功夫,CUP不知奔腾了多少下了。这点时间的损耗,我们基本上可以忽略不计。我们应该把重点放在简单清晰的逻辑处理上。

OK,上面的逻辑处理如果使用“重头再来”的策略,该如何实现呢?如下:

var funDoLogin = function(callback) { /* ... */ },
    funDoBind = function(callback) { /* ... */ },
    funDoNumberChange = function() { /* ... */ };

button.click(function() {
    if (isLogin && isBind) {
        //如果登录同时绑定,打开修改礼品数目弹框
        funDoNumberChange();
    } else {
        if (!isLogin) {
            //如果没有登录,打开登录弹框
            funDoLogin(function() {
                //登录后重新触发点击事件
                button.trigger("click");	
            });
        } else if (!isBind) {
            //如果没有绑定,打开绑定弹框
                funDoBind(function() {
                //绑定后重新触发点击事件
                button.trigger("click");
            });
        }
    }
});

上面代码红色高亮注释的部分就是“重头再来”的执行部分。我们浪费了点微不足道的时间,换去了更简单易懂的代码空间。显然,比牺牲空间的做法要划算多了。

五、末了点唠叨

其实时间换空间的做法不仅是在JS中,其他语言也是如此。其实本文内容属于程序算法的一些基础东西,随便卖弄,凑个文章数。已经几个星期没有更新了,因为最近手上有紧急的项目,关键问题是设计的匆忙导致开发的时候出现很多折腾的问题,最近又要折腾手机版的开发。

末了的随意唠叨,见谅。我JS其实还是比较菜的,文中有什么表述不准确的地方欢迎指正。感谢阅读。

(本篇完)1f44d.svg 是不是学到了很多?可以分享到微信
1f44a.svg 有话要说?点击这里


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK