惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Vercel News
Vercel News
N
Netflix TechBlog - Medium
C
Check Point Blog
MyScale Blog
MyScale Blog
The GitHub Blog
The GitHub Blog
Blog — PlanetScale
Blog — PlanetScale
B
Blog RSS Feed
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
WordPress大学
WordPress大学
博客园 - Franky
MongoDB | Blog
MongoDB | Blog
I
InfoQ
Hugging Face - Blog
Hugging Face - Blog
Recent Announcements
Recent Announcements
人人都是产品经理
人人都是产品经理
腾讯CDC
V
Visual Studio Blog
Engineering at Meta
Engineering at Meta
T
The Blog of Author Tim Ferriss
V
V2EX
云风的 BLOG
云风的 BLOG
Microsoft Azure Blog
Microsoft Azure Blog
U
Unit 42
B
Blog

张鑫旭-鑫空间-鑫生活

1分钟速度了解text-align match-parent声明 « 张鑫旭-鑫空间-鑫生活 光标的形状也能设置了,就是CSS caret-shape属性 « 张鑫旭-鑫空间-鑫生活 pretext与文字四面环绕效果的实现 « 张鑫旭-鑫空间-鑫生活 JSON.rawJSON方法的作用是什么? « 张鑫旭-鑫空间-鑫生活 如何使用CSS判断鼠标从哪个方向进入元素? « 张鑫旭-鑫空间-鑫生活 借助mediabunny纯JS实现视频水印、剪裁、合成等功能 « 张鑫旭-鑫空间-鑫生活 务必谨慎使用JS WeakRef弱引用 « 张鑫旭-鑫空间-鑫生活 CSS六边形头像的实现与蜂巢布局 « 张鑫旭-鑫空间-鑫生活 CSS corner-shape与背景底纹技术 « 张鑫旭-鑫空间-鑫生活 浅学WebTransport API:下一代Web双向通信技术 « 张鑫旭-鑫空间-鑫生活 HTML dialog元素新支持了closedBy属性 « 张鑫旭-鑫空间-鑫生活 HTML interestfor属性与悬停popover交互效果 « 张鑫旭-鑫空间-鑫生活 CSS3模拟window7炫酷界面效果展示 « 张鑫旭-鑫空间-鑫生活 图片旋转+剪裁js插件(兼容各浏览器) « 张鑫旭-鑫空间-鑫生活 纯js无图片无外链CSS图片幻灯片播放插件 « 张鑫旭-鑫空间-鑫生活 CSS border三角、圆角图形生成技术简介 « 张鑫旭-鑫空间-鑫生活 CSS “渐进增强”在web制作中常见应用举例 « 张鑫旭-鑫空间-鑫生活 让IE6/IE7/IE8浏览器支持CSS3属性 « 张鑫旭-鑫空间-鑫生活 jQuery – 高亮动态显示页面HTML代码插件 « 张鑫旭-鑫空间-鑫生活 翻译 – 逐渐消失的Flash网站 « 张鑫旭-鑫空间-鑫生活 CSS reset的重新审视 – 避免样式重置 « 张鑫旭-鑫空间-鑫生活 新浪微博插入话题后部分文字选中的js实现 « 张鑫旭-鑫空间-鑫生活 JavaScript实现http地址自动检测并添加URL链接 « 张鑫旭-鑫空间-鑫生活 CSS实现兼容性的渐变背景(gradient)效果 « 张鑫旭-鑫空间-鑫生活 CSS content内容生成技术以及应用 « 张鑫旭-鑫空间-鑫生活 CSS gradient渐变之webkit核心浏览器下的使用 « 张鑫旭-鑫空间-鑫生活 CSS渐变之CSS3 gradient在Firefox3.6下的使用 « 张鑫旭-鑫空间-鑫生活 区分IE8/IE7/IE6及其他浏览器-CSS “\9″hack « 张鑫旭-鑫空间-鑫生活 CSS实现跨浏览器兼容性的盒阴影效果 « 张鑫旭-鑫空间-鑫生活 CSS3&HTML5各浏览器支持情况一览表 « 张鑫旭-鑫空间-鑫生活
关于一个JS功能实现的思维方式 « 张鑫旭-鑫空间-鑫生活
张鑫旭,zhangxinxu · 2011-10-26 · via 张鑫旭-鑫空间-鑫生活

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

一、关于功能情境

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

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

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

二、现实世界的映射

我们习惯于将现实世界的思维方式映射到程序逻辑的实现中,这是很正常。我们很自然会想到如下的逻辑处理(大家一般都熟悉的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其实还是比较菜的,文中有什么表述不准确的地方欢迎指正。感谢阅读。

本文为原创文章,转载请注明来自张鑫旭-鑫空间-鑫生活[http://www.zhangxinxu.com]
本文地址:http://www.zhangxinxu.com/wordpress/?p=1997

(本篇完)