小叉试验场 http://ciaoca.com 小叉的个人网站,小叉的博客,记录小叉的生活宅事。此地亦是小叉练习技术的地方,不求SEO,不求流量,不求兼容IE6。 zh-cn 2014年05月18日 2014年05月18日 ciaoca@126.com you@youremail.com 教你怎么把图标字体(IconFont)转为 PNG http://ciaoca.com/diary?id=239   使用图标字体非常方便,不过总有些时候需要用图片,或者是只用极少数的图标,又或者为了兼容性,而又想要使用某个图标字体的图标。看到有各种 Python、PHP脚本转换的,对于偏向设计或者系统没有环境配置的同学来说实在麻烦。

  在这里教个简单的方法:

  1. 下载你所需要的图标字体,然后安装(复制到 C:\Windows\Fonts\);

  2. 打开 PS,选文字工具,选择到刚才安装的图标字体;

  3. 输入图标字符,图标就出来了,随时可以在 PS 中更改字体大小。


不知道图标的字符是什么怎么办?

直接从页面上复制,粘贴到 PS 即可。

例如 Font Awesome 的速记表:http://fortawesome.github.io/Font-Awesome/cheatsheet/,直接复制图标

]]>
2014年05月18日 代码日记
程序员的心理疾病 http://ciaoca.com/diary?id=238   说实话,虽然似乎为之奋斗了十多年,在真正进入软件行业的短短一年之后,我已经对它感到相当的厌倦了。这并不是说这个行业没有前景,而是在这个行业工作,其实很难得到心理上的快乐。


  人们说女怕嫁错郎,男怕入错行。我并不认为自己入错了行,我仍然很喜欢设计自己的程序和语言,而且我显然是这个领域的王牌之一。然而我却看到了这个行业里的无限混沌,让我觉得喘不过气来。几十年的垃圾设计堆积在那里,却没有人试图把它们清理掉,权威主义盛行。无论你在哪个公司,哪个地方,只要跟程序员说话,十有八九会谈不来。非常扫兴不说,甚至感觉很伤自尊。


  久而久之我发现了,由于程序员工作的性质,他们长期以来受到的“黑客”式的“熏陶”,形成了一种行业性的心理疾病。这里我就简单的把我所观察到的一些症状总结一下。


无自知之明

  由于程序员的工作最近几年比较容易找,工资还不错,所以很多程序员往往只看到自己的肚脐眼,看不到自己在整个社会里的位置其实并不是那么的关键和重要。很多程序员除了自己会的那点东西,几乎对其它领域和事情完全不感兴趣,看不起其他人。这就是为什么我的前同事 TJ 作为一个资深的天体物理学家,在一个软件公司里面那么卑微。貌似会写点 node.js,iOS 软件的人都可以对他趾高气昂的样子,而其实这些东西的价值哪里可能跟 TJ 知道的物理知识相提并论。很多科学家其实都 可以轻而易举的掌握程序员知道的东西,有人却认定了他们不是这个专业的,不懂我们的东西,或者故意把问题搞复杂,让他们弄不明白。让人感觉是在阴沟里翻了船被老鼠欺负。


  如果力学工程师犯了错误,飞机会坠毁;如果结构工程师犯了错误,大桥会垮塌;可是如果软件工程师犯了错误,大不了网站挂掉一小时,重启一下貌似又好了。所以所谓“软件工程师”,由于门槛太低,他们的工作严谨程度,其实是根本没法和力学工程,结构工程等真正的工程师相提并论的。实际上“软件工程”这个名词根本就是扯淡的,软件工程师也根本不能被叫做“工程师”。跟其他的工程不一样,软件工程并不是建立在科学的基础上的,计算机科学也根本不是科学。


垃圾当宝贝

  按照 Dijkstra 的说法,“软件工程”是穷途末路的领域,因为它的目标是:如果我不会写程序的话,怎么样才能写出程序?


  为了达到这个愚蠢的目的,很多人开始兜售各种像减肥药一样的东西。面向对象方法,软件“重用”,设计模式,关系式数据库,NoSQL,大数据…… 没完没了。只要是有钱人发布的东西,神马垃圾都能被吹捧上天。Facebook 给 PHP 做了个编译器,可以编译成 C++,还做了个 VM,多么了不起啊!其实那种东西就是我们在 Indiana 第一堂课就写过的,只不过我们是把比 PHP 好很多的语言翻译成 C。我们根本不想给 PHP 那么垃圾的语言做什么编译器,让垃圾继续存活下去并不能证明我们的价值。


  其实软件里面有少数永恒的珍宝,可惜很少有人理解和尊重它们的价值。这在其它的工程领域看来是不可思议的,然而这却是事实。由于没有科学作为理论的基础,没有实验作为检验它们的标准,软件行业的很多东西就像现代艺术一样,丑陋无比的垃圾还能摆在外表堂皇的“现代艺术博物馆”里面,被人当成传世大作一样膜拜。


  为了凸显自己根本不存在的价值,又提出一些新的“理念”,就像有些现代艺术家一样,说“艺术的目的不是为了美,而是为了自由。”哦,这就是为什么你们可以自由地把那些让人反胃的东西放在博物馆里,还要买门票才能参观?


宗教斗争

  当然了因为没有实质的技术,为了争夺市场和利益,各种软件的理念就开始互相倾轧。一会儿说软件危机啦,面向对象方法来拯救你们!一会儿又提出设计模式。过了一会儿又有人说这些设计模式里面有些模式是“反模式”,然后又有人把函数式编程包装起来,说是面向对象编程的克星,一会儿是关系式数据库,一会儿是 NoSQL,一会儿是 web,一会儿是 cloud,一会儿又是 mobile…… 每个东西都喜欢把自己说成是未来的希望。


  这就是为什么有人说在软件行业里需要不停地“学习”,因为不断地有人为了制造新的理念而制造新的理念。在这样一个行业里,你会很难找到一个只把程序语言或者技术当成是工具的人。如果有人问你对某个语言或者技术的评价,是非常尴尬甚至危险的事情,所以最可靠的办法就是不做评论,什么都不要说。


引难为豪

  在 IT 行业里批评一个技术难用,是一件非常容易伤自尊的事情,因为立马会有人噼里啪啦打出一些稀奇古怪的命令或者一大篇代码,说:就是这么简单!然后你就发现,这些人完全不明白什么叫做设计,他们以自己能用最快的速度绕过各种前人的设计失误为豪,很多程序员甚至以自己打字快为豪。


  当遇到这样的人,我的经验是,千万不要恭维他们。你必须大声地嘲笑这些东西的设计,并且指出它们的失误之处,否则你不但助长了这些人的气焰,而且将来自己的自尊也难保了。很可惜的是不是每个人都有这种勇气把这些话说出来,这就造成了今天的局面,纷繁复杂的垃圾充斥着世界。爱因斯坦说,你需要很多的天才和非常大的勇气,才能追求到简单。


  非常大的勇气…… 也许就是这个意思。


去读文档!

  不知从什么时候开始,人们开始引用 Eric Raymond 的一篇叫做《提问的艺术》的文章,这篇文章后来就成为了对提问者没礼貌的借口。由于这篇文章的误导,当你希望同事能给你一个手把手的演示的时候,他们往往会丢给你一篇不知道什么时候写的文档,让你自己去读,仿佛文档就可以代替人之间的直接互动。况且不说这文档可能已经过时,里面有很多地方已经不符合最新的设计,而这意味着在潜意识里,他们觉得高你一等。他们甚至会对你说,如果每个新人来了我们都花这么多时间去指导他们入门,哪里还有时间干正事呢?然后你就意识到了,你在他们心里的地位,其实是如此的卑微和低下。


  有的人稍微委婉一点,当你提问的时候,他们会二话不说打开一个浏览器窗口,在里面用 Google 搜索,然后指给你:看,就是这样。貌似比较礼貌,但那其实意味着他们在教训你:Google 一下就找到了的,自己不动脑筋!有谁不会用 Google 呢?提问的人恐怕是想得到 Google 不能给他的答案。真正有礼貌的人在不知道答案的时候是不会当面去帮你搜索的,他会对你说:“这个我也不知道…… 要不你搜索一下?”


  在 IRC 的聊天室里,由于隔着网络的屏障,这种对提问者没礼貌的现象就更加嚣张。我曾经有几次去 Java 的聊天室问一些貌似基础,而其实很深入的语言设计问题,结果没有一次不是以收到像“去读 API!”这样的回答而结束。API 谁不会读,然而我需要的是一个有血有肉的人对此的理解。所以后来我根本不去 IRC 这种地方了,因为那里面对你打字的基本上已经不是人类了。他们觉得你问问题浪费了他们的时间,好像他们一天到晚泡在 IRC 里面就是在做什么正事似的。不想回答问题,不开口还不行吗。后来你发现,原来在 IRC 里面训斥新手就是这些人唯一的乐趣,所以其实他们是非开口说话不可的。然而这次他们遇到的却不是个新手,而是一个可以把 Java 整个造出来的人。


  像 Haskell 之类的聊天室貌似稍微友好一点,然而后来你发现他们显得友好是有所企图的。因为当时 Haskell 还没有很多人用,他们需要吸引新手,所以竭尽所能的诱导他们。而一旦它用户稍微多了一点,有声势了,那些积极分子就成了专家一样的人物。他们就开始写书,然后就开始牛气哄哄的了。然后你就会发现当对 Haskell 的设计提出异议的时候,这些“id”们是多么的不友好,有理也说不清。所以最后你发现,其实所有语言的所谓“社区”都一个德行。如果 Haskell 有一天像 Java 一样如日中天(当然不大可能),肯定对大部分问题的答案也就是“去读API!”其实它已经在向这一步发展了。


  不得不指出,《提问的艺术》等介绍“黑客文化”的文章对于这种现象的出现有着极大的责任。说穿了,写这些文章的人一般都是 Unix 的跟屁虫。这种文章试图抹去人类文明几千年来传承的文化,而重新给“礼貌”做出定义。其结果是,人类的文明因为这些文章,在程序员的世界里倒退了几十甚至几百年。很多外行人人不喜欢跟程序员说话,叫他们是 nerd,就是这个原因。


不要提问,不要谦虚,不要恭维

  跟上面的症状相似,程序员世界里的一条重要的潜规则是:只有菜鸟才会问问题。所以如果你有任何机会可以自己得到答案,就不要试图向人“请教”,尤其不要显得好奇,否则你就会被认为是菜鸟。我有几次不耻下问的经历,最后导致了我被人当成菜鸟。我只是觉得那问题有趣,也许能够启发我设计自己的东西,所以吃饭时觉得是个话题可以说一下,结果呢就有人忙着鄙视你,那么小的问题都没搞清楚。正确的态度应该是诚实,直接,见惯不惊,那有什么大不了的,我什么没见过,我很怀疑。


  随之而来的引论就是:不要谦虚!那些“职场经验”之类的文章告诉你的进入新的公司工作,要谦虚好问,对 IT 公司这种不讲美德的地方是不管用的。有的大 IT 公司有所谓的“文化”,比如叫你要“Googley”,要“humble”,其实只是用来贬低你价值的借口。他们要你向他们“学习”,但其实他们没有什么值得学习的地方。他们只是想让你安于“本分”,做一些微不足道,不能发挥你才能的工作。看看那些叫你要 humble 的人,他们 humble 吗?所以跟江湖一样,在 IT 公司里面一件很重要的事情是,亮出自己的宝剑和绝招,给人下马威。介绍自己的东西一定要自豪,这就是世界上最好的,无敌的,没有其他人能做到!不能有任何保留。不要像科学家一样介绍自己技术的局限性,否则随之而来的就是有些人对你价值的怀疑和对你自信心的打击。


  另外要注意的是对于别人介绍的东西,不要轻易地表扬或者点头,否则有人就更有气势了。你要问这样的问题:这里面有什么新的东西吗?这个事情,另外一种技术早就能做了啊,没觉得有什么了不起。


  哎,总之这样还是很累,所以最好是能不跟程序员讲话就不讲。


以语言取人

  你的软件是什么语言写的,告诉别人的时候是千万要小心的,不到万不得已最好不要说。因为十有八九,对方会立即在心里对你的软件的价值做出判断,光凭你用的是什么语言。


  很多程序员都以自己会用最近流行的一些新语言为豪,以为有了它们自己就成了更好的程序员。他们看不到,用新的语言并不能让他们成为更好的程序员。其实最厉害的程序员无论用什么语言都能写出很好的代码。在他们的头脑里其实只有一种很简单的语言,他们首先用这种语言把问题建模出来,然后根据实际需要“翻译”成最后的代码。这种在头脑里的建模过程的价值,是很难用他最后用语言的优劣来衡量的。有时候高明的程序员用一个语言并不是因为他只会用那种语言,而是其他的原因。他们的头脑里有着万变不离其宗的理念,可以让他们立即掌握几乎任何语言或者工具,所以他们对所谓的“新语言”都不以为然。可是很多人误以为他们不愿意学习“新东西”,从而从心里鄙视他们。其实计算机的世界里哪里有很多新的东西,只不过是有人给同样的东西起了很多不同的名字而已。如果连这样的程序员都不能理解你的技术,就说明你的技术设计有问题,而不是他们有问题。就像 Seymour Cray 说的,我只能理解简单的东西,如果它太复杂了,我是不能理解的。


  早些年的时候,大家都认为招募某种特定语言的程序员是一种浮浅的做法,很多公司看重的都是解决问题的能力。可是近些年我发现这些浮浅的做法越来越普遍。可以说现在像 Google 这样的公司面试员工的方式和态度,其实还不如八年前我的第一份国内工作。很可笑的是,我离开 Coverity 之后那段时间面试的所有声称使用 Python 的公司,最后都认定了我是 Python 的菜鸟。然而如果你知道 PySonar 的技术含量就会明白,这样的东西需要水平高过 Python 的创造者 Guido van Rossum 很多的人才能造出来。在制造了 PySonar 之后,他对程序语言的理解,他的每一个错误都被我看得清清楚楚。当然,Ruby 就更烂了,我可以说,Matz 这人其实根本不知道他在干什么。


  说到这些的时候,我很惊讶的发现有人来信告诉我,还是等你做出了什么“成就”再来说这些话吧。从这里我看到了“竞争”和“攀比”的思想在有些人心里是多么的根深蒂固,我也看出了这些“大牛”在他们心里是个什么地位。然而他们是激将不到我的,因为我根本没有跟别人“比”的意思。说实话吧,就算你打死我,我也做不出有那么多毛病的语言来。我不可能以“超过 Python 和 Ruby”这么肤浅的目的为动机,来达到别人所认同的“成就”。打个比方,我有什么必要证明我比 Justin Bieber 或者 Lady Gaga 强呢?我根本不使用他们的东西,不明白这些人到底有什么成就,也完全没有必要向他们的粉丝证明我的价值。在这几次有伤自尊的面试之后,我再也不会给任何使用 Python 作为主要语言的公司工作。


跟屁虫

  有些程序员对新手和同事是那么的不友好,然而对大牛们拍马屁的功夫可真是出类拔萃。我刚到旧金山的几个月有时候参加一些程序语言的“meetup”,后来我发现这种 meetup 都是宗教气氛非常浓厚的地方,跟传销大会差不多。Scala 的 meetup 里面的人几乎全都对 Scala 和 Martin Odersky 顶礼膜拜,甚至把 Rod Johnson 请来扯淡。Clojure 的,当然基本上把 Rich Hickey 当成神,甚至称他为“二十一世纪最重要的思想家之一”。各种 talk 总是宣扬,哇,我们用 Scala/Clojure 做出了多么了不起的东西云云,其实只不过是在向你兜售减肥药。


  很多人喜欢做这些新的语言和技术的“evangelist”,尽显各种马屁神功,然后就开始写书,写 blog,…… 目的就是成为这个“领域”的第一批专家。这就难怪了,再垃圾的语言也有一大批人来鼓吹。因为这些没真本事的人,随便把一个东西捧上天都有自己的好处。


  由于受到这些“先知”的影响,有些人开始在他们自己的公司里“布道”。比如有人在 Python 的 meetup 集会时告诉我,他试图在自己的小组里推 Python,可是一些老顽固一定要用 Java,认为 Java 才是王道。很鄙夷不高兴的样子。我并不认为 Java 是很好的语言,然而 Python 也好不到哪去。它们在我眼里只不过是临时拿来用一下的工具,可是我仍然能用它们写出一流的代码。


  看到这些宗教性质的聚会,我终于理解了一些地区是如何被从一个国家分裂出去,最后沦落为另外一个国家殖民地的。最早的时候,一般是派传教士过去“传经”,然后就煽动一小部分人起来造反。到后来就可以名正言顺的以“保护传教士”,“保护宗教自由”,“维持和平”等理由把军舰开到别人家门口……

]]>
2014年02月18日 科普日记
判断 DOM 对象、jQuery 对象以及 Zepto 对象 http://ciaoca.com/diary?id=236   方法本来非常简单,直到今天我遇到了判断 Zepto 对象失败之后,我才决定这事得记一下。

  判断一个对象是否属于某个对象,我们都是使用 instanceof 运算符,例如判断一个对象是否是 DOM 对象:

var dom=document.getElementById("box")
console.log(dom instanceof HTMLElement);    // =>true,如果页面中没有 id=box 的元素,则会返回 false

  在 DOM 标准中,每个 HTML 元素都是继承自 HTMLElement。当提到标准时,往往都会提到 IE,没错,在 IE9 之前,都是没有 HTMLElement 对象的。这时,我们得使用另外一个属性 nodeType 来判断。

var dom=document.getElementById("box")
console.log(dom && dom.nodeType && dom.nodeType===1);    // =>true,如果页面中,没有 id=box 的元素,则会返回 null

nodeType 属性返回被选节点的节点类型:

常量名
ELEMENT_NODE1
ATTRIBUTE_NODE2
TEXT_NODE3
CDATA_SECTION_NODE4
ENTITY_REFERENCE_NODE5
ENTITY_NODE6
PROCESSING_INSTRUCTION_NODE7
COMMENT_NODE8
DOCUMENT_NODE9
DOCUMENT_TYPE_NODE10
DOCUMENT_FRAGMENT_NODE11
NOTATION_NODE12

  现在,将这两个方法整合在一起,就完成了判断 DOM 对象的方法:

// 检测是否是 DOM 元素
function isElement(o) {
    if(o && (typeof HTMLElement==="function" || typeof HTMLElement==="object") && o instanceof HTMLElement){
        return true;
    }else{
        return (o && o.nodeType && o.nodeType===1) ? true : false;
    };
};

  加上 typeof 检测引用对象是有必要的,否则不存在的时候将会出现错误。


  接着说检测 jQuery 对象,学会检测 DOM 对象方法后,这事简单得多了,上代码:

// 检测是否是 jquery 对象
function isJquery(o) {
    return (o && o.length && (typeof jQuery==="function" || typeof jQuery==="object") && o instanceof jQuery) ? true : false;
};

  在这里多了对 length 属性的判断,因为 jQuery 选择器返回的是一个数组对象,所以当页面上没有所要选择的元素时,依然属于 jQuery 对象,只是没有 DOM 而已。当然如果你只是需要单纯的判断是不是 jQuery 对象,这可以去掉这一步。


  继续说怎么检测 Zepto 对,你是不是已经想到,是这样的?

// 错误的示例
function isZepto(o) {
    return (o && o.length && (typeof Zepto==="function" || typeof Zepto==="object") && o instanceof Zepto) ? true : false;
};

  万万没想到,这居然是错的,不论怎样都会返回 false,这绝壁是坑。经过查阅,终于发现 Zepto 居然自己有一个方法:$.zepto.isZ。(需要 Zepto v0.8 以上版本支持),于是方法改为:

// 检测是否是 Zepto 对象
function isZepto(o){
    return (o && o.length && (typeof Zepto==="function" || typeof Zepto==="object") && Zepto.zepto.isZ(o)) ? true : false;
};


]]>
2014年01月14日 代码日记
优雅的使用 jQuery Validation Engine 表单验证插件 http://ciaoca.com/diary?id=235   一直都是使用 jQuery Validation Engine 来处理表单验证,其功能及自定义很友好,这次再去看时,发现竟然升级了!

  新版本 2.6.1 中,新增了很多对用户体验很好的东西,下面开摆。


maxErrorsPerField

  在老版本中,如果我们设置验证规则为:validate[required,minSize[6],maxSize[20]],如果什么都没有填,就会出现 3 个提示有木有!如果多个输入框之间的间隔不是很多,会遮住下面的输入框或者提示信息有木有!

  这个参数是我觉得这次更新最有用的参数,设置为 1 时,就不会出现 3 个提示,而只会出现 1 个提示。

$("#formId")..validationEngine({
    maxErrorsPerField: 1    // 参数值为数值
});


showOneMessage

  该参数的功能是,在提交验证时,只会显示第一个输入框的错误,后面的都不会显示,和 maxErrorsPerField 结合使用,超级赞!

$("#formId").validationEngine({
    showOneMessage: true
});


focusFirstField

  使用该参数,在提交验证时,如果没有通过验证规则,那么会让第一个输入框自动获取焦点,用户体验很好,这个参数默认是开启的,所以不需要再次设置。

$("#formId").validationEngine({
    focusFirstField: true
});


autoHidePrompt

autoHideDelay

  自动隐藏提示信息,以及设置延时多久自动隐藏。

$("#formId").validationEngine({
    autoHidePrompt: true
    autoHideDelay: 5000    // 单位毫秒(ms)
});


autoPositionUpdate

  自动调整提示信息。使用后,当窗口大小变化时,会自动调整提示信息的位置,对于不是固定布局的页面很有用。

$("#formId").validationEngine({
    autoPositionUpdate: true
});


addPromptClass

  给提示信息的元素增加样式。在没有这个参数之前,都是直接修改 Validation Engine 自身的样式,或者在表单上手动增加一个样式,再通过后辈选择器来覆盖,有了这个参数,将能更灵活的控制样式。

$("#formId").validationEngine({
    addPromptClass: ""
});


custom_error_messages

  自定义错误信息的内容。当同一个验证方式,在不同的页面要求显示不同的提示信息时,这个参数就能大显身手,例如:注册的同意协议勾选框,要求必选,默认只会提示为必填,而我们需要更准确的提示“请先阅读并同意服务协议”。具体可以参考这个例子

$("#formId").validationEngine({
    custom_error_messages: {
        "#id":{    // 元素的选择器
            "ruleName":{    // 该元素的验证规则名称,如:required、minSize、custom[url]
                "message":""    // 自定义提示的内容
            }
        }
    }
});


addSuccessCssClassToField

addFailureCssClassToField

  当验证通过或不通过时,给元素增加的样式。通过增加样式来让元素更醒目的提示,也是不错的体验。

$("#formId").validationEngine({
    addSuccessCssClassToField: "success"
    addFailureCssClassToField: "failure"
});


data-prompt-positio

  这个参数,可以给提示信息的位置进行细调,当元素周围有内容,不希望被提示信息遮挡时,可以通过该参数来调整,例如:验证码的图片通常都是在输入框的右边,那么可以将提示信息调到验证码图片的右边。

  这个参数不是调用时使用的,是直接写在元素上,

<input class="validate[required]" type="text" data-prompt-position="centerRight:100,0">


]]>
2013年10月16日 代码日记
《编写可维护的 JavaScript》笔记三 http://ciaoca.com/diary?id=233 【第5章 UI层的松耦合】

在 Web 开发中,用户界面(User Interfaoe, UI)是由三个彼此隔离又相互作用的层定义的。

  • HTML 用来定义页面的数据和语义。

  • CSS 用来给页面添加样式,创建视觉特征。

  • JavaScript 用来给页面添加行为,使其更具交互性。


5.1 将 JavaScript 从 CSS 中抽离

避免使用 CSS 表达式(CSS Expression)

※ IE9 不再支持 CSS 表达式


5.2 将 CSS 从JavaScript 中抽离

修改 DOM 元素的 className,而不是修改 DOM 元素的 style

// 原生方法
element.className += "newclass";

// HTML5
element.classList.add("newclass");

// YUI
Y.one(element).addClass("newclass");

// jQuery
$(element).addClass("newclass");

// Dojo
dojo.addClass(element, "newclass");

※ 在重新给元素定位时,可以直接修改 style 的 top、left、bottom、right 属性,因为在 CSS 中无法完成。可以在 CSS 中定义元素的默认属性,而在 JavaScript 中修改这些默认属性。


5.3 将 JavaScript 从 HTML 中抽离

避免使用 on 属性(例如 onclick)来绑定事件处理程序:

// 不好的写法
<button onclick="doSomething()" id="action-btn">Click Me</button>

使用 JavaScript 方法来添加事件处理程序,更好的方法:

function addListener(target, type, handler) {
    if (target.addEventListener) {
        target.addEventListener(target, type, handler);
    } else if (target.attachEvent) {
        target.attachEvent("on" + type, handler);
    } else {
        target["on" + type] = handler;
    }
}

function doSomething(){
    // 代码
}
var btn = document.getElementById("action-btn");
addListener(btn, "click", doSomething);

一些常见类库的方法:

// YUI
Y.one("#action-btn").on("click", doSomething);

// jQuery
$("#action-btn").on("click", doSomething);

// Dojo
var btn = dojo.byId("action-btn");
dojo.connect(btn, "click", doSomething);)


5.4 将 HTML 从 JavaScript 中抽离

方法 1:从服务器加载

将模板放在服务器,通过 Ajax 方法从服务器读取模板。


方法 2:简单客户端模板

通过一些标识,通过 JavaScript 替换内容。


方法 3:复杂客户端模板

使用模板引擎,如:Handlebars(http://handlebarsjs.com)。



【第6章 避免使用全局变量】

在浏览器中, window 对象往往重载并等同于全局对象,因此任何在全局作用域中声明的变量和函数都是 window 对象的属性。

  • 始终使用 var 声明变量

  • 使用命名空间

  • 使用模块


“异步模块定义”(AMD)

AMD 规范:https://github.com/amdjs/amdjs-api/wiki/AMD


零全局变量(匿名函数)

(function(win) {
    var doc = win.document;
    // 在这里定义其他的变量
    // 其他相关代码
})(window);



【第7章 事件处理】

当事件触发时,事件对象(event 对象)会作为回调参数传入事件处理程序中。event 对象包含所有和事件相关的信息,包括事件的宿主(target)以及其他和事件类型相关的数据。

  • 鼠标事件会将其位置信息暴露在 event 对象上;

  • 键盘事件会将按键的信息暴露在 event 对象上;

  • 触屏事件会将触摸位置和持续时间(duration)暴露在 event 对象上。


规则:

  1. 隔离应用逻辑

  2. 不要分发事件对象



【第8章 避免“空比较”】

8.1 检测原始值

检测字符串、数字、布尔值或 undefine,最佳选择是使用 typeof 运算符。

  • 对于字符串,typeof 返回“string”

  • 对于数字,typeof 返回“number”

  • 对于布尔值,typeof 返回“boolean”

  • 对于 undefined,typeof 返回“undefined”


8.2 检测引用值

引用值也称作对象(object)。

在 JavaScript 中除了原始值之外的值都是引用。

内置的引用类型:Object、Array、Date 和 Error。

typeof 运算符在判断这些引用类型时都会返回“object”。

检测某个引用值的类型的最好方法是使用 instanceof 运算符。instanceof 的基本语法是:

value instanceof constructor

// 例子:检测日期
if (value instanceof Date) { // 代码 }

// 例子:检测正则表达式
if (value instanceof RegExp) { // 代码 }

// 例子:检测 Error
if (value instanceof Error) { // 代码 }

instanceof 不仅检测对象的构造器,还检测原型链。默认情况下,每个对象都继承自 Object,因此每个对象的 value instanceof Object 都会返回 true。

※ instanceof 不支持跨 frame


8.2.1 检测函数

检测函数最好的方法是使用 typeof 运算符。

对于函数,typeof 返回“function”。

※ 在 IE 8 及以下的 IE 中,使用 typeof 来检测 DOM 节点(比如:document.getElementById())中的函数都会返回“object”而不是“function”。


8.2.2 检测数组

ECMAScript5 将 Array.isArray() 正式引入 JavaScript。

// 兼容旧浏览器的方法
function isArray(value) {
    if (typeof Array.isArray === "function") {
        return Array.isArray(value);
    } else {
        return Object.prototype.toString.call(value) === "[object Array]";
    }
}

※ IE 9+、Firefox 4+、Safari 5+、Opera 10.5+ 和 Chrome 都实现了 Array.isArray() 方法。


8.3 检测属性

判断属性是否存在的最好的方法是使用 in 运算符。

in 运算符仅仅会简单的判断属性是否存在,而不会去读属性的值。如果对象的属性存在,或者继承自对线的原型,in 运算符都会返回 true。


如果你只想检查实例对象的某个属性是否存在,则使用 hasOwnProperty() 方法。如果实例中存在这个属性则返回 true(如果这属性值存在于原型里,则返回 false)。

※ 在 IE 8 及以下的 IE 中,DOM 对象并非继承自 Object。

]]>
2013年08月30日 读书笔记
《编写可维护的 JavaScript》笔记二 http://ciaoca.com/diary?id=232 【第2章 注释】

2.1 单行注释

  • 独占一行的注释,用来解释下一行代码。这行注释之前总是有一个空行,且缩进层级和下一行代码保持一致。
           

  • 在代码尾部的注释。代码结束到注释之间至少有一个缩进。注释(包括之前的代码部分)不应当超过单行最大字符数限制,如果超过了,就将这条注释放置于当前代码行的上方。

  • 被注释掉的大段代码。

在双斜线之后增加一个空格有助于阅读。


2.2 多行注释

Java 风格:

/*
 * 另一段注释
 * 这段注释包含两行文本
 */

文档注释:

@符号表示一个或多个属性

/**
返回一个对象,这个对象包含被提供对象的所有属性。
更多的介绍……
@method merge
@param {Object} 被合并的一个或多个对象
@return {Object} 一个新的合并后的对象
**/



【第3章 语句和表达式】

所有的块语句都应当使用花括号,包括:

  • if

  • for

  • while

  • do...while...

  • try...catch...finally


3.1 花括号的对齐方式

将左花括号放置在块语句中第一句代码的末尾,比如:

if (condition) {
    doSomething();
} else {
    doSomethingElse();
}

不推荐将左花括号放置于块语句首行的下一行,以免导致错误的分号自动插入。


3.2 块语句间隔

语句名、圆括号和左花括号之间没有间隔。

左圆括号之前和右圆括号之后各添加一个空格。

左圆括号后和右圆括号前各添加一个空格。


3.3 switch 语句

第一种,每条 case 语句相对于 switch 关键字都缩进一个层级。

从第二条 case 语句开始,每条 case 语句前后各有一个空行。

switch(condition) {
    case "first":
        // 代码
        break;

    case "second":
        // 代码
        break;

    case "third":
        // 代码
        break;

    default:
        // 代码
}

另一种,case 关键字保持和 switch 关键字左对齐。

在语句中并没有空行的存在。

switch(condition) {
case "first":
    // 代码
    break;
case "second":
    // 代码
    break;
case "third":
    // 代码
    break;
default:
    // 代码
}

case 语句的“连续执行”应当看起来逻辑清晰或添加注释说明。

没有默认行为是可省略 default ,但最好写上注释表明。


3.4 with 语句

强烈推荐避免使用 with 语句。


3.5 for 循环

传统的 for 循环往往用于遍历数组。


3.6 for-in 循环

for-in 循环是用来遍历对象属性的。



【第4章 变量、函数和运算符】

4.1 变量声明

不论 var 语句是否真正会被执行,所有的 var 语句都提前到包含这段逻辑的函数的顶部执行。

因此,推荐将所有变量声明放在函数顶部而不是散落在各个角落。


4.2 函数声明

和变量声明一样,函数声明也会被 JavaScript 引擎提前。

因此,推荐总是先声明 JavaScript 函数然后再使用函数。

此外,函数声明不应当出现在语句块之内。


4.3 函数调用间隔

在函数名和左括号直接没有空格。这样做是为了将它和块语句区分开来。


4.4 立即调用函数

将函数用一对圆括号包裹起来,这样代码在第一行就有了一个标示符(左圆括号),表明这是一个立即执行的函数。

而不是在函数尾部添加一对圆括号,这样除非读完整段代码看到最后一行的那对圆括号,否则不会知道是将函数赋值给变量还是将函数的执行结果复制给变量。


4.6 相等

推荐总是使用 === 和 !==

在和 null 比较的时候用 ==,因为这时程序编写者往往都是想判断值是否为 null 或 undefined。


4.6.1 eval()

只在解析 JSON 时才使用 eval();

* ECMAScript 5 严格模式对于 eval() 有着严格的显示,禁止在一个封闭的作用域中使用它创建新变量或者函数。这条限制帮助我们避免了 eval() 先天的安全漏洞。


4.6.2 原始包装类型

JavaScript 里有 3 种原始包装类型:String、Boolean、Number。

var name = "Nicholas";
name.author = true;
console.log(name.author); // undefined

在第 2 行结束后,author 属性就不见了。因为表示这个字符串的临时 String 对象在第 2 行执行结束后就销毁了,在第 3 行中又创建了一个新 String 对象。同样你也可以手动创建这些对象:

// 不好的做法
var name = new String("Nicholas");
var author = new Boolean(true);
var count = new Number(10);

尽管我们可以使用这些包装类型,但强烈推荐避免使用它们。

]]>
2013年07月05日 读书笔记
《编写可维护的 JavaScript》笔记一 http://ciaoca.com/diary?id=231 【第1章 基本的格式化】

1.1 缩进层级

制表符 或 空格符(2个空格、4个空格、8个空格)

  • jQuery 核心风格指南(jQuery Core Style Guide)明确规定使用制表符缩进。

  • Dauglas Crockford 的 JavaScript 代码规范(Douglas Crockford's Code Conventions for the JavaScript Programming Language)规定使用4个空格字符的缩进。

  • SproutCore 风格指南(CproutCore Style Guide)规定使用2个空格的缩进。

  • Google 的 JavaScript 风格指南(Google JavaScript Style Guide)规定使用2个空格的缩进。          

  • Dojo 变成风格指南(Dojo Style Guide)规定使用制表符缩进。            


1.2 语句结尾

推荐不要省略分号


1.3 行的长度

将行的长度限定在80个字符


1.4 换行

当一行的长度达到单行最大字符数限制时,就需要手动将一行拆成两行。

  • 在运算符后换行,第二行追加两个缩进;

  • 例外:当给变量赋值时,第二行的位置应该和复制运算符的位置保持对齐。


1.5 空行

在方法之间;

在方法中的局部变量(local variable)和第一条语句之间;

在多行或单行注释之前;

在方法内的逻辑片段之间插入空行,提高可读性。


1.6 命名

小驼峰命名法(Camel Case):首字母小写,后续单词首字母大写

大驼峰命名法(Pascal Case):首字母及后续单词首字母都大写

匈牙利命名法:名字之前冠以类型标示符前缀,比如:sName 表示字符串,iCount 表示整数。(不推荐)


1.6.1 变量和函数

变量名应当总是遵守驼峰大小写命名法,并且命名前缀应当是名词。

对于函数和方法命名来说,第一个单词应该是动词,这里有一些使用动词场景的约定:

csn:函数返回一个布尔值

has:函数返回一个布尔值

is:函数返回一个布尔值

get:函数返回一个非布尔值

set:函数用来保存一个值


1.6.2 常量

使用大写字母和下划线来命名,下划线用以分隔单词。(源于C语言)


1.6.3 构造函数

使用大驼峰命名法,与内置构造函数(Object、RegExp)相同的命名法。

构造函数的命名也常常是名词,因为它们是用来创建某个类型的实例的。


1.7 直接量

字符串:统一双引号或单引号

数字:浮点数不要省略整数或小数部分,不要使用八进制写法

null:

  • 用来初始化一个变量,这个变量可能赋值为一个对象。

  • 用来和一个已经初始化的变量比较,这个变量可以是也可以不是一个对象。

  • 当函数的参数期望是对象时,用作参数传入。

  • 当函数的返回值期望是对象时,用作返回值传出。

例子1:

var person;
console.log(typeof person); //"undefined"
console.log(typeof foo); //"undefined"

例子2:

var person=null;
var foo;
console.log(typeof person); //"object"
console.log(typeof foo); //"undefined"

undefined:避免在代码中使用 undefined

对象直接量:使用花括号取代显式地创建

数字直接量:使用方括号取代显式地创建

]]>
2013年07月05日 读书笔记
写给程序猿们的交互设计 http://ciaoca.com/diary?id=229

  编者按:看到此文时恍惚回到自己学习网页的时候,那时候只知有编程,不知有设计。各个论坛大部分时候讨论的也是如何用 Frame 实现页面的分区,如何做出圆角,以及写一大段 javascript 代码或者做个 flash 只为让页面看起来更眩一点。后来 css1.0, 2.0 陆续出现,html 4.0 4.1 以及如今的 html 5 也逐渐淘汰掉了表现样式的标签。视觉传达思想开始陆续进入程序猿与产品经理的视线,从网页到现在的 APP,经历过野蛮生长阶段后,只有那些功能与视觉传达同样优秀的产品才能笑到最后。

  2007 年苹果给业界带来了耳目一新的感觉,之后无数 APP 展现了几乎无限的让人惊艳的新概念,但是,不是每一个新奇的想法都能被称作设计。设计师需要经过严格训练,才能把想法转化为最终的设计,而在整个转化过程中,无数的想法是经不起仔细推敲的。设计师更多的时候在观察生活,观察自然,灵感不是随时就有,但是一个经过严格训练的设计师可以把普通的生活细节经过加工融入设计,最终打造出合格甚至优秀的产品。

  本文作者 Pasquale D'Silva 是 Elepath 的一位交互设计师兼产品设计师,在本文中,他从交互的角度阐释了优秀的设计应该具有的一些品质,或者说,优秀的产品该如何实现与用户的自然沟通。

  不得不说,有太多程序猿或者美工(注意,是美工,真正的设计师不会这么干)误把技术当艺术、把漂亮当设计了,真正重要的交互部分反而被忽略,你可以看看,一大批的产品都是近乎静态的,许多操作诡异至极,诸如你想添加一个条目到列表里,它就生硬的出现在那;你想删除,它就直接消失。这样的产品经理,你们到底有没有考虑过用户的感受,有没有考虑过产品的感受,这种完全不合逻辑的东西也亏你们做的出。

  当然,还有一部分产品是有交互的,但是,悲哀的是,那些交互完全被用作另一种形式的美化,天才知道那些人在想什么。

  交互真正革命性的意义在于,它把时间这一魔幻般的属性带入静态的产品之中,通过对动作、速度、显现等等的定义,让产品的操作体现出真实感,使得用户能自然而然的理解每一个动作的含义。不过这不是那些高中时候整天泡妞、看不起书呆子的人能理解的。


一些简单的例子

  这些例子的目的是向各位读者介绍动画的精髓,告诉各位读者时间轴和空间对于动画意义。而动画对于交互的意义不言而喻。


例:缓冲效果

以下三个 demo 展示了在最传统的动画中,如何通过控制关键帧来控制整个动画的效果。

  在这三段 25 帧的动画中,设计师只需要定义第一帧、最后一帧和关键帧(第 13 帧),其余 22 帧由计算机自动填充,但是,计算机没想像中那么聪明,它只能线性的填充空白帧。优秀的动画师和动作设计师需要花费大量时间来学会如何控制计算机按照自己设计的效果工作。有兴趣的读者可以自己做些实验,本文重点在于阐述概念,所以不着过多笔墨于技术方面。


另一些稍复杂的例子:交互动画所能营造的真实感

  这些例子的目的在于告诉设计师们,交互所能代替的一些旧功能以及实现以前所不能做到的功能。


例一 插入元素

以下是三个关于向列表里添加/删除元素的 demo,来展示不同的交互动画所产生的效果

  Demo 1 没有进行任何加工,既生硬又粗糙,不能给人以任何自然的感觉。

  Demo 2 添加了一些关键帧使得添加的动作顺畅了很多,这样的动画已经能给用户一些暗示了。

  最后一个 demo 是最贴合自然状态的,就象我们平时把一本书插入书架一样,需要先腾出空间,然后再插入/取出。

  例一最后一个 demo 的设计让人一目了然,因为这和生活中的动作完全相似,用户不需要其他提示就知道这样的动作所代表的含义。这样的交互动作在之前的非触摸屏上没有多大用处,但对于如今遍地的 APP 意义重大。


例二 展开/弹出菜单

同样是三个 demo,分别展示不同的展开效果所带来的不一样的感觉。

  第一个是最典型的展开样式,但是不具有体验上的一致性,这个动作在现实中并不存在,所以没有办法让用户轻易的明白它的含义。

  再观察下第二个,这样的样式是不是给了你更多的信息?

  最后一个样式可以使关键内容突出,可以用来表示强调。

  切记,不要试图把多种样式放在一个产品/功能中,这样会导致用户不明所以的。

  例二后两个 demo 的设计可以代替老式导航栏,用户可以很容易记得自己的动作,从而知道自己所处的位置。

  当然,所有的例子都不是万金油,需要视情况而使用。放在这里的目的只是让大家明白,干净利落但是逻辑性强的动画对于改善产品体验的作用。

  想要更多的了解动画在具体产品中的效果,可以体验下Thinglist,这是我与 Kyle Bragger 合作为 Elepath 开发的一款产品。下图是该 APP 关于如何加载内容的示范。



动作化界面的设计原则

  你明白的,我不能把很具体的产品名字些在这,但是,有些产品的确是走极端了,一种是界面极端漂亮但没有一点交互,另一种是拿交互动画当装饰完全失去交互的本质。所以我列出以下几项原则来定义真正的交互:

  一、 动画干净利落

  二、 节奏一致、过渡自然

  有些人的想法让我很无语,他们从不认为可以添加时间元素到界面中。难道,你们不知道交互能提供更多更有用的信息给用户么,还是你们觉得这样做对你们来说太复杂了?

  起初,这份文档只是用来培训内部员工,后来我们觉得如果公开来讨论可能会更有用,而且我也愿意与更多同行交换意见。如果有兴趣可以在推特@pasql。或者在Branch参与我们的讨论。


读者福利(一些值得读或者看的材料):

The Animator's Survival Kit by Richard Williams

Timing & Spacing Primer

Prologue - Designing Fictional Interfaces for Iron Man 2

A demonstration of me using Moonbase, an Elepath animation experiment

]]>
2013年06月04日 科普日记
我猜我不是“501”程序员 http://ciaoca.com/diary?id=228 注:501程序员指的是那些选择在每天 5 点 01 分下班的程序员,他们通常在下班后,就不再关心工作,而是把精力放在家庭上。


  当我初次接触到《501程序员宣言》(译文见本文最后部分)时,我就高度赞同它的观点。程序员这个职业(尤其是在旧金山)通常鼓励加班。但我却不喜欢这样做,我向往的是一种快乐的编程方式。501程序员宣言,太棒了!

  然后,我就读到以下内容:

《501程序员宣言》 写道

如果你:

·写技术博客。

·参与开源项目的开发。

·在业余时间参加技术交流活动。

·几乎只读和编程与开发效率有关的书籍。

·在 GitHub 上有自己的托管项目。

·许下诺言始终做到最好,或者让别人深信这一点。

……我们会因此而尊重你。以上内容或许并不全面,但列出的这些,说实话,它们几乎都是值得尊重的。


  读完这些,我凌乱了。因为我几乎符合以上所有条件。对于我来说,编程不是一份工作,而是一项充满激情的事业。我曾参与过一些开源项目中,这倒不是因为我本身有多么的优秀,而是因为编程是一项令人肃然起敬的工作。想想看:拥有一台电脑,只要你能想得到的,你都有能力把它开发出来。我想这也是每一个程序员的梦想吧。


  开源是一项伟大的运动。它为我提供了诸如 Acme::BleachSemicolonHaskell 之类的优秀的项目。并且这些都是免费的,因为创始人的本意就是如此。撇开玩笑不谈,也正是这点惹恼了我(因为我发现这些条件让我不再是一名 501 程序员)。开源运动允许我们以绝大多数工作想都不敢想的速度来推动社会的创新发展。难道你没看见近 5 年来,由于科技的发展,整个世界发生了巨大的变化吗?而且,你将有成千上万名有志于让世界变得更美丽的同行……大部分职业本应该也是如此幸运的。


  我可以肯定我是一名 501 程序员。我喜欢和朋友呆在一起讨论技术问题,我喜欢以一种连续不断的节奏来开发我的项目(我满足《501宣言》的条件)。无论是哪一份新工作,我总是安排合理的时间去工作。我尤其想找一份每周工作时间少于 40 个小时的工作。但或许这些可能不适合你。因为,虽然你成为了一名程序员,但这仅仅是因为你擅长编程并且薪水丰厚,而不是因为你热爱编程。


下面这段由 zacharyvoase 女士发表在 Hace News 上的留言道出了我的心声:

  一周只有 5 天,一天也仅仅有 8 个小时在工作。总共大约占到你一生时间的 25% 吧。此外,另有 33% 的时间花在了睡觉上。

  你一生中所有重要的事,都要挤在这珍贵而又少得可怜的时间里完成。比如上学、醉酒、结婚、买房、参加葬礼等等。

  鉴于此,我决定:我不再把我生命中这宝贵的 25% 的时间浪费在做我不喜欢的事情上。

对于这段话,我猜你想说的是:

虽然对于我们来说这只是一份工作,但我们依然做到最好。

  你可以不喜欢编程。而我也理解这一点。但如果这句话的潜台词是,当你由于工作出色得到奖励之后,就放弃了学习和创新,我将无法容忍这一点。


另附《501程序员宣言》译文:

《501程序员宣言》 写道

我们是程序员。我们以我们的工作为荣,但不允许生活被其完全左右。

基于此,我们非常自豪的宣布,我们认为:

·家庭比老板的生意更重要。

·业余时间比公司提供的免费零食更重要。

·过自己的生活比辛苦维护个人品牌更重要。

·有计划和连续不断的工作节奏比个人超常的能力更重要。

·花时间自己去购物比耗费心思得到微软的免费T恤更重要。

·和挚友打球比和上司打球更重要。

·不拖团队后腿比成为业界大牛更重要。

·在以上所列内容中,我们把前者看的更重要。对于后者,我们不屑一顾。

但如果你:

·写技术博客。

·参与开源项目的开发。

·在业余时间参加技术交流活动。

·几乎只读和编程与开发效率有关的书籍。

·在 GitHub 上有自己的托管项目。

·许下诺言始终做到最好,或者让别人深信这一点。

……我们会因此而尊重你。以上内容或许并不全面,但列出的这些,说实话,它们几乎都是值得尊重的。

  而从这些内容中,我们也意识到你将把事业深深地融入到你的生活中,这些努力会让你不可避免的会成为我们的上司。对于这一点,我们为你感到高兴。

  但反过来,你也必须意识到,事业的成功是和你是否尊重我们,包括对我们作为专业人士并有享受多姿多彩的生活权利的尊重,是息息相关的。选择尊重这些,我们将一起创造美好的未来;而如果选择否定这些,一切成功的梦想都将只是梦想。而这一切,将取决于你的选择。

  虽然对于我们来说这只是一份工作,但我们依然做到最好。

]]>
2013年06月04日 科普日记
IE6 - IE9 的 CSS Hack http://ciaoca.com/diary?id=226 .hack{ color:#fff;background:#000; background:#06f\9; /* all IE */ background:#090\0; /* IE8-9 */ background:#090\0/; /* IE8 only */ *background:#f60; /* IE6-7 */ _background:#f00; /* IE6 only */ }

  根据需要,选择所需的Hack,不要滥用!在需要降级处理,或者不可避免要用到Hack的时候,再用吧!

]]>
2012年11月12日 代码日记