标签: JavaScript

  • NerveNet——俺也开始写框架了!

    感谢姆二,如果不是你,这篇文章和文中的框架可以提前半个月面世。我爱你和你妈。

    本文说明了我设计此框架的意图和实现的方式,框架本身还没写完。

    NerveNet(神经网)是一个JavaScript框架,帮助我们创造命名空间、生成事件总线,并进行依赖注入。未来它还会管理依赖,处理编译输出。

    我给框架命名时从Backbone那里获得了灵感,因为使用Backbone时发现各种欠缺,在逐步修补它们时,这个框架渐渐成形了。我希望,一,它能弥补Backbone欠缺的地方;二,不要依赖Backbone,以便在更多场景中发挥作用。

    (更多…)

  • 也谈提升代码可读性的小技巧

    看完了《编写可维护的JavaScript》,觉得他技巧性的东西讲得太少,还不如看《重构》来得实在。这里分享两个我常用的优化代码的技巧,好学常用。范例代码用的是JavaScript,其实几乎所有语言都用的到。

    逻辑扁平化

    我们工作中,可能会碰到一些比较复杂的逻辑,比如:满足条件1,不然XX;满足条件2,不然XX……如此都满足了才OO,写出来大概是这样:

    if (condition1) {
      if (condition2) {
        if (condition3) {
          // do
          // a
          // lot
        } else {
          // do zz
        }
      } else {
        // do oo
      }
    } else {
      // do xx
    }

    这样带来的结果就是逻辑嵌套后显得很复杂,不好读。如果再赶上缩进没搞好或者换行就更惨了。这个时候,通常可以提前中断代码执行来使得逻辑扁平化。提前中断的方法包括returnthrow,以及PHP中的die()exit()。重新整理后的代码如下:

    if (!condition1) {
      // do xx
      return;
    }
    
    if (!condition2) {
      // do oo
      return;
    }
    
    if (!condition3) {
      // do zz
      return;
    }
    
    // do
    // a
    // lot

    当然,有例外情况要排除的地方也很适用这种方法。甚至有激进的言论,表示不应该使用else,而都要这样提前中断。我觉得那样也有点过分,if ... else ... 的意义还是非常明确的。

    缩短超长逻辑判断

    有个从上古时期传下的不成文的规定,一行代码80个字符。随着显示器变大,这个老规矩应该打破。但是单行代码太长的话左右看起来也会很累,所以我们还是有必要控制。超长的代码经常出现在逻辑判断里,比如游戏中常见的检测子弹有没有打中玩家的代码,用较好的格式写出来大概是这样:

    if (bullet.x > enemy.x + enemy.width || bullet.y > enemy.y + enemy.height || bullet.x + bullet.width < enemy.x || bullet.y + bullet.width < enemy.y) {
      console.log('没打中');
    }

    这就已经不短了。有些时候我们还要加上enemy.damagable、!enemy.immunePhysical之类的其它条件判断,把这一行写的特别长。这个时候就需要我们用点小技巧将它缩短了。方法可能有多种,思路是一致的,就是提炼“目的”——将某一组判断的目的提炼成一个变量,既好读又能缩短代码。接下来还是用一段代码来说明吧:

    var isGod = !enemy.damagable || eneymy.immunePhysical, // 判断敌人是否不能攻击/上帝模式
        isHit = bullet.hitTest(eneymy); // 将刚才那一大串抽出方法“碰撞检测”
    if (!isGod && isHit) {
      enemy.die();
    }

    总结

    这两个小技巧都很简单,但对代码的可读性提高却很显著。各种各种的小技巧叠加起来,会让代码更好读,更容易维护。

  • 书评:《编写可维护的JavaScript》

    书评:《编写可维护的JavaScript》

    编写可维护的JavaScript
    书的封面

    评价:

    3星。如果手头宽裕,或者公司给买就买本看看。如果觉得自己水平欠佳,也推荐学习下。不然就算了。

    其中内容3.5,编辑2.5,综合起来就是3星了。

    适合人群:

    • 缺少规范编程训练的开发者,比如学生
    • 对整个开发环境缺乏了解的新人

    读后感

    很早就关注这本书,当时还只有英文版,前几日看到中文版上线,又是淘宝几个人译的,就赶紧买了,结果看后大失所望。

    最让我失望的是书里印刷错误很多,甚至连!=都能印成!==(第50页),估计道行浅的看到这儿就迷茫了。全书我看得比较细的是前面8章,几乎每章都有错误,实在让人如鲠在喉。

    整书的内容偏浅,讨论的多是差不多的几种方案选择其一,比如空格缩进、4空格2空格、注释要不要有空行之类。其实这种东西绝大多数语言都会涉及到,也没什么好坏之分,团队领导随便选一个就是了。真正对代码质量有较大帮助的是命名空间(第6章)、UI层解耦(第5章)、事件和逻辑接偶(第7章)。读完这几章本以为书会渐入佳境,结果后面都是很浅显的否定浏览器推断的做法,以及介绍使用Ant进行编译,就没什么意思了。

    在我看来,有些内容是不用多说的,比如用浏览器推断某种方法是否存在,提一嘴就行了;有些内容则是初段码农和高阶程序员的分水岭,这才值得大书特书。比如,复杂逻辑的扁平化处理、超长条件分拣成更易读的名字、模式的应用、大型项目的架构、消息机制,等等。可惜这些书里都没有提。至于Ant的介绍,至少我这种半路出家的非Java开发者并不熟悉,倒是直接node.js+grunt用起来挺顺手,而且每家公司的工具使用状况也不一样,是否直接写好几章真的有待商榷。

    我认为,如果自我感觉缺乏系统可靠的编程培训,可以看看这本书。如果想真正提高自己的代码质量,这本书价值不高。

  • 前端框架点评

    前两天被人@,提问前端框架的问题。这还是第一次在微博上被陌生人提问,感觉有点小激动。今天写篇小文章,简单点评一下我用过的前端框架,希望对大家有所帮助。

    本文涉及的范围

    本文要点评的前端框架,都是我用过的,以JavaScript框架为主,也可能包括一些工具类库。由于前端的特殊性,弱语言HTML和CSS是必不可少的工具,运行机制导致很多成熟的工程学方法没法用,必须用工具库补充。烦请大家不要抠字眼,我一向很马虎,呵呵。

    Bootstrap

    一定要先推荐Bootstrap。它由Twitter的两位工程师首创,当前版本2.3.1,涵盖了文本、布局、表单、工具,除了暂时没有日期选择器之外,几乎包含了网页所需的一切。我们知道,网页出现是为了传递信息,而成熟的印刷业对其影响很大,表现出来就是,HTML中很多标签,比如H1~H6p等,都是有具体语义的。但很多前端框架并未给予他们足够的重视,所以往往需要我们重置或者自己动手写。Bootstrap则不是这样。它不仅包含大量组件,还帮助我们给每种可能用到的语义标签都定义了样式,又设计出很多helper;而其网格系统也能帮我们出色完成排版工作。总而言之,使用它几乎足以满足任何网页开发需求。

    值得一提的是,Bootstrap的组件和Widget都基于HTML标签构建,非常好用;而响应用户操作则基于对document的侦听,所以几乎不会对我们其它代码逻辑造成影响,我们可以放心大胆的在项目当中使用。当然,Bootstrap依赖jQuery,后者近期遭遇到一些纷争。不过我还是要强烈推荐这个框架。

    jQuery UI

    比较遗憾的是,虽然号称UI,但jQuery UI只能算作一个组件库。因为缺少基础排版支持,所以既想使用jQuery UI,又想和自己的样式保持一致会有些困难,需要花费不少时间做修改。

    抛开这一点,jQuery UI也是个很好的工具,几个widget都很实用,文档丰富详实,如果项目本身对交互要求不高,只是个别地方需要一些功能补充,jQuery UI确实是不错的选择。尤其当我们需要draggablesortableresizable这几个功能时,选择的余地真的不大。

    HTML5 Boilerplate

    这个工具力图给开发者提供一个舒适的起点。他们为项目建立了标准化的目录结构,并且把常用的资源都整理在合适的位置,这样我们只需要替换它们就能保证项目对所有浏览器都有完美表现。同时,他们重置了CSS,引入了GA统计,在页面中标记了合适的输入点,这样我们能尽快投入到项目逻辑的开发中。

    但这个工具的问题也很明显,它努力达成的目标,是消弭浏览期差异。假如我们只需要统一的环境就能开展工作,那H5B就足够了;而实际上,我们通常需要更多,比如排版、比如组件。所以,这个工具对我来说,学习的意义大于使用的意义。

    HTML KickStart

    我见过的前端框架里只有这个跟Bootstrap的覆盖面接近。它的设计更好,更鲜艳更有活力,不过最近的开发好像慢了下来。我并没有真正使用它,因为它的组件太少了。

    Backbone

    非常好的MV*框架,真的像根脊柱一样,把被jQuery拆的七零八散的js统一在合理的框架内,让整个项目都变得协调了。引入Collection真的很天才,结合其出色的View设计——其实Backbone的View并不是传统意义上的View,更像mediator——可以看出,Backbone的设计者对Web开发有着深刻理解。哦,差点忘了,Router还能帮我们很好的整理单页应用的逻辑。

    不过js毕竟是一门很烂的语言——或者让我换种表述方式,缺陷很多,所以它尚无法做到像AS3的Robotlegs那样好。不过,如果我们希望把代码组织的更好,Backbone类的框架是不可或缺的。

    Rachet

    Rachet的目的和架构,很像Bootstrap,不过它瞄准在移动端。Rachet现在仍处于比较低级的阶段,组件太少,开发起来不太方便,最多相当于Kickstart把。可惜的是,移动端移动框架普遍较弱,在我看来,基于它的Junior仍然是不二之选。

    Zepto

    说到移动端开发就不能不提Zepto。它力图实现一个十分类似jQuery的库,不过只考虑支持移动端,所以体积会小很多,速度也会快不少。Zepto的升级频率最近也不高,不过还是到了1.0。新版Zepto放弃了ruby,使用coffee作为编译工具,支持使用者自由组合功能模块,相当贴心。

    不过具体使用时,还是会有一些函数的用法和jQuery不同,需要注意。举个例子,css函数,jQuery里支持数字,比如$('div').css('height', 100),会把页面中所有div的高度设置为100px;而Zepto不行,必须$('div').css('height', '100px')才会正常工作。

    jQuery Mobile

    强大的jQuery团队最失败的作品。贪恋于风光的过去,迷信“全覆盖”,使得jQuery Mobile步履蹒跚,在移动平台上无法取得足够好的性能表现(早期版本甚至不支持固定底部)。而这直接带来了对HTML在移动端的质疑。有很多本不擅长前端开发的人,看到Phonegap,就直接上jQuery Mobile,结果发现性能不行,体验很差,便在各种渠道大放厥词,说HTML不行。这种行为直接伤害了HTML和Hybrid应用。

    jQuery Mobile失败不仅在于此。jQuery本身方便快捷,使用它很容易养成不重视代码组织的习惯;而在移动端,单页应用占据主流,这意味着,使用jQuery Mobile很可能无法良好的组织代码,直接带来项目维护成本的提高。另外,早期版本的设计也不可避免的带有大量Web痕迹,导致实用性不足。所以直到今天,jQuery Mobile都还是个悲剧。

    不过,jQuery 2.0已经beta2了,我们知道,jQuery 2.0里放弃了对IE678的支持,性能会得到不小的提升;jQuery Mobile 1.3已经引入了对hash的支持,组织代码好多了;同时,随着3次小版本更新,越来越多适用于移动应用的组件加入进来,大大扩充了军备库。我认为,未来的jQuery Mobile,值得一试。

    Sencha Touch

    大家可能还记得,Facebook闹过一阵,说HTML5不够好,还把他们的手机客户端用原生重做了一遍。之后Sencha的两位工程师表示不服,以HTML5为基础开发了功能几乎完全一样的客户端,他们用到的框架就是Sencha Touch。据说,它的性能比jQuery Mobile好不少。

    但是,真正用了就知道,sencha touch实在太不“前端”了。它里面几乎没有给HTML和CSS留下太多位置,明明十分强力的布局样式工具,被封装成了单薄的接口;但是没少往JS框架里加内容。结果就是用起来非常复杂,随时需要看文档;自定义困难,它里面甚至有一个属性叫“html”,用来填入大段文本类型的html;数级嵌套起来的对象也很让人头疼,而且感觉维护也不会太容易。所以我做了一半就还是放弃了。劝大家也别去尝试了。

    如果有哪位高人愿意以实际经验教育我的,我洗耳恭听。

  • 二维码小工具

    这两天利用业余时间,做了个二维码的小工具,用来在页面里插入二维码。这个工具比较方便编辑同学在自己的文章或者专题里添加二维码,推广手机应用,或者手机网站。——要么说第一份工作很重要呢,离开媒体那么多年,想做点独立项目还是跟编辑工作有关。

    工具地址是:http://meatqr.sinaapp.com/

    代码也是完全开放的,采用MIT协议,托管在Github上,地址是:http://meathill.github.com/qrcode.js

    有兴趣的同学试用下吧,记得给我反馈哟,我会不断更新维护的。


  • 原来早期Android的WebView真的很奇葩

    以前没在Android下做过原生HTML开发,所以一直觉得大家的吐槽很莫名其妙——不同于桌面错综复杂的环境,高度统一的webkit内核浏览器能整出什么幺蛾子来?结果这次遇到了,才发现原来早期Android系统的WebView真的很奇葩。

    先是有一块文字,可能比较长,我就在作容器的div上写样式为overflow:scroll,以为这样就能用手指触摸滚动了,拿来小米1S一试,通过。结果后来同事找来,说他的手机不行。研究半天,在StackOverflow上看到Android 3.0之后才开始支持触摸滚动,想在2.x系统上实现还得自己写JS实现。一看他的手机,2.3.5。OK,写JS嘛,好说。

    事先我已经知道触摸事件的触发机制,所以很自然的就去侦听touchstarttouchendtouchmove。结果,不行,滚不起来。我以为自己记错了,去MDN上查了查,没错;又猜是事件用错了,尝试touchleavetouchcancel,也不行;2.x的系统不能装Chrome,测试也不好搞。后来终于通过输出发现,touchmove只触发一次,然后Google之,原来Android设计的机制就是只触发一次,想要自主控制事件结束的时机只能event.preventDefault()。这……难道touchmove不是对应mousemove么?

    只这两点就花了我不少时间,不知道还有没有其它的坑。反正做完这个需求我不禁感慨,早期Android的WebView真的很奇葩啊。

    PS:这篇博文应该早于上一篇,换言之就是这个时候我为了在本地调试打开了“Emulate Touch Events”开关的。

  • 一个诡异问题的排查

    这个问题本身其实不能称之为问题,记下来只是我觉得排查经历挺典型的,值得分享。

    先说下我的环境:MacOS 10.8.2 + Chrome 23.x + Bootstrap 2.2.1 + jQuery 1.8.2。事情是这样的,我本来在开发一个新功能,顺便把老页面重构一下,貌似一切正常。重构完毕后,我想随手测试一下重构后的页面,发现下拉菜单竟然不能点击了,或者说,点击完全失效了。

    这让我很恐慌,因为类似的重构过程我近段时间来做的不是一次两次,这次我应该没有任何冒险的改动才是。这种情况下出现的Bug,一般都很棘手。于是,我打开以前的某个页面——同样经历了重构,但是通过了测试,并且在一顿时间的使用中完全没有问题——发现里面的下拉菜单同样点击失效了。于是,真正的排查开始了。

    (更多…)

  • INFINITE会阻碍JavaScript数组排序

    如题。代码就是最简单的,一个装满对象的数组根据某个值排序:

    sortArray.sort(function (a, b) {
      return a[key] - b[key];
    });

    开始某些对象的值是NaN,我试了下,排序正常,结果稳定,就没再管。

    今天突然发现排序失败,没有报错,查了半天不见异常,只好下手排查一切可能因素。第一个就是INFINITE,翻找MDN无果,想办法过滤掉,排序正常。

    想来负无穷也会影响,所以先判断除数不能为0 还是很有必要的啊。

  • 使用免费CDN加速JavaScript的加载

    做前端的,基本都会用上各种开源的框架、类库。在项目中引用它们,就可能需要把用到的文件纳入版本库,这样每次类库更新,我们也得跟着更新文件,比较麻烦。而且,我们知道,浏览器对同一个域名下的资源同时加载的数量是有限制的,加载页面时光类库的CSS和JS就得搞半天,整体速度也会被拖累。

    好在很多仁人志士已经提供免费的CDN分流服务,帮助我们托管类库。我用到的主要有这些:

    jQuery

    jQuery流行度毋庸置疑,所以微软和Google都提供了jQuery系列,包括UI和Mobile的CDN,Google的CDN还包括一些其它类库,比如prototype和Mootools等。

    微软:http://www.asp.net/ajaxlibrary/cdn.ashx#jQuery_Releases_on_the_CDN_0

    Google:https://developers.google.com/speed/libraries/devguide

    Bootstrap

    Bootstrap是由来自twitter的两名“Nerd”工程师创建的前端框架,非常棒,刚好覆盖了网站页面所需,组合使用无往不利。BootstrapCDN为我们提供了相应的服务:

    http://www.bootstrapcdn.com/

    Underscore和Backbone

    cdnjs.com 这种业界良心提供了最丰富的CDN资源,还包括了每种类库的官网或者其在github上的链接(好吧,很多时候他们就是一回事儿),我觉得甚至可以把这个站点当成学习的出发点。肉大师项目中用到的Underscore和Backbone就取自这里,感谢他们。

    值得一提的是他们的域名也很好记~

  • JS加分号的理由

    JS加分号的理由

    JavaScript界关于是否应该加分号的争论由来已久。在我看来,这就跟《格利佛游记》中“大头党”、“小头党”一样,纯粹蛋疼,一群衣食无忧的达人,领着一群不明所以的小白战来战去。

    吐槽时间结束。我本来对于分号不是很在意,一般每行都加,函数和条件后面不加。后来学会了“模块化”的写法——即每个逻辑用一个立即执行函数——(function () { // 逻辑主体 })()包裹,就开始混用。一直没遇到什么问题,直到今天是 Ant + Closure Compiler 编译部署肉大师,莫名其妙的挂掉了。排查半天发现是分号的问题。

    原来的代码可能是这个样子:

    // 模块1
    // 前面有若干代码
    var Manager = {
      prop: '',
      method: function () {
    
      }
    }
    
    // 模块2,开头是个立即执行函数
    (function () {
      // 代码
    })()<
    

    经过压缩后变成这个样子:

    // }}(function 那里,会被当成一个函数来执行,于是整体的解析就会出错了
    var Manager = {prop: '',method: function () { // code }}(function () {// 代码})()
    

    这时只要给每个文件的末尾加上分号,就解决了。还有种做法,就是在开头加上分号,很多开源代码也是这样做的:

    ;(function () {
      // code
    })()
    

    如此,便给JavaScript代码写分号添了一个理由。