出 Nook Simple Touch 一只
1====================已出,谢谢====================
因为刚刚入了 iPad,所以想把原来的 Nook 出掉,买过来一年不到,8.5 成新,入手价格 749,现在 400 出掉:
正面照:

背面照:

不了解的朋友可以看我刚刚入手的时候的评测:Nook 入手评测
本人人在杭州,可以当面交易,或者走支付宝,想要的朋友加我的 QQ:64132906 或者通过邮件和我联系 hting1@gmail.com
又一次马拉松
2今天跑完了今年的杭州马拉松,还是半马,成绩在预料之中,算起来已经是第四次参加了马拉松了,也是第三次半程马拉松,跑过苏州和杭州,如果明年有机会,我想去厦门和北京跑,换个不同的城市跑跑应该还是挺有意思的,:-)。
想起去年第一次跑半程马拉松之前的那段时间,和一群同事每周三都到西湖去环湖跑,跑完之后去绿茶吃一个鱼头诱惑,很是惬意。到了今年,原来的伙伴们离职的离职,出国的出国,又或者是各种各样的原因不跑了,能够坚持下来的已经没有几个(不过也有一位今年积极备战跑完了全马),不过对我来说,跑步更像是一种瘾,一周不跑就全身不爽,非要去跑个几公里才开心,真是一种非常奇妙的感觉,所以今年虽然跑地比较少,但是还是算在断断续续地在跑。
另外,我也在正在找人组队去跑明年 1 月 5 号的厦门马拉松,想去的联系我啊~~~

Javascript 闭包
2从知道 Javascript 这门语言以来,一直不断听到身边的人提到 Javascript 的闭包,也有很多人跟我解释过 Javascript 的闭包是怎么回事,但是,作为一个主力语言是 Java 的程序员,天资愚钝,不管别人跟我怎么解释,我怎么都无法很好地理解 Javascript 的闭包。
前段时间由于项目需要,写了不少的 Javascript 代码,不过都是照前端同学的代码依样画葫芦,里面也包含很多对闭包的使用,虽然代码可以跑,没有错,但是不理解,心里憋得难受,遂花了一点时间去“深入”理解了一下 Javascript 的闭包。
那么我们先来看看维基百科中闭包的定义:
在计算机科学中,闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。
一眼看这个定义,相当抽象,但是抛开抽象的名词,仔细分析一下我们可以发现只要理解 变量离开了创造它的环境还可以和引用它的函数一同存在 是怎么回事儿就可以。那么,要理解这句话,首先要理解 ECMAScript 标准中的几个概念:执行上下文(Execution Context),变量环境(VariableEnvironment)和 Function 对象的 [[scope]] 属性,下面先来看看这几个概念:
执行上下文
执行上下文是 ECMAScript 标准中定义的一个需要标准的实现者实现的行为。在一段 Javascript 代码中,最外层的 Global Object 关联一个全局的上下文,每执行一个方法就会进入到一个新的执行上下文中,方法执行结束就从这个执行上下文中退出,回到原来的执行上下文中,如果新执行一个方法,那么就又会进入到一个新的执行上下文中,这样,一个个的执行上下文就形成了一个栈,栈顶就是当前正在执行的方法的执行上下文。
PS,如果你是一个 Java 程序员,那么执行上下文并不难理解,它很像 Java 虚拟机中的 Stack Frame,我们知道 Java 每执行一个方法,都会在 VM Stack 中压入一个 Stack Frame,执行完后就弹出这个 Stack Frame,栈顶就是正在执行的方法,这和执行上下文基本上是一样的。
变量环境
Javascript 中每执行一个方法,都会创建一个执行上下文,当执行上下文创建完成以后,Javascript 会在执行上下文中定义一个变量环境,所谓的变量环境,就是用来存放在该执行上下文中创建的各种变量(包括方法变量),就像下面这段代码这样:

[[scope]] 属性
当然,变量环境没有这么简单,相互之间并不是没有关系,每一个 Javascript 的 Function 对象都一个 [[scope]] 内部属性,这个属性指向的是 Function 对象所在的执行上下文的变量环境。对于上面例子中的 outer 方法,它的 [[scope]] 属性指向的就是全局执行上下文的变量环境,而 inner 方法的 [[scope]] 属性指向的是 outer 方法的执行上下文的变量环境。
每进入一个方法的代码,Javascript 都会把方法对象的 [[scope]] 属性拿来初始化变量环境,在声明绑定实例化的时候,再将在方法代码中定义的变量加入到变量环境中,因此,每一个变量环境都继承了外一层的变量环境,对于上面这段代码来说:
最外层的全局的变量环境就是:
{
global: "global"
}
里面的 outer 方法的变量环境就是:
{
global: "global",
outer: "outer"
}
再往里面的 innter 方法的变量环境就是:
{
global: "global",
outer: "outer",
inner: "inner"
}
闭包
从上面的我们得知,[[scope]] 起到了桥接内部和外部的变量环境的作用,那么,还是看上面的那段代码,inner 方法被返回,在其变量环境中的所有的变量,当然也都会随着 inner 方法被返回而继续存在,这就意味着在 outer 方法中定义的变量 outer,即使在 outer 方法执行结束以后还会继续随着 inner 方法存在,这个时候 outer 就成为了自由变量,它离开了创造它的环境(outer 方法)还和引用它的函数(inner)一起存在,这就是前面我们提到的闭包的定义。
结论
从上面的分析思路来看,闭包差不多就是变量环境的继承而导致的副作用物。了解了闭包产生的过程,以后使用的时候就不会再感到无所适从了。当然,这个“副作用物”的威力有多大,现在初学 Javascript 的我还没有领会到,如果大家有这方面的经验,不吝赐教。
参考资料
- ECMAScript Reference:http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
- Javascript Closures:http://jibbering.com/faq/notes/closures/
- Understanding JavaScript Closures:http://javascriptweblog.wordpress.com/2010/10/25/understanding-javascript-closures/
《程序员的思维训练》书评
0本书的作者是大名鼎鼎的程序员,敏捷开发的先驱 Andy Hunt,他写过的最著名的一本书可能就是《程序员修炼之道》了。
很惭愧,虽然手上早早就有了一本英文版的《程序员修炼之道》,却迟迟没有看完,所以虽然大家都说很好,但是我还不敢评论那本书。但是 Andy Hunt 的这本书,绝对值得推荐,这是一本帮助你认识你自己的书,自己到底处在那个层级?新手?高级新手?专家?(有趣的是,这本书刚好也是写给新手的,所以按照这本书中的理论,本书刚好非常适合新手去看)。如果你在工作中感觉经常分心,或许你应该试试书中提到的诸如冥想之类的练习控制注意力的方法。如果你觉得看书就是看了,没有记住什么东西,你或许可以试试这本书中提到的 SQ3R 阅读法。
这本书本身的可操作性非常强,按照书中的方法中就可以开始做了,至于其中的方法靠不靠谱,我自己倾向于还是比较靠谱的,就看读者自己的执行力了。另外书中提到的小组学习的方式,在我刚刚开始工作的那段时间,就和几个同事这样干过,效果还是非常不错,还建了一个网站黄金档,当然,随着时间的推移加入的人多了,效果就打折了,这也是这本书中提到的,刚好和我本身的经历比较符合。
下面是我根据书中的介绍的思维导图做的一个读书的记录,我想看这个图(点击可查看大图)大概就可以知道这本书主要在讲些什么东西:
我学到的一些关于编程的事儿(翻译)
2原文地址:Some things I’ve learnt about programming —- By John Graham-Cumming
我已经从事编程 30 年了,用过的机器包括从现在看来很差的(基于 Z80 和 6502)到最新的,用过的语言包括 BASIC,汇编语言,C,C++,Tcl,Perl,Lisp,ML,occam,arc,Ruby,Go等等。
下面是我学到的一些关于编程的事儿:
0. 编程是一门手艺而不是科学或工程
编程更接近于一门手艺而不是科学或工程。它是技能和经验的组合,它需要通过工具来表达出来。一个手艺人会选择特定的工具(有时候他们会自己去做)然后学习用它去创造。
在我看来这就是手艺。我认为最好的工程师更加接近于钟表匠而不是桥梁建筑师或者是物理学家。当然因为对逻辑和数学的应用,编程看起来像是科学或工程,但是本质上它就是你拿你手上的工具去做东西。
既然编程是一门手艺,那么我们就不难理解为什么在编程中经验,工具,直觉很重要。
1. 诚实是最好的方针
编程的时候我们经常为了看看发生了什么或者让一个程序跑起来去试试一些代码,但是却并不真正地理解到底发生了什么。比如:你决定要调用一个 API,仅仅因为它神奇地让 Bug 消失了;再比如,在程序中插入一行 printf ,因为它让程序不再崩溃。
这些都是对自己不诚实的例子。你必须问自己:“我是否知道我的程序到底做了什么事情?为什么做这个事情?”。如果你不知道,你迟早会陷入麻烦。明白一个程序做了什么是程序员的责任,计算机只会精确地做它被告诉去做的事情,而不是你想要它做的事情。
诚实需要你对自己非常严格。你必须非常严格地确定你已经知道你的程序干什么,为什么这么干。
2. 简化,简化,再简化
Tony Hoare 说过:
有两种方式构建软件设计:一种把软件做得非常简单以至于明显没有缺陷,另一种是把它做得非常复杂以至于找不到明显的缺陷。第一种方法要难得多。
简化,重构,删除。
我把 Hoare 的话改了一下:“在每一个大型复杂的程序里面,都是一些小而优雅的程序在把同样的事情做对。”
和这个相关的是“小块松散组合”哲学。通过一些相互通信的部分去构建一个程序,而不是构建一个单独的大程序。这也是 UNIX 如此成功的部分原因。
3. 不要依赖调试器,但是性能分析器不一样
我几乎从来不用调试器。我的程序会打印日志,我知道我的程序到底干了什么。大部分时候我可以从日志中看出发生了什么而不用借助调试器。
我不用调试器的原因是因为我认为它会导致你懒于思考。当遇到一个 Bug 的时候,很多人都会去设置断点,然后检查内存或者变量的值。我们很容易被这样迷人的工具所吸引,因为思考看起来会花费更多的时间。如果你的程序非常复杂,你必须需要一个调试器,那么你或许应该回去看看第二点。
(题外话:尽管说了这么多,但是一个我非常尊重的程序员,John Ousterhout,似乎会把整天的时间都花在 Windows 调试器上)。
另一方面,如果你需要了解你的程序的性能,那么性能分析器是非常重要。你永远不会对性能分析器所告诉你的东西停止感兴趣
4. 代码重复会让你很受伤
不要重复你自己。你的代码中的每一件事情应该只做一次。
这是第二点的一个特例。甚至是一点小小的代码重复都会在将来给你带来麻烦。
5. 对语言要随便一点
有些人对一门特定的语言很着迷,所有的东西都用它去做。这是一个错误。没有一门语言是适合所有的编程任务的。
关键是你要明白当你遇到问题的时候你要从你的工具箱里面拿什么语言去处理。工具箱中的工具当然是越多越好。试试不同的语言,试着用它做些东西。
如果你用下 Python 或者 ML,你会觉得 List Comprehension 很强大;或者你可以尝试下 Go,看看它是如何处理并发的;或者你可以用用 Perl,看看它处理字符串是多么地灵活;或者你可以用 PHP 去快速搭建一个动态网页。
我讨厌语言战争。失败者才会参与语言战争,因为这个争吵的东西本身就是个错误。比如说,在我的手上,PHP 就是个悲剧,但是在别人会用得很爽。对于 C++ 也是一样的道理。
6. 发展一个软件要比构建一个容易
这也和第二点有关。从一个小的部分出发,然后慢慢发展起来。如果你正在解决一个问题,那么从你要解决的问题的一个部分开始发展要比在问题的基础上设计一个庞大的架构容易。
当你从一开始就创建了一个庞大的架构,你就错了,你做了一个拜占庭式的复杂而死板的迷宫,你会发现自己很难去改变它。反过来,如果你从一些相互协作的小的部分出发,那么当你意识到从一开始你就把一个问题搞错了以后,重构起来将会非常容易。
这个的根本是你无法知道一个正确的架构到底长什么样子。这是因为你很难知道你的程序的外部输入会是什么样子。你也许认为你知道,比如,你的邮件服务器所需要处理的 TCP 流,或者是收件人的个数是多少,或者是垃圾邮件长什么样子。有些外部的数据会让你的假设失效。如果你的假设已经融合在一个大的,复杂的,难以改变的程序里,那么你真是麻烦大了。
7. 学习计算机的每一个层次
我觉得对从 CPU 到你所用的语言有一个认识是非常重要的。理解计算机的每一个层次非常重要。
当你需要处理性能问题的时候这就非常有用。我想起一个事儿,这个事情我依然记得很清楚,一个客户给我们公司发了一个 Window 2000 的崩溃截图,图上有一些内存和寄存器的信息。当我们知道他所用的程序的版本后,我们就找到了是一个空指针的问题导致了这个现象。
8. 我还不够年轻至足以知道一切
我依然有很多的东西要去学。有一些语言我想要接触还没有怎么接触过(Erlang,Clojure);有些语言我有所涉猎但是并不精通(JavaScript);有一些知识点我根本就不懂(monads)。
PS:我还没有提到过测试。我应该加上这一点,因为我确实认为对任何不是马上就扔掉的代码,测试用例都是非常重要的。也许再写 30 年的代码我就可以对“单元测试提升了软件质量吗?”这个问题有了一个答案。我写代码有时候写单元测试,有时候不写,我不知道这个问题的答案,尽管我更倾向于写单元测试。
