<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:series="http://unfoldingneurons.com/"
	>

<channel>
	<title>小麦的自习教室</title>
	<atom:link href="http://www.mikkolee.com/feed" rel="self" type="application/rss+xml" />
	<link>http://www.mikkolee.com</link>
	<description>关于界面的价值观与方法论</description>
	<pubDate>Sat, 22 Nov 2008 03:32:19 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.6.2</generator>
	<language>en</language>
			<item>
		<title>作用域链 词法作用域 与闭包（二）</title>
		<link>http://www.mikkolee.com/84</link>
		<comments>http://www.mikkolee.com/84#comments</comments>
		<pubDate>Sat, 22 Nov 2008 03:31:54 +0000</pubDate>
		<dc:creator>小麦</dc:creator>
		
		<category><![CDATA[网页标准]]></category>

		<guid isPermaLink="false">http://www.mikkolee.com/?p=84</guid>
		<description><![CDATA[这次讲词法作用域。这个概念其实跟JS没太大关系，它一定程度上属于更广泛的层次：程序设计语言。
词法作用域又被成为静态作用域，它的关键特性就是“作用域由定义语句决定”。而和它相对的“作用域由调用语句决定”的，被成为动态作用域。这几个概念，实际上就是在描述构建作用域的规则。
《程序设计语言-实践之路》中说，“在采用静态（词法）作用域的语言里，名字与对象的约束可以在编译时通过检查程序正文确定，完全不需要考虑运行时的控制流。”这句话看起来揭露了为什么“词法作用域”被称为静态作用域。
但是仔细回忆“作用域链 词法作用域 与 闭包（一）”中所讲，JS的一个函数的作用域链事实上是在它被调用时才建立的。这里就有困惑了。既然JS的作用域其实是在调用时才建立，为啥又说它是遵循静态作用域规则呢？
更让人困惑的是，之前不是说JS的作用域链是“由定义它的语句决定”的么？这似乎和“在它被调用时才建立”有矛盾。这个问题让我困惑了很久。事实上呢，两句话都没错。我们还是把上次那个例子拿出来：

function f(x) {
    var g = function () { return x; }
    return g;
}
var g1 = f(1);
var g2 = f(2);
alert(g1());  //输出 1
alert(g2());  //输出 2

g1的作用域链，确实是在调用它的时候才建立起来的。这个作用域链的内容是:g1的调用对象 -> f(1)的调用对象 -> 全局对象。注意哦，你会发觉，其实这个作用域链中，只有第一个是g1()调用时新建的，剩下的部分其实是f(1)的作用域链。
事实上呢，虽然g1()的作用域链“在它被调用时才建立”，但是，由于除了这个作用域链头部以外，其他部分都定死了，所以这个作用域链的内容也就被“决定”了：无论它在何处被调用，调用几次，即使每次调用时都新建一个调用对象，它的作用域也肯定是“g1的调用对象 -> f(1)的调用对象 -> 全局对象”这个形式。
OK，《程序设计语言-实践之路》的作者Michael L.Scott会说，“可以在编译时通过检查程序正文确定，完全不需要考虑运行时的控制流”呢？按理说，是在调用f(1)时，定义了g1。而f(1)何时何处如何被调用，仍然可能是在编译时无法预知的。
如果要在编译时，就能确定作用域，只有一种可能性，在函数定义时就为函数开辟一个唯一的执行环境。每次调用此函数时，把变量值放到这个执行环境中运行即可。
我试着以这样的假设来重新解释上面那段JS运行时的步骤：
1. 解析到function f(x)时，为其创建一个调用对象F，在该调用对象中定义x变量。
2. 解析到function () { return x; }，再创建一个调用对象G，将其加在F的头部，形成作用域链。
3. 执行f(1)的时候，将F的x变量赋值为1，并返回调用对象G的指针。
4. G的指针被赋给g1。
5. 执行g1()的时候，会通过指针找到G，再通过作用域链找到F中的x，返回x。
这样看来，调用对象在解析函数的function定义语句时就生成，好像也是合理的。但问题是，例子中，f(1)执行后紧接着执行f(2)。如果它们俩只用一个调用对象的话，在接下来执行g1()的时候，x就应该是2，而不是1。由此可看出，JS确实是“动态的创建作用域”的。
换句话说，将JS称为是“静态作用域”语言，确实有点问题！
而将JS称为“词法作用域”语言，却不无道理。虽然说，JS是动态的创建作用域链。但由于g1的定义是写在f的执行语句中的，因此，从代码上看，g1只有在f被调用执行的时候，才会被定义。换句话说，g1的调用对象建立的时候，相应的f的调用对象肯定已经被建立了。因此它的作用域结构一开始就由代码结构定死了。（当然，我个人觉得，或许叫“语法作用域”更恰当。词法（Lexical）和语法（Syntax）的区别，请见编译原理教材）。
对此我确实提出几个质疑：
1. [...]]]></description>
			<content:encoded><![CDATA[<p>这次讲词法作用域。这个概念其实跟JS没太大关系，它一定程度上属于更广泛的层次：程序设计语言。</p>
<p>词法作用域又被成为静态作用域，它的关键特性就是“作用域由定义语句决定”。而和它相对的“作用域由调用语句决定”的，被成为动态作用域。这几个概念，实际上就是在描述构建作用域的规则。</p>
<p>《<a href="http://www.douban.com/subject/1231298/">程序设计语言-实践之路</a>》中说，“在采用静态（词法）作用域的语言里，名字与对象的约束可以在编译时通过检查程序正文确定，完全不需要考虑运行时的控制流。”这句话看起来揭露了为什么“词法作用域”被称为静态作用域。</p>
<p>但是仔细回忆“作用域链 词法作用域 与 闭包（一）”中所讲，JS的一个函数的作用域链事实上是在它被调用时才建立的。这里就有困惑了。既然JS的作用域其实是在调用时才建立，为啥又说它是遵循静态作用域规则呢？</p>
<p>更让人困惑的是，之前不是说JS的作用域链是“由定义它的语句决定”的么？这似乎和“在它被调用时才建立”有矛盾。这个问题让我困惑了很久。事实上呢，两句话都没错。我们还是把上次那个例子拿出来：</p>
<pre>
function f(x) {
    var g = function () { return x; }
    return g;
}
var g1 = f(1);
var g2 = f(2);
alert(g1());  //输出 1
alert(g2());  //输出 2
</pre>
<p>g1的作用域链，确实是在调用它的时候才建立起来的。这个作用域链的内容是:g1的调用对象 -> f(1)的调用对象 -> 全局对象。注意哦，你会发觉，其实这个作用域链中，只有第一个是g1()调用时新建的，剩下的部分其实是f(1)的作用域链。</p>
<p>事实上呢，虽然g1()的作用域链“在它被调用时才建立”，但是，由于除了这个作用域链头部以外，其他部分都定死了，所以这个作用域链的内容也就被“决定”了：无论它在何处被调用，调用几次，即使每次调用时都新建一个调用对象，它的作用域也肯定是“g1的调用对象 -> f(1)的调用对象 -> 全局对象”这个形式。</p>
<p>OK，《<a href="http://www.douban.com/subject/1231298/">程序设计语言-实践之路</a>》的作者Michael L.Scott会说，“可以在编译时通过检查程序正文确定，完全不需要考虑运行时的控制流”呢？按理说，是在调用f(1)时，定义了g1。而f(1)何时何处如何被调用，仍然可能是在编译时无法预知的。</p>
<p>如果要在编译时，就能确定作用域，只有一种可能性，在函数定义时就为函数开辟一个唯一的执行环境。每次调用此函数时，把变量值放到这个执行环境中运行即可。</p>
<p>我试着以这样的假设来重新解释上面那段JS运行时的步骤：</p>
<p>1. 解析到function f(x)时，为其创建一个调用对象F，在该调用对象中定义x变量。<br />
2. 解析到function () { return x; }，再创建一个调用对象G，将其加在F的头部，形成作用域链。<br />
3. 执行f(1)的时候，将F的x变量赋值为1，并返回调用对象G的指针。<br />
4. G的指针被赋给g1。<br />
5. 执行g1()的时候，会通过指针找到G，再通过作用域链找到F中的x，返回x。</p>
<p>这样看来，调用对象在解析函数的function定义语句时就生成，好像也是合理的。但问题是，例子中，f(1)执行后紧接着执行f(2)。如果它们俩只用一个调用对象的话，在接下来执行g1()的时候，x就应该是2，而不是1。由此可看出，JS确实是“动态的创建作用域”的。</p>
<p>换句话说，将JS称为是“静态作用域”语言，确实有点问题！</p>
<p>而将JS称为“词法作用域”语言，却不无道理。虽然说，JS是动态的创建作用域链。但由于g1的定义是写在f的执行语句中的，因此，从代码上看，g1只有在f被调用执行的时候，才会被定义。换句话说，g1的调用对象建立的时候，相应的f的调用对象肯定已经被建立了。因此它的作用域结构一开始就由代码结构定死了。（当然，我个人觉得，或许叫“语法作用域”更恰当。词法（Lexical）和语法（Syntax）的区别，请见编译原理教材）。</p>
<p>对此我确实提出几个质疑：<br />
1. 或许Scott对“静态作用域”的解释有误，静态作用域的语言，并非都可以在编译时确定作用域。<br />
2. 或许，他文中说能够确定的是“名字与对象的约束”，这句话并非是指具体的作用域，而是作用域的结构。<br />
3. 如果上面两个质疑都不对，那么“词法作用域”和“静态作用域”不应该是同一概念。至少不应该叫“静态作用域”。</p>
<p>最后，值得一提的是，“词法作用域”和“作用域链”，彼此并不相干。很简单，采用“词法作用域”，也就是“静态作用域”的语言，不一定有“作用域链”。比如C语言，采用的就是“静态作用域”。何以证明？C语言中存在函数指针的概念，因此，一个函数g可能会在另一个函数f中被调用。而无论g在哪里被调用，它的作用域都不会包括调用它的f的作用域，因此，C语言函数的作用域并不是“由调用环境决定的”，它是“静态作用域”。但是C语言不存在作用域链的概念，原因很简单：C语言的作用域被严格限定在函数体内，未在函数体内被声明的变量是不允许使用的。所以它不需要作用域链的概念。</p>
<p>此外，有作用域链（或类似概念）的语言，未必是“静态作用域”的。Perl就是一个例子。</p>
<p>由此看来，是否有作用域链，取决于是否允许使用本代码块中未定义的变量。这种变量被称为自由变量。而自由变量，则是闭包概念中的关键要素。这个下次再讲。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikkolee.com/84/feed</wfw:commentRss>
		</item>
		<item>
		<title>海角七号</title>
		<link>http://www.mikkolee.com/92</link>
		<comments>http://www.mikkolee.com/92#comments</comments>
		<pubDate>Thu, 20 Nov 2008 13:09:00 +0000</pubDate>
		<dc:creator>小麦</dc:creator>
		
		<category><![CDATA[懒得分类]]></category>

		<guid isPermaLink="false">http://www.mikkolee.com/?p=92</guid>
		<description><![CDATA[

吃晚饭时路过买碟小摊，瞥到一眼海角七号，回来和kaki聊到，就到网上找来看了。
这是一部神奇的电影。它讲述了失落的一群人如何冲破现实的阻挠，将自己的理想升华。
讲述了60年前对友子的一份深切爱恋，如何成为历史的尘埃。
讲述了带着这份爱恋的7封情书，60年后如何跨越遥远的时空，最终静静的落在友子的身旁。
讲述了阿嘉如何面对一个原本快要擦肩而过的人，最终鼓起勇气对她说，留下来，或者我跟你走。
和阿达谈起日据的台湾，忽然意识到，在过去一百年里，台湾只有4年时间和大陆有联系。而正是这个在太平洋西岸漂泊多年的小岛，给我们带来如此多的故事。
其实除了情节本身，让我更感慨的是那段历史。这部电影的配乐，名叫“1945”。1945对日本来说，是战败的屈辱；对台湾来说，是光复的喜悦；对我们这些后人来说，是教科书上的一段文字。
而对友子，和那位深爱着她却不辞而别的日本教师而言，1945不需要背负那么多沉重的意义，它只是一道狠狠刻在自己心中的痕。而那来自1945的7封信，被阿嘉轻轻的放在友子婆婆的身旁，而她却没有察觉。直到做完一天的活，轻轻回头，看见这个盒子。当她拿起信的时候，镜头就结束了。
我很喜欢电影如此轻轻的带过了这个场景。7封来自大洋彼岸的信，在60年后最终送到了友子婆婆的面前。它并不需要什么结果，只不过告诉对方，在这一个甲子的轮回后，我一直在。

]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.mikkolee.com/blog/wp-content/uploads/2008/11/200811172349071.jpg" alt="" width="400" height="294"  /></p>
<p><img src="http://www.mikkolee.com/blog/wp-content/uploads/2008/11/200811180020351.jpg" alt="" width="350" height="501"  /></p>
<p>吃晚饭时路过买碟小摊，瞥到一眼海角七号，回来和kaki聊到，就到网上找来看了。</p>
<p>这是一部神奇的电影。它讲述了失落的一群人如何冲破现实的阻挠，将自己的理想升华。</p>
<p>讲述了60年前对友子的一份深切爱恋，如何成为历史的尘埃。</p>
<p>讲述了带着这份爱恋的7封情书，60年后如何跨越遥远的时空，最终静静的落在友子的身旁。</p>
<p>讲述了阿嘉如何面对一个原本快要擦肩而过的人，最终鼓起勇气对她说，留下来，或者我跟你走。</p>
<p>和阿达谈起日据的台湾，忽然意识到，在过去一百年里，台湾只有4年时间和大陆有联系。而正是这个在太平洋西岸漂泊多年的小岛，给我们带来如此多的故事。</p>
<p>其实除了情节本身，让我更感慨的是那段历史。这部电影的配乐，名叫“1945”。1945对日本来说，是战败的屈辱；对台湾来说，是光复的喜悦；对我们这些后人来说，是教科书上的一段文字。</p>
<p>而对友子，和那位深爱着她却不辞而别的日本教师而言，1945不需要背负那么多沉重的意义，它只是一道狠狠刻在自己心中的痕。而那来自1945的7封信，被阿嘉轻轻的放在友子婆婆的身旁，而她却没有察觉。直到做完一天的活，轻轻回头，看见这个盒子。当她拿起信的时候，镜头就结束了。</p>
<p>我很喜欢电影如此轻轻的带过了这个场景。7封来自大洋彼岸的信，在60年后最终送到了友子婆婆的面前。它并不需要什么结果，只不过告诉对方，在这一个甲子的轮回后，我一直在。</p>
<p><img src="http://www.mikkolee.com/blog/wp-content/uploads/2008/11/200811180041261.jpg" alt="" width="400" height="267"  /></p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikkolee.com/92/feed</wfw:commentRss>
		</item>
		<item>
		<title>作用域链 词法作用域 与 闭包（一）</title>
		<link>http://www.mikkolee.com/81</link>
		<comments>http://www.mikkolee.com/81#comments</comments>
		<pubDate>Wed, 19 Nov 2008 13:59:44 +0000</pubDate>
		<dc:creator>小麦</dc:creator>
		
		<category><![CDATA[网页标准]]></category>

		<guid isPermaLink="false">http://www.mikkolee.com/?p=81</guid>
		<description><![CDATA[什么叫闭包？我花了很长时间来弄明白这个概念，但每次以为弄明白的时候，却又会发现其实没搞清楚。
本来是在JS里遇到这个概念，与它相伴出入的还有作用域链、词法作用域两个概念。我原本以为这三个概念是彼此等价的。但事实上，最近才发现，它们彼此不怎么相干，只是恰好同时存在与JS这种语言当中。
这次就先说说作用域链。犀牛书中应该有对作用域链的很形象的描述，这里就不赘述它的含义了。作用域链中有一个很重要的概念，叫调用对象。
调用对象可以理解为当一个函数如f()形式被调用执行的时候，引擎会为它创建一个对象，其中包含了函数的参数（亦即arguments对象），然后再按照函数定义中定义的各个变量名，在调用对象中开辟相应的变量作为调用对象的属性。最后将这个调用对象放到作用域链的头部。
所以一个函数被调用执行的时候，引擎大致会经历如下的步骤：
1. 根据调用参数，创建调用对象，创建参数变量
2. 根据函数定义，创建函数内部定义的变量
3. 把调用对象挂到作用域链的头部
4. 执行函数，返回结果
插一句，“调用对象(the call object)”这个名称其实很诡异。它的名字容易让它被误解为两个东东：
1. 作为方法调用这个函数的对象，如o.f()。
2.调用这个函数的函数，如function g() {f();}。
事实上两个都不是。第1个可以在函数中通过this引用，第2个通过Function对象的caller属性引用。但它们都不是“调用对象”。有一篇文章提到“执行环境（Excution Context），一定程度上可以把调用对象看做是函数的执行环境，它是函数自身运行的空间，而不是函数外部的东西。
这里有个很有趣的问题就是，我上面写的函数调用时的4个步骤中，第3个步骤“把调用对象挂到作用域链的头部”，其实并没有指出，挂在哪个作用域的头部。事实上这也是为什么我之前一直很迷惑的地方。好多文章，包括犀牛书，都没有讲明调用对象该挂到哪一个作用域的头部。
在这里引用一段JS代码，是犀牛书中提到的，我把它稍微改造了一下：

function f(x) {
    var g = function () { return x; }
    return g;
}
var g1 = f(1);
var g2 = f(2);
alert(g1());  //输出 1
alert(g2());  //输出 2

这段代码其实描述了一件很值得注意的事。函数f的功能是返回一个函数，这个函数的定义就是 function() { return x; }。所以对于后来的g1，它接受到的是这个函数，而g2接收到的也是这个函数。但它们执行出来的结果就不一样。也就是说，g1和g2在执行的时候，它们的调用对象挂在了不同的作用域链上！
犀牛书对此的解释是，JS采用的是“词法作用域”，亦即，一个函数的调用对象该挂在哪个作用域，是由它的定义语句决定，而不是由它的调用语句决定。其实这样说，仍然会很迷惑。我具体解释一下这两者的区别：
1. 如果作用域由“调用语句”决定。上例中，g1()这个调用，是写在alert()里的，那么它的作用域就应该按照调用语句的顺序：g1的调用对象 -> alert的调用对象 ->全局对象。同样，g2的调用形式和g1完全相同，所以它的作用域链也应该是：g2的调用对象 -> alert的调用对象 ->全局对象。如此看来，g1和g2中的x，都应该是undefined，因为沿着它们的作用域链中，都没有x的定义。
2. 如果作用域由“定义语句”决定。上例中，g1这个函数是在调用f(1)的时候定义的。g2这个函数，是在调用f(2)这个函数时定义的。所以，当执行g1()的时候，会将它的调用对象挂在f(1)的作用域链头部，而f(1)的作用域链中，x被赋值为1，所以g1中的x也是1。同理，g2的x是2。
所以从结果看，JS采用的是第2种方式。
这里还有一个容易混淆的地方：“由定义语句决定”。g1和g2这两个函数，并不是在写function() [...]]]></description>
			<content:encoded><![CDATA[<p>什么叫闭包？我花了很长时间来弄明白这个概念，但每次以为弄明白的时候，却又会发现其实没搞清楚。</p>
<p>本来是在JS里遇到这个概念，与它相伴出入的还有作用域链、词法作用域两个概念。我原本以为这三个概念是彼此等价的。但事实上，最近才发现，<strong>它们彼此不怎么相干</strong>，只是恰好同时存在与JS这种语言当中。</p>
<p>这次就先说说作用域链。犀牛书中应该有对作用域链的很形象的描述，这里就不赘述它的含义了。作用域链中有一个很重要的概念，叫调用对象。</p>
<p>调用对象可以理解为当一个函数如f()形式被调用执行的时候，引擎会为它创建一个对象，其中包含了函数的参数（亦即arguments对象），然后再按照函数定义中定义的各个变量名，在调用对象中开辟相应的变量作为调用对象的属性。最后将这个调用对象放到作用域链的头部。</p>
<p>所以一个函数被调用执行的时候，引擎大致会经历如下的步骤：</p>
<p>1. 根据调用参数，创建调用对象，创建参数变量<br />
2. 根据函数定义，创建函数内部定义的变量<br />
3. 把调用对象挂到作用域链的头部<br />
4. 执行函数，返回结果</p>
<p>插一句，“调用对象(the call object)”这个名称其实很诡异。它的名字容易让它被误解为两个东东：<br />
1. 作为方法调用这个函数的对象，如o.f()。<br />
2.调用这个函数的函数，如function g() {f();}。<br />
事实上两个都不是。第1个可以在函数中通过this引用，第2个通过Function对象的caller属性引用。但它们都不是“调用对象”。有一篇<a href="http://www.jibbering.com/faq/faq_notes/closures.html">文章</a>提到“执行环境（Excution Context），一定程度上可以把调用对象看做是函数的执行环境，它是函数<strong>自身运行的空间</strong>，而不是函数外部的东西。</p>
<p>这里有个很有趣的问题就是，我上面写的函数调用时的4个步骤中，第3个步骤“把调用对象挂到作用域链的头部”，其实并没有指出，挂在哪个作用域的头部。事实上这也是为什么我之前一直很迷惑的地方。好多文章，包括犀牛书，都没有讲明调用对象该挂到哪一个作用域的头部。</p>
<p>在这里引用一段JS代码，是犀牛书中提到的，我把它稍微改造了一下：</p>
<pre>
function f(x) {
    var g = function () { return x; }
    return g;
}
var g1 = f(1);
var g2 = f(2);
alert(g1());  //输出 1
alert(g2());  //输出 2
</pre>
<p>这段代码其实描述了一件很值得注意的事。函数f的功能是返回一个函数，这个函数的定义就是 function() { return x; }。所以对于后来的g1，它接受到的是这个函数，而g2接收到的也是这个函数。但它们执行出来的结果就不一样。也就是说，g1和g2在执行的时候，<strong>它们的调用对象挂在了不同的作用域链上</strong>！</p>
<p>犀牛书对此的解释是，JS采用的是“词法作用域”，亦即，一个函数的调用对象该挂在哪个作用域，是由它的<strong>定义语句</strong>决定，而不是由它的<strong>调用语句</strong>决定。其实这样说，仍然会很迷惑。我具体解释一下这两者的区别：</p>
<p>1. 如果作用域由“调用语句”决定。上例中，g1()这个调用，是写在alert()里的，那么它的作用域就应该按照调用语句的顺序：g1的调用对象 -> alert的调用对象 ->全局对象。同样，g2的调用形式和g1完全相同，所以它的作用域链也应该是：g2的调用对象 -> alert的调用对象 ->全局对象。如此看来，g1和g2中的x，都应该是undefined，因为沿着它们的作用域链中，都没有x的定义。</p>
<p>2. 如果作用域由“定义语句”决定。上例中，g1这个函数是在<strong>调用f(1)的时候定义的</strong>。g2这个函数，是在调用f(2)这个函数时定义的。所以，当执行g1()的时候，会将它的调用对象挂在f(1)的作用域链头部，而f(1)的作用域链中，x被赋值为1，所以g1中的x也是1。同理，g2的x是2。</p>
<p>所以从结果看，JS采用的是第2种方式。</p>
<p>这里还有一个容易混淆的地方：“由定义语句决定”。g1和g2这两个函数，<strong>并不是在写function() { return x; }的时候定义的哦！</strong>也就是说，虽然写了function语句，但不代表这个函数就马上被定义了。这点很关键！因为<strong>只有当f(x)被调用执行的时候，这个function语句才会被执行，这个函数才会被定义！</strong>其实这里的问题在于，“定义”的概念。<strong>在JS中，“定义一个函数”，意味着要“执行function语句”</strong>。很不巧，function语句无法写在循环或条件语句中，否则，这一点很容易可以得到证实（犀牛书说JS1.5的Netscape允许在条件语句中定义函数，大家可以试试看）。</p>
<p>至于说，g1()在执行的时候，还能记得它当初是在f(1)中定义的，并把调用函数挂在f(1)的作用域链上。并且，此时f(1)的作用域链居然还存在（它的调用执行已经结束了），这究竟是为什么，我目前还不清楚。但据说<a href="http://www.ecma-international.org/publications/standards/Ecma-262.htm">ECMA262</a>标准给出了具体的实现方法的，在函数定义时生成一个叫[[scope]]的内部属性。我没体力看了，交给大家吧。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikkolee.com/81/feed</wfw:commentRss>
		</item>
		<item>
		<title>图形化按钮</title>
		<link>http://www.mikkolee.com/73</link>
		<comments>http://www.mikkolee.com/73#comments</comments>
		<pubDate>Sat, 15 Nov 2008 04:49:38 +0000</pubDate>
		<dc:creator>小麦</dc:creator>
		
		<category><![CDATA[网页标准]]></category>

		<guid isPermaLink="false">http://www.mikkolee.com/?p=73</guid>
		<description><![CDATA[图形化按钮，就类似这个样子的：

当然，它其实就是一张图片而已。这样做纯粹是为了好看。这里探讨的不是怎么设计这种按钮，而是怎么在网页里把它做出来。这里要提几个要求：
A. 语义化。如果这个按钮叫“完成注册”，就要在HTML中写出这四个字，以保证只读HTML的情况下也知道这个按钮是什么文字。
B. display:inline。用display:block可以很容易的调整大小。但是如果一横排并列两个按钮，就比较难解决。用float?不好。万一我需要两个按钮并排，且居中，用float会增加更多额外的代码。
C.理所当然，跨平台兼容性。所以inline-block的想法，在IE6上就行不通。
有几种方法可以做这种按钮：
1. 用image类型的input标签，或是button标签。这样做最大的问题是，必须在HTML里引用图片地址。我个人是倾向于不要将修饰图片地址放在HTML代码里。结构和表现要分离嘛。此外，用button环绕img，你会惹一堆布局上的麻烦。
2. 用a标签，CSS加背景。这种方法挺容易。但是有几个问题：
   a) 对inline的a标签设置高宽，你会遇到一堆麻烦事儿。
   b) 此外，为了达到要求A，需要在a里面写入文字，并且将文字隐藏掉。这里如果用text-indent的话，就不能用inline了。另外一个方法是vertical-align，但是，这个属性基本上被我废止。原因是vista里，用微软雅黑及vertical-align，你会遇到很可怕的事情。记住要求C：跨平台兼容性。
   c) 用a标签，你还得写JS来提交表单，麻烦。
3. a标签环绕图片。这个同样不是太好，理由在1和2里都有讲。（但它倒是可以满足要求B：display:inline）
4. 用buton类型的input，加CSS背景。这种方法看上去是可以满足要求A和B。关键的问题是：在保证跨平台兼容性的同时，如何隐藏掉button的文字。
我这里给出一个比较好的方法：

input {
&#160;&#160;&#160;&#160;border:none;
&#160;&#160;&#160;&#160;width:120px;
&#160;&#160;&#160;&#160;height:24px;
&#160;&#160;&#160;&#160;background:url(http://www.mikkolee.com/blog/wp-content/uploads/2008/11/login.png) no-repeat 0 0;
&#160;&#160;&#160;&#160;text-indent:-3000px;
&#160;&#160;&#160;&#160;overflow:hidden;
&#160;&#160;&#160;&#160;cursor:pointer;
}
* input {*text-indent: 0;*padding:0 0 0 120px;}  /*hacked for IE*/

解释一下：在FF3和Chrome中，将按钮的text-indent设为-3000px，就可以将文字隐藏。但同样的设置在IE下，会导致按钮本身也跟着跑到-3000px的位置去，除非按钮被声明为display:block（但这就不满足要求B了）。
对此有一个巧妙的解决办法：首先用hack在IE里将text-indent恢复。然后再将左padding设置成120px，和width一样。这个方法之所以很妙，是因为，无论在哪个浏览器下。所以将左padding设为和width一样宽，会将真正的文字空间压缩到0！。
但是这个解决办法在FF中却会有问题。原因是，即使文字空间压缩到0，FF仍然会将文字显示出来，而不受overflow的影响（事实上这样处理是符合标准的，理由自己思考一下）。所以仍然要写text-indent。
还有一个问题是，在Opera里，左padding要设为差不多180才能将文字隐藏。原因不详。至少我用的9.2版本是如此。所以上面的代码在Opera中并不兼容，需要再单独为Opera做hack。
还有一层更深入的思考：那为啥不就将padding: 0 0 0 180px以正常的形式写到CSS中呢？这个就作为思考题啦，提示一下，180px会对FF造成不利影响。
综上呢，我给的代码是多一不可，缺一不可的（当然，我没写对Opera的变态hack，因为这家伙已经开始背叛标准了，而且不同版本之间兼容性很差，所以放弃掉它）。
此外还可以补充一下，cursor:pointer是为了增强可用性。这是个很奇怪UX问题，如果是正常的button，鼠标不改变，也不会觉得奇怪。但是如果按钮没有突起感，鼠标移上之后不变形，就会感觉是不可点。
]]></description>
			<content:encoded><![CDATA[<p>图形化按钮，就类似这个样子的：</p>
<p><img src="http://www.mikkolee.com/blog/wp-content/uploads/2008/11/login.png" alt=""  width="120" height="24" /></p>
<p>当然，它其实就是一张图片而已。这样做纯粹是为了好看。这里探讨的不是怎么设计这种按钮，而是怎么在网页里把它做出来。这里要提几个要求：<br />
A. 语义化。如果这个按钮叫“完成注册”，就要在HTML中写出这四个字，以保证只读HTML的情况下也知道这个按钮是什么文字。<br />
B. display:inline。用display:block可以很容易的调整大小。但是如果一横排并列两个按钮，就比较难解决。用float?不好。万一我需要两个按钮并排，且居中，用float会增加更多额外的代码。<br />
C.理所当然，跨平台兼容性。所以inline-block的想法，在IE6上就行不通。</p>
<p>有几种方法可以做这种按钮：<br />
1. 用image类型的input标签，或是button标签。这样做最大的问题是，必须在HTML里引用图片地址。我个人是倾向于不要将修饰图片地址放在HTML代码里。结构和表现要分离嘛。此外，用button环绕img，你会惹一堆布局上的麻烦。</p>
<p>2. 用a标签，CSS加背景。这种方法挺容易。但是有几个问题：<br />
   a) 对inline的a标签设置高宽，你会遇到一堆麻烦事儿。<br />
   b) 此外，为了达到要求A，需要在a里面写入文字，并且将文字隐藏掉。这里如果用text-indent的话，就不能用inline了。另外一个方法是vertical-align，但是，这个属性基本上被我废止。原因是vista里，用微软雅黑及vertical-align，你会遇到<a href="http://www.google.cn/search?hl=zh-CN&#038;newwindow=1&#038;q=vertical-align+%E5%BE%AE%E8%BD%AF%E9%9B%85%E9%BB%91&#038;meta=&#038;aq=f&#038;oq=">很可怕的事情</a>。记住要求C：跨平台兼容性。<br />
   c) 用a标签，你还得写JS来提交表单，麻烦。</p>
<p>3. a标签环绕图片。这个同样不是太好，理由在1和2里都有讲。（但它倒是可以满足要求B：display:inline）</p>
<p>4. 用buton类型的input，加CSS背景。这种方法看上去是可以满足要求A和B。关键的问题是：在保证跨平台兼容性的同时，如何隐藏掉button的文字。</p>
<p>我这里给出一个比较好的方法：</p>
<pre>
input {
&nbsp;&nbsp;&nbsp;&nbsp;border:none;
&nbsp;&nbsp;&nbsp;&nbsp;width:120px;
&nbsp;&nbsp;&nbsp;&nbsp;height:24px;
&nbsp;&nbsp;&nbsp;&nbsp;background:url(http://www.mikkolee.com/blog/wp-content/uploads/2008/11/login.png) no-repeat 0 0;
&nbsp;&nbsp;&nbsp;&nbsp;text-indent:-3000px;
&nbsp;&nbsp;&nbsp;&nbsp;overflow:hidden;
&nbsp;&nbsp;&nbsp;&nbsp;cursor:pointer;
}
* input {*text-indent: 0;*padding:0 0 0 120px;}  /*hacked for IE*/
</pre>
<p>解释一下：在FF3和Chrome中，将按钮的text-indent设为-3000px，就可以将文字隐藏。但同样的设置在IE下，会导致按钮本身也跟着跑到-3000px的位置去，除非按钮被声明为display:block（但这就不满足要求B了）。</p>
<p>对此有一个巧妙的解决办法：首先用hack在IE里将text-indent恢复。然后再将左padding设置成120px，和width一样。这个方法之所以很妙，是因为<strong>按钮是唯一一个不遵守盒模型的元素</strong>，无论在哪个浏览器下。所以将左padding设为和width一样宽，会将真正的文字空间压缩到0！。</p>
<p>但是这个解决办法在FF中却会有问题。原因是，即使文字空间压缩到0，FF仍然会将文字显示出来，而不受overflow的影响（事实上这样处理是符合标准的，理由自己思考一下）。所以仍然要写text-indent。</p>
<p>还有一个问题是，在Opera里，左padding要设为差不多180才能将文字隐藏。原因不详。至少我用的9.2版本是如此。所以上面的代码在Opera中并不兼容，需要再单独为Opera做hack。</p>
<p>还有一层更深入的思考：那为啥不就将padding: 0 0 0 180px以正常的形式写到CSS中呢？这个就作为思考题啦，提示一下，180px会对FF造成不利影响。</p>
<p>综上呢，我给的代码是多一不可，缺一不可的（当然，我没写对Opera的变态hack，因为这家伙已经开始背叛标准了，而且不同版本之间兼容性很差，所以放弃掉它）。</p>
<p>此外还可以补充一下，cursor:pointer是为了增强可用性。这是个很奇怪UX问题，如果是正常的button，鼠标不改变，也不会觉得奇怪。但是如果按钮没有突起感，鼠标移上之后不变形，就会感觉是不可点。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikkolee.com/73/feed</wfw:commentRss>
		</item>
		<item>
		<title>从“Browser”说起</title>
		<link>http://www.mikkolee.com/70</link>
		<comments>http://www.mikkolee.com/70#comments</comments>
		<pubDate>Tue, 11 Nov 2008 16:06:03 +0000</pubDate>
		<dc:creator>小麦</dc:creator>
		
		<category><![CDATA[用户体验]]></category>

		<guid isPermaLink="false">http://www.mikkolee.com/?p=70</guid>
		<description><![CDATA[今天回家路上突然想到的。
我们用来看网页的那个软件，叫什么，什么来着？“浏览器”。它是从“Browser”翻译过来的。什么叫“浏览”？躺在床上细细阅读就不算浏览。浏览就是路过报摊看见一本杂志，拿起来随便翻翻，看看有没有好看的内容。这就叫“浏览”。
不知道当初是谁起的这个名字，很妙。为啥不叫“阅读器”，或是“观看器”？因为网页是用“浏览”的~这是网页可用性原则的基础。由此才会衍生出其他的如“Don&#8217;t make me think”或“将字数减一半，再把剩下的减一半”之类的可用性准则。
在十几年前，开山鼻祖们就用Browser这个名词告诉我们，网页是用“浏览”的。他们真强！
]]></description>
			<content:encoded><![CDATA[<p>今天回家路上突然想到的。</p>
<p>我们用来看网页的那个软件，叫什么，什么来着？“浏览器”。它是从“Browser”翻译过来的。什么叫“浏览”？躺在床上细细阅读就不算浏览。浏览就是路过报摊看见一本杂志，拿起来随便翻翻，看看有没有好看的内容。这就叫“浏览”。</p>
<p>不知道当初是谁起的这个名字，很妙。为啥不叫“阅读器”，或是“观看器”？因为网页是用“浏览”的~这是网页可用性原则的基础。由此才会衍生出其他的如“Don&#8217;t make me think”或“将字数减一半，再把剩下的减一半”之类的可用性准则。</p>
<p>在十几年前，开山鼻祖们就用Browser这个名词告诉我们，网页是用“浏览”的。他们真强！</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikkolee.com/70/feed</wfw:commentRss>
		</item>
		<item>
		<title>配色字典（一）</title>
		<link>http://www.mikkolee.com/44</link>
		<comments>http://www.mikkolee.com/44#comments</comments>
		<pubDate>Fri, 12 Sep 2008 15:32:26 +0000</pubDate>
		<dc:creator>小麦</dc:creator>
		
		<category><![CDATA[以色列]]></category>

		<guid isPermaLink="false">http://www.mikkolee.com/?p=44</guid>
		<description><![CDATA[





]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.mikkolee.com/blog/wp-content/uploads/2008/09/1.jpg" alt="" title="1" width="440" height="440" class="alignnone size-full wp-image-45" /></p>
<p><img src="http://www.mikkolee.com/blog/wp-content/uploads/2008/09/2.jpg" alt="" title="2" width="440" height="440" class="alignnone size-full wp-image-46" /></p>
<p><img src="http://www.mikkolee.com/blog/wp-content/uploads/2008/09/3.jpg" alt="" title="3" width="440" height="440" class="alignnone size-full wp-image-47" /></p>
<p><img src="http://www.mikkolee.com/blog/wp-content/uploads/2008/09/4.jpg" alt="" title="4" width="440" height="440" class="alignnone size-full wp-image-48" /></p>
<p><img src="http://www.mikkolee.com/blog/wp-content/uploads/2008/09/5.jpg" alt="" title="5" width="440" height="440" class="alignnone size-full wp-image-49" /></p>
<p><img src="http://www.mikkolee.com/blog/wp-content/uploads/2008/09/6.jpg" alt="" title="6" width="440" height="440" class="alignnone size-full wp-image-50" /></p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikkolee.com/44/feed</wfw:commentRss>
		</item>
		<item>
		<title>上海地铁自动售票机（续）</title>
		<link>http://www.mikkolee.com/43</link>
		<comments>http://www.mikkolee.com/43#comments</comments>
		<pubDate>Mon, 08 Sep 2008 14:02:36 +0000</pubDate>
		<dc:creator>小麦</dc:creator>
		
		<category><![CDATA[交互设计]]></category>

		<guid isPermaLink="false">http://www.mikkolee.com/?p=43</guid>
		<description><![CDATA[将关于自动售票机的交互问题分享给了几个朋友。都是非专业的朋友，这样我可以更清楚的了解一般用户的使用习惯。
让我很意外的是，事实上并没有如我所想的那么多人觉得自动售票机不好用。而下意识先投硬币的人，告诉我他怀疑是因为界面设计得让人不想点，所以才先投硬币的。这个原因是有可能的。一个类比的例子就是游戏机。游戏机会不停的闪动一些游戏的片段，当你投币之后，才会一下子跳到一个可操作界面。回头我还是拍一张自动售票机的待机画面，看看是不是让人不想点。
此外不少人认为就应该先选目的地，然后根据票价投硬币。看来按照售票台的购买流程设计的交互，还是可以得到很多人的认可的。不过这里又出现一个新的问题，到底该如何选择目的地？
假设，张泽是一个初次来上海找工作的大学毕业生，他之前从来没有坐过地铁。今天要去参加上海体育馆的人才招聘会，通知上告诉他，可以坐地铁到“上海体育馆站”下。当他走到地铁的自动售票机前，想要找到“上海体育馆”。但是按照现在自动售票机的交互，必须先选择线路，再选择站名。那请问，“上海体育馆”在哪条线上？所以他只能问旁人。或者，从一号线开始找&#8230;呵呵很幸运，就是在一号线上，可是一号线上有20多个站，很担心他是否能找到。
所以一个可替代的方案是，直接将所有的站名全部列出来，并按照音序排序。张泽第一眼就看见“黄陂南路”，马上可以推断“上海体育馆”在它的后面，再继续找下去&#8230;
音序排序是个不错的方案。但是李翠红是一个来上海打工的农村姑娘。她要去看她的亲戚。她从来信上得知，那个地方叫“颛桥”。请问有谁知道“颛桥”是排在“莘庄”前面，还是后面？
所以，或许，按照笔画排序才是个不错的方案？OK，那请告诉我，“衡山路”是几画？那个鱼字头和下面的“大”字到底是连在一起写还是分开写？
很遗憾，我确实也没想出一个很好的办法。最好的办法还是问售票员。
]]></description>
			<content:encoded><![CDATA[<p>将关于自动售票机的交互问题分享给了几个朋友。都是非专业的朋友，这样我可以更清楚的了解一般用户的使用习惯。</p>
<p>让我很意外的是，事实上并没有如我所想的那么多人觉得自动售票机不好用。而下意识先投硬币的人，告诉我他怀疑是因为界面设计得让人不想点，所以才先投硬币的。这个原因是有可能的。一个类比的例子就是游戏机。游戏机会不停的闪动一些游戏的片段，当你投币之后，才会一下子跳到一个可操作界面。回头我还是拍一张自动售票机的待机画面，看看是不是让人不想点。</p>
<p>此外不少人认为就应该先选目的地，然后根据票价投硬币。看来按照售票台的购买流程设计的交互，还是可以得到很多人的认可的。不过这里又出现一个新的问题，到底该如何选择目的地？</p>
<p>假设，张泽是一个初次来上海找工作的大学毕业生，他之前从来没有坐过地铁。今天要去参加上海体育馆的人才招聘会，通知上告诉他，可以坐地铁到“上海体育馆站”下。当他走到地铁的自动售票机前，想要找到“上海体育馆”。但是按照现在自动售票机的交互，必须先选择线路，再选择站名。那请问，“上海体育馆”在哪条线上？所以他只能问旁人。或者，从一号线开始找&#8230;呵呵很幸运，就是在一号线上，可是一号线上有20多个站，很担心他是否能找到。</p>
<p>所以一个可替代的方案是，直接将所有的站名全部列出来，并按照音序排序。张泽第一眼就看见“黄陂南路”，马上可以推断“上海体育馆”在它的后面，再继续找下去&#8230;</p>
<p>音序排序是个不错的方案。但是李翠红是一个来上海打工的农村姑娘。她要去看她的亲戚。她从来信上得知，那个地方叫“颛桥”。请问有谁知道“颛桥”是排在“莘庄”前面，还是后面？</p>
<p>所以，或许，按照笔画排序才是个不错的方案？OK，那请告诉我，“衡山路”是几画？那个鱼字头和下面的“大”字到底是连在一起写还是分开写？</p>
<p>很遗憾，我确实也没想出一个很好的办法。最好的办法还是问售票员。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikkolee.com/43/feed</wfw:commentRss>
		</item>
		<item>
		<title>上海地铁的自动贩卖机</title>
		<link>http://www.mikkolee.com/40</link>
		<comments>http://www.mikkolee.com/40#comments</comments>
		<pubDate>Fri, 05 Sep 2008 15:21:16 +0000</pubDate>
		<dc:creator>小麦</dc:creator>
		
		<category><![CDATA[交互设计]]></category>

		<guid isPermaLink="false">http://www.mikkolee.com/?p=40</guid>
		<description><![CDATA[说说上海地铁的自动售票机。如果有用过的人，应该都会觉得它的交互很糟糕。我先简单扫盲一下。
走进自动售票机，第一步是选择你的目的地是在哪条线上（我忘记拍照了）。
第二步如下图，选择你的目的地。

第三步，它会问你要几张票。

第四步，投币或塞钞票。
第五步，它会吐出票，找零。
这个交互流程我讲起来好像还可以。但是你亲自去用用，就会发现问题。因为几乎所有的人到它面前，一开始就想把钱塞进去。然后发现塞不进去。按我上面给的“正确”流程，塞钱其实是在倒数第二步才要求的，而之前你要回答三个问题。这个流程让人不舒服。因为饮料贩卖机是先投币再选罐子，公用电话是先投币再拨号，自动取款机是先插卡再输金额，都是。偏偏这个自动售票机是反过来的。难怪难到一堆人。
不过问题还没完。为什么自动售票机的设计者会采用这么一个“非主流”的流程呢？
道理很简单。你去站台买票是怎么买的？走进窗口，对服务员讲：我要到中山公园。她问你要几张，你说一张。然后把钱交给她，她给你票和找零。对不对？所以自动售票机的交互流程是在模拟售票员售票！
这样看起来，其实自动售票机才是正确的咯？当然！你去便利店买饮料，难道不是先选饮料，再付钱么？你去烟酒摊上打电话，难道不是先打电话再交钱么？你去银行取钱，难道不是先填取款单然后再递存折么？！！所有的自动服务机器都在按照一个悖于普通流程的方式在提供交互，只有上海地铁的自动售票机做对了！
那为什么只有上海地铁的自动售票机让人觉得很难用呢？说实话，我也不知道。但是我可以用另外一个例子来给出一个可能的解释：我们用的键盘，当初是为了让打字机不卡纸，才排成这样的布局的。但事实上科学研究证明，标准键盘的布局是所有组合中最难用的一种。但是，有哪个厂家敢改变这个布局，用一个“更好用”的布局？
]]></description>
			<content:encoded><![CDATA[<p>说说上海地铁的自动售票机。如果有用过的人，应该都会觉得它的交互很糟糕。我先简单扫盲一下。</p>
<p>走进自动售票机，第一步是选择你的目的地是在哪条线上（我忘记拍照了）。</p>
<p>第二步如下图，选择你的目的地。<br />
<img src="http://www.mikkolee.com/blog/wp-content/uploads/2008/09/200809051350.jpg" alt="" title="上海地铁" width="400" height="300" class="alignnone size-full wp-image-41" /></p>
<p>第三步，它会问你要几张票。<br />
<img src="http://www.mikkolee.com/blog/wp-content/uploads/2008/09/200809051351.jpg" alt="" title="上海地铁" width="400" height="300" class="alignnone size-full wp-image-42" /></p>
<p>第四步，投币或塞钞票。</p>
<p>第五步，它会吐出票，找零。</p>
<p>这个交互流程我讲起来好像还可以。但是你亲自去用用，就会发现问题。因为几乎所有的人到它面前，一开始就想把钱塞进去。然后发现塞不进去。按我上面给的“正确”流程，塞钱其实是在倒数第二步才要求的，而之前你要回答三个问题。这个流程让人不舒服。因为饮料贩卖机是先投币再选罐子，公用电话是先投币再拨号，自动取款机是先插卡再输金额，都是<strong>“先付出，再提要求”</strong>。偏偏这个自动售票机是反过来的。难怪难到一堆人。</p>
<p>不过问题还没完。为什么自动售票机的设计者会采用这么一个“非主流”的流程呢？</p>
<p>道理很简单。你去站台买票是怎么买的？走进窗口，对服务员讲：我要到中山公园。她问你要几张，你说一张。然后把钱交给她，她给你票和找零。对不对？所以自动售票机的交互流程是在模拟售票员售票！</p>
<p>这样看起来，其实自动售票机才是正确的咯？当然！你去便利店买饮料，难道不是先选饮料，再付钱么？你去烟酒摊上打电话，难道不是先打电话再交钱么？你去银行取钱，难道不是先填取款单然后再递存折么？！！所有的自动服务机器都在按照一个悖于普通流程的方式在提供交互，只有上海地铁的自动售票机做对了！</p>
<p>那为什么只有上海地铁的自动售票机让人觉得很难用呢？说实话，我也不知道。但是我可以用另外一个例子来给出一个可能的解释：我们用的键盘，当初是为了让打字机不卡纸，才排成这样的布局的。但事实上科学研究证明，标准键盘的布局是所有组合中最难用的一种。但是，有哪个厂家敢改变这个布局，用一个“更好用”的布局？</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikkolee.com/40/feed</wfw:commentRss>
		</item>
		<item>
		<title>网页用户体验的“常识”</title>
		<link>http://www.mikkolee.com/39</link>
		<comments>http://www.mikkolee.com/39#comments</comments>
		<pubDate>Thu, 04 Sep 2008 15:51:53 +0000</pubDate>
		<dc:creator>小麦</dc:creator>
		
		<category><![CDATA[用户体验]]></category>

		<category><![CDATA[常识]]></category>

		<guid isPermaLink="false">http://www.mikkolee.com/?p=39</guid>
		<description><![CDATA[我爸今年55岁，在家里没事儿，就喜欢捣腾我给他买的电脑。遇到不懂的就打电话给我，非常勤学好问爱思考。下面是某一次对话：
“那个QQ怎么聊天？”
“哦，你找到那个企鹅的图标了吗？”
“&#8230;（2分钟后）找到了，然后呢？”
“&#8230;打开它。”
“怎么打开？”
“&#8230;把鼠标移到上面，然后点击图标”
“左键还是右键？”
“左键&#8230;”
“单击还是双击？”
“双击&#8230;”
“怎么没反应？”
“你可能双击得太慢了，要快一点”
“哦&#8230;还是没反应。”
“鼠标变成漏斗了么？”
“嗯”
“那就是反应，等吧”
&#8230;
好吧，就到此为止。这其实是一个很有趣的案例。它很直观的揭示了一个道理：其实任何用户体验的评价都是基于用户了解一些很基本的“常识”。而这些“常识”，其实并非是真正的基于本能的常识，而是一些外部获取知识。以至于我爸问出“左键还是右键”“单击还是双击” 的时候，我们会很震惊。事实上，类似的“常识”还有很多。就以Web来说，就可以列举出如下：

“网页”的概念。看一下，你就明白这个概念对于不上网的人来说其实并非“常识”。将一个Web画面类比成Page是一个很不错的创意。坦率的说，将浏览器里的画面都定义为“网页”是不准确的。比如弹出窗，就不大像是一个“页面”。还有整站Flash的动画，似乎也不能称作是页面。
“网址”的概念。事实上，我认为把它叫做“频道”更恰当。因为URL对应网站，跟电视里的频道对应电视台的关系是一样的。可打开网页偏偏要被形象为“访问”网站，所以“地址”这个概念就出来了。
“手型”鼠标表示可以点击。这其实是个很另类的“常识”，因为除了网页，没有任何软件、操作系统有这样的惯例。软件里面可以点击的部分，从来不需要将鼠标变成手型。甚至网页本身，按钮其实是可以点击的，但是鼠标移上去之后并没有出现手型。
“登录”的概念。这个词本身就很古怪。你要怎么解释登录这个概念？类似的还有“退出”。

所以，当我们做网页界面的时候，不停的引用这些“惯例”作为支持自己方案的理由，有没有停下来想一下，遵循这些“惯例”，或是说常识，凭什么就一定可以给出良好的用户体验？尤其对我爸这样的“骨灰级菜鸟”用户而言。
最后，作为交互设计师，如果能有一个像我这样的老爸，那将是很大的幸运。
]]></description>
			<content:encoded><![CDATA[<p>我爸今年55岁，在家里没事儿，就喜欢捣腾我给他买的电脑。遇到不懂的就打电话给我，非常勤学好问爱思考。下面是某一次对话：</p>
<p>“那个QQ怎么聊天？”<br />
“哦，你找到那个企鹅的图标了吗？”<br />
“&#8230;（2分钟后）找到了，然后呢？”<br />
“&#8230;打开它。”<br />
“怎么打开？”<br />
“&#8230;把鼠标移到上面，然后点击图标”<br />
“左键还是右键？”<br />
“左键&#8230;”<br />
“单击还是双击？”<br />
“双击&#8230;”<br />
“怎么没反应？”<br />
“你可能双击得太慢了，要快一点”<br />
“哦&#8230;还是没反应。”<br />
“鼠标变成漏斗了么？”<br />
“嗯”<br />
“那就是反应，等吧”<br />
&#8230;</p>
<p>好吧，就到此为止。这其实是一个很有趣的案例。它很直观的揭示了一个道理：其实任何用户体验的评价都是基于用户了解一些很基本的“常识”。而这些“常识”，其实并非是真正的基于本能的常识，而是一些外部获取知识。以至于我爸问出“左键还是右键”“单击还是双击” 的时候，我们会很震惊。事实上，类似的“常识”还有很多。就以Web来说，就可以列举出如下：</p>
<ol>
<li>“网页”的概念。看一下<a href="=http://baike.baidu.com/view/828.html?wtp=tt">这里</a>，你就明白这个概念对于不上网的人来说其实并非“常识”。将一个Web画面类比成Page是一个很不错的创意。坦率的说，将浏览器里的画面都定义为“网页”是不准确的。比如弹出窗，就不大像是一个“页面”。还有整站Flash的动画，似乎也不能称作是页面。</li>
<li>“网址”的概念。事实上，我认为把它叫做“频道”更恰当。因为URL对应网站，跟电视里的频道对应电视台的关系是一样的。可打开网页偏偏要被形象为“访问”网站，所以“地址”这个概念就出来了。</li>
<li>“手型”鼠标表示可以点击。这其实是个很另类的“常识”，因为除了网页，没有任何软件、操作系统有这样的惯例。软件里面可以点击的部分，从来不需要将鼠标变成手型。甚至网页本身，按钮其实是可以点击的，但是鼠标移上去之后并没有出现手型。</li>
<li>“登录”的概念。这个词本身就很古怪。你要怎么解释登录这个概念？类似的还有“退出”。</li>
</ol>
<p>所以，当我们做网页界面的时候，不停的引用这些“惯例”作为支持自己方案的理由，有没有停下来想一下，遵循这些“惯例”，或是说常识，凭什么就一定可以给出良好的用户体验？尤其对我爸这样的“骨灰级菜鸟”用户而言。</p>
<p>最后，作为交互设计师，如果能有一个像我这样的老爸，那将是很大的幸运。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikkolee.com/39/feed</wfw:commentRss>
		</item>
		<item>
		<title>两个值得表扬的细节</title>
		<link>http://www.mikkolee.com/36</link>
		<comments>http://www.mikkolee.com/36#comments</comments>
		<pubDate>Wed, 03 Sep 2008 15:26:18 +0000</pubDate>
		<dc:creator>小麦</dc:creator>
		
		<category><![CDATA[用户体验]]></category>

		<category><![CDATA[Firefox3]]></category>

		<category><![CDATA[Google Chrome]]></category>

		<guid isPermaLink="false">http://www.mikkolee.com/?p=36</guid>
		<description><![CDATA[Google不负众望的发布了Chrome。据说它的目标是抢占20%的市场。有趣的在于，它想抢谁的20%？目前看起来，恐怕更是Firefox的那一块吧~~阔别十年的浏览器战国时代快拉开序幕了。呵呵。
不过比起Google其他的产品糟糕的UX，Chrome确实让我看到了他们的用心。只讲其中一个细节：

这点之所以让我很打击，是因为为什么我从来没有想到过，可以把Tab放在顶上。所有的浏览器都把Tab放在菜单栏、工具栏和地址栏的下方。
OK，那放上面有什么了不起？第一个优点就是，切换起来会非常顺手。我再也不需要在杂乱的菜单工具或地址栏里寻找Tab了。
而第二个优点是，它其实暗示了一个概念：一个Tab代表并不只是一个“页面视区”，而是Tab以下的整个窗口。这个概念对应着一个强大的功能：就如同Photoshop里的浮动工具栏一样，可以将Tab拉出来成为独立窗口，也可以将独立的窗口再合并进Tab。
另外再讲一个Firefox 3在UI上的一个好细节：它的“后退”按钮。

将“后退”按钮变大，其实应该是一个很理所当然的事情啊。因为对于浏览器来说，除了地址栏边上的“转到（GO）”按钮，就数这个“后退”按钮使用得最频繁了，甚至比前者用得更多。将它放大，而且比“前进”按钮更大，是一个“情理之中”的“突破设计”。
不过顺带批评一句，Firefox没有新建Tab的按钮，比较败笔。
]]></description>
			<content:encoded><![CDATA[<p>Google不负众望的发布了Chrome。据说它的目标是抢占20%的市场。有趣的在于，它想抢谁的20%？目前看起来，恐怕更是Firefox的那一块吧~~阔别十年的浏览器战国时代快拉开序幕了。呵呵。</p>
<p>不过比起Google其他的产品糟糕的UX，Chrome确实让我看到了他们的用心。只讲其中一个细节：<strong>它的tab居然放在顶部！</strong></p>
<p><img src="http://www.mikkolee.com/blog/wp-content/uploads/2008/09/google_chrome.png" alt="Google Chrome" title="google Chrome" width="335" height="78" /></p>
<p>这点之所以让我很打击，是因为为什么我从来没有想到过，可以把Tab放在顶上。所有的浏览器都把Tab放在菜单栏、工具栏和地址栏的下方。</p>
<p>OK，那放上面有什么了不起？第一个优点就是，切换起来会非常顺手。我再也不需要在杂乱的菜单工具或地址栏里寻找Tab了。</p>
<p>而第二个优点是，它其实暗示了一个概念：一个Tab代表并不只是一个“页面视区”，而是Tab以下的整个窗口。这个概念对应着一个强大的功能：<strong>这个Tab是可以拉出来单独成为一个窗口！</strong>就如同Photoshop里的浮动工具栏一样，可以将Tab拉出来成为独立窗口，也可以将独立的窗口再合并进Tab。</p>
<p>另外再讲一个Firefox 3在UI上的一个好细节：它的“后退”按钮。</p>
<p><img src="http://www.mikkolee.com/blog/wp-content/uploads/2008/09/firefox.png" alt="Firefox 3" title="Firefox 3" width="214" height="131" /></p>
<p>将“后退”按钮变大，其实应该是一个很理所当然的事情啊。因为对于浏览器来说，除了地址栏边上的“转到（GO）”按钮，就数这个“后退”按钮使用得最频繁了，甚至比前者用得更多。将它放大，而且比“前进”按钮更大，是一个“情理之中”的“突破设计”。</p>
<p>不过顺带批评一句，Firefox没有新建Tab的按钮，比较败笔。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikkolee.com/36/feed</wfw:commentRss>
		</item>
	</channel>
</rss>
