<?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:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>为之漫笔 &#187; Web开发</title>
	<atom:link href="http://www.cn-cuckoo.com/category/web/feed" rel="self" type="application/rss+xml" />
	<link>http://www.cn-cuckoo.com</link>
	<description>为之漫笔（李松峰），本博客专注于Web前后端技术、移动平台开发技术、交互设计和技术翻译。声明一下，因为时常需要外出审稿，而且基本不带笔记本，所以有时可能会迟一点回复大家的留言。</description>
	<lastBuildDate>Mon, 12 Dec 2011 01:43:07 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>使用JavaScript和Canvas开发游戏（五）</title>
		<link>http://www.cn-cuckoo.com/2011/08/17/game-development-with-javascript-and-the-canvas-element-5-2645.html</link>
		<comments>http://www.cn-cuckoo.com/2011/08/17/game-development-with-javascript-and-the-canvas-element-5-2645.html#comments</comments>
		<pubDate>Wed, 17 Aug 2011 00:22:03 +0000</pubDate>
		<dc:creator>为之漫笔</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[编程技术]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://www.cn-cuckoo.com/?p=2645</guid>
		<description><![CDATA[原文作者：Matthew Casperson • 编辑：Michele McDonough 原文链接: Game Development with JavaScript and the Canvas element 1、认识一下Canvas 2、在Canvas上绘图 3、通过Canvas元素实现高级图像操作 4、写一个游戏框架（一） 5、写一个游戏框架（二） 6、通过Canvas实现视差滚动 7、动画 8、JavaScript键盘输入 9、综合运用 10、定义级别 11、跳跃与坠落 12、添加道具 13、加载资源 14、添加主菜单 在Canvas元素上实现视差滚动 http://www.brighthub.com/internet/web-development/articles/40511.aspx 视差滚动是在2D应用中创造立体纵深感的一种技术。这篇文章就来看一看在我们刚刚创建的游戏框架基础上实现视差滚动有多容易。 视差滚动 有了游戏框架，就可以通过画布元素来做一些好玩的东西了。 视差滚动指的是屏幕上的几个图层发生相对位移的效果，换句话说，背景图层滚动得比它前面的那些图层要慢一些。这种创造视觉纵深感的技术在2D游戏中的应用极为普遍。 RepeatingGameObject.js /** 这个类可以重复显示纹理图像，支持纹理图像在x轴或y轴偏移 @class */ function RepeatingGameObject() { /** 最终图像占据的宽度 @type Number */ this.width = 0; /** 最终图像占据的高度 @type Number */ [...]]]></description>
			<content:encoded><![CDATA[<p>原文作者：Matthew Casperson • 编辑：Michele McDonough<br />
原文链接: <a href="http://www.brighthub.com/hubfolio/matthew-casperson/blog/archive/2009/06/29/game-development-with-javascript-and-the-canvas-element.aspx" target="_blank">Game Development with JavaScript and the Canvas element</a></p>
<p>1、认识一下Canvas<br />
2、在Canvas上绘图<br />
3、通过Canvas元素实现高级图像操作<br />
4、写一个游戏框架（一）<br />
5、写一个游戏框架（二）<br />
6、通过Canvas实现视差滚动<br />
7、动画<br />
8、JavaScript键盘输入<br />
9、综合运用<br />
10、定义级别<br />
11、跳跃与坠落<br />
12、添加道具<br />
13、加载资源<br />
14、添加主菜单</p>
<h1>在Canvas元素上实现视差滚动</h1>
<p><a href="http://www.brighthub.com/internet/web-development/articles/40511.aspx" target="_blank">http://www.brighthub.com/internet/web-development/articles/40511.aspx</a></p>
<p>视差滚动是在2D应用中创造立体纵深感的一种技术。这篇文章就来看一看在我们刚刚创建的游戏框架基础上实现视差滚动有多容易。</p>
<h2>视差滚动</h2>
<p>有了游戏框架，就可以通过画布元素来做一些好玩的东西了。</p>
<p>视差滚动指的是屏幕上的几个图层发生相对位移的效果，换句话说，背景图层滚动得比它前面的那些图层要慢一些。这种创造视觉纵深感的技术在2D游戏中的应用极为普遍。</p>
<h2>RepeatingGameObject.js</h2>
<pre class="brush: js; ">

/**
    这个类可以重复显示纹理图像，支持纹理图像在x轴或y轴偏移
    @class
*/
function RepeatingGameObject()
{
    /** 最终图像占据的宽度
 	@type Number
    */
    this.width = 0;
    /** 最终图像占据的高度
    	@type Number
    */
    this.height = 0;
    /** 绘制时应用多少scrollX和scrollY
	@type Number
    */
    this.scrollFactor = 1;

    /**
        初始化对象
        @return 对初始化对象的引用
    */
    this.startupRepeatingGameObject = function(image, x, y, z, width, height, scrollFactor)
    {
        this.startupVisualGameObject(image, x, y, z);
        this.width = width;
        this.height = height;
        this.scrollFactor = scrollFactor;
        return this;
    }

    /**
        清理对象
    */
    this.shutdownstartupRepeatingGameObject = function()
    {
        this.shutdownVisualGameObject();
    }

	/**
        把当前元素绘制到后台缓冲
        @param dt 自上一帧绘制起经过的秒数
		@param context 绘制上下文
		@param xScroll x轴的全局滚动值
		@param yScroll y轴的全局滚动值

    */
    this.draw = function(dt, canvas, xScroll, yScroll)
    {
        var areaDrawn = [0, 0];

        for (var y = 0; y &lt; this.height; y += areaDrawn[1])
        {
            for (var x = 0; x &lt; this.width; x += areaDrawn[0])
            {
                // 绘制下一张贴片左上角的点
		var newPosition = [this.x + x, this.y + y];
		// 剩余的绘制空间
                var newFillArea = [this.width - x, this.height - y];
		// 第一次必须从图像的中央开始绘制
		// 后续贴片从上方或左侧绘制
                var newScrollPosition = [0, 0];
                if (x==0) newScrollPosition[0] = xScroll * this.scrollFactor;
                if (y==0) newScrollPosition[1] = yScroll * this.scrollFactor;
                areaDrawn = this.drawRepeat(canvas, newPosition, newFillArea, newScrollPosition);
            }
        }
    }

    this.drawRepeat = function(canvas, newPosition, newFillArea, newScrollPosition)
    {
        // 找到重复绘制纹理图像的起点（左上角）
        var xOffset = Math.abs(newScrollPosition[0]) % this.image.width;
        var yOffset = Math.abs(newScrollPosition[1]) % this.image.height;
        var left = newScrollPosition[0]&lt;0?this.image.width-xOffset:xOffset;
        var top = newScrollPosition[1]&lt;0?this.image.height-yOffset:yOffset;
        var width = newFillArea[0] &lt; this.image.width-left?newFillArea[0]:this.image.width-left;
        var height = newFillArea[1] &lt; this.image.height-top?newFillArea[1]:this.image.height-top;

        // 绘制图像
        canvas.drawImage(this.image, left, top, width, height, newPosition[0], newPosition[1], width, height);

        return [width, height];
    }
}
RepeatingGameObject.prototype = new VisualGameObject();
</pre>
<p>这个RepeatingGameObject类可以让图像在一个确定的区域内重复和滚动。此前，我们已经实现了绘制整幅图像。而RepeatingGameObject的不同之处在于，它拿到一幅图像并用它来填充一块范围既定的区域（其尺寸与绘制的图像无关）。我们通过这个类每次显示一幅大图像（如一座山的全景图）的一小部分，从而创建出一个背景。</p>
<p>也许你已经注意到了GameObjectManager的xScroll和yScroll属性，它们被传递给了GameObject的draw和updata函数。这两个值定义的是摄像机沿x轴或y轴移动了多远。RepeatingGameObject使用这两个值来它们显示的纹理，以创造移动的假象。</p>
<p>首先，定义RepeatingGameObject要绘制的区域。底层的GameObject类的x和y属性定义了左上角位置，而新的width和height属性定义的是绘制区域。</p>
<pre class="brush: js; ">

    /** 最终图像占据的宽度
 	@type Number
    */
    this.width = 0;
    /** 最终图像占据的高度
    	@type Number
    */
    this.height = 0;
    /** 绘制时应用多少scrollX和scrollY
	@type Number
    */
</pre>
<p>而scrollFactor属性用于改变RepeatingGameObject滚动的量，该变化是通过传递到draw函数的xScroll和yScroll来控制的。将scrollFactor设置为小于1的值，会导致滚动变慢，从而造就画面中的远景。</p>
<pre class="brush: js; ">

    /** 绘制时应用多少scrollX和scrollY
	@type Number
    */
    this.scrollFactor = 1;
</pre>
<p>最后两个draw和drawRepeat函数具体负责渲染贴片及偏移的纹理。</p>
<pre class="brush: js; ">

	/**
        把当前元素绘制到后台缓冲
        @param dt 自上一帧绘制起经过的秒数
		@param context 绘制上下文
		@param xScroll x轴的全局滚动值
		@param yScroll y轴的全局滚动值

    */
    this.draw = function(dt, canvas, xScroll, yScroll)
    {
        var areaDrawn = [0, 0];

        for (var y = 0; y &lt; this.height; y += areaDrawn[1])
        {
            for (var x = 0; x &lt; this.width; x += areaDrawn[0])
            {
                // 绘制下一张贴片左上角的点
		var newPosition = [this.x + x, this.y + y];
		// 剩余的绘制空间
                var newFillArea = [this.width - x, this.height - y];
		// 第一次必须从图像的中央开始绘制
		// 后续贴片从上方或左侧绘制
                var newScrollPosition = [0, 0];
                if (x==0) newScrollPosition[0] = xScroll * this.scrollFactor;
                if (y==0) newScrollPosition[1] = yScroll * this.scrollFactor;
                areaDrawn = this.drawRepeat(canvas, newPosition, newFillArea, newScrollPosition);
            }
        }
    }

    this.drawRepeat = function(canvas, newPosition, newFillArea, newScrollPosition)
    {
        // 找到重复绘制纹理图像的起点（左上角）
        var xOffset = Math.abs(newScrollPosition[0]) % this.image.width;
        var yOffset = Math.abs(newScrollPosition[1]) % this.image.height;
        var left = newScrollPosition[0]&lt;0?this.image.width-xOffset:xOffset;
        var top = newScrollPosition[1]&lt;0?this.image.height-yOffset:yOffset;
        var width = newFillArea[0] &lt; this.image.width-left?newFillArea[0]:this.image.width-left;
        var height = newFillArea[1] &lt; this.image.height-top?newFillArea[1]:this.image.height-top;

        // 绘制图像
        canvas.drawImage(this.image, left, top, width, height, newPosition[0], newPosition[1], width, height);

        return [width, height];
    }   
</pre>
<h2>ApplicationManager.js</h2>
<pre class="brush: js; ">

/**
    ApplicationManager用于管理应用
    @class
*/
function ApplicationManager()
{
    /**
        初始化对象
        @return A 对初始化对象的引用
    */
    this.startupApplicationManager = function()
    {
        this.startupGameObject();
	this.background3 = new RepeatingGameObject().startupRepeatingGameObject(g_back2, 0, 100, 3, 600, 320, 1);
        this.background2 = new RepeatingGameObject().startupRepeatingGameObject(g_back1, 0, 100, 2, 600, 320, 0.75);
        this.background = new RepeatingGameObject().startupRepeatingGameObject(g_back0, 0, 0, 1, 600, 320, 0.5);
        return this;
    }

	/**
        更新当前对象
        @param dt 自上一帧绘制起经过的秒数
        @param context 绘制上下文
        @param xScroll x轴的全局滚动值
        @param yScroll y轴的全局滚动值
    */
    this.update = function(/**Number*/ dt, /**CanvasRenderingContext2D*/ context, /**Number*/ xScroll, /**Number*/ yScroll)
    {
		g_GameObjectManager.xScroll += 50 * dt;
	}
}
ApplicationManager.prototype = new GameObject
</pre>
<p>在这里，我们通过ApplicationManager创建了三个RepeatingGameObject类的实例，每个实例分别显示为一个图层，使用z（深度）和scrollFactor值来创造RepeatingGameObject 渐远和渐慢的效果。</p>
<p>最终结果很不错。视差滚动为画布赋予了完美的纵深感，而整个效果只多编写了一个类就实现了。</p>
<p>看一看视差滚动的Demo吧。<a href="http://webdemos.sourceforge.net/jsplatformer4/jsplatformer4.html" target="_blank">http://webdemos.sourceforge.net/jsplatformer4/jsplatformer4.html</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.cn-cuckoo.com/2011/08/17/game-development-with-javascript-and-the-canvas-element-5-2645.html/feed</wfw:commentRss>
		<slash:comments>44</slash:comments>
		</item>
		<item>
		<title>使用JavaScript和Canvas开发游戏（四）</title>
		<link>http://www.cn-cuckoo.com/2011/08/15/game-development-with-javascript-and-the-canvas-element-4-2639.html</link>
		<comments>http://www.cn-cuckoo.com/2011/08/15/game-development-with-javascript-and-the-canvas-element-4-2639.html#comments</comments>
		<pubDate>Mon, 15 Aug 2011 11:56:57 +0000</pubDate>
		<dc:creator>为之漫笔</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[编程技术]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://www.cn-cuckoo.com/?p=2639</guid>
		<description><![CDATA[原文作者：Matthew Casperson • 编辑：Michele McDonough 原文链接: Game Development with JavaScript and the Canvas element 1、认识一下Canvas 2、在Canvas上绘图 3、通过Canvas元素实现高级图像操作 4、写一个游戏框架（一） 5、写一个游戏框架（二） 6、通过Canvas实现视差滚动 7、动画 8、JavaScript键盘输入 9、综合运用 10、定义级别 11、跳跃与坠落 12、添加道具 13、加载资源 14、添加主菜单 4、写一个游戏框架（二） 在这篇文章里，我们继续介绍构成这个基本JavaScript游戏框架的其他必要的类。 前一篇文章介绍了GameObjectManager类，该类负责画布的渲染并允许GameObject类更新和删除它们自己。下面就来看一看GameObject类。 GameObject.js /** 游戏中出现的所有元素的基类 @class */ function GameObject() { /** 显示的深度次序。较小的zOrder值表示先渲染，因而会在背景中。 @type Number */ this.zOrder = 0; /** x轴的坐标 @type Number */ this.x = 0; [...]]]></description>
			<content:encoded><![CDATA[<p>原文作者：Matthew Casperson • 编辑：Michele McDonough<br />
原文链接: <a href="http://www.brighthub.com/hubfolio/matthew-casperson/blog/archive/2009/06/29/game-development-with-javascript-and-the-canvas-element.aspx" target="_blank">Game Development with JavaScript and the Canvas element</a></p>
<p>1、认识一下Canvas<br />
2、在Canvas上绘图<br />
3、通过Canvas元素实现高级图像操作<br />
4、写一个游戏框架（一）<br />
5、写一个游戏框架（二）<br />
6、通过Canvas实现视差滚动<br />
7、动画<br />
8、JavaScript键盘输入<br />
9、综合运用<br />
10、定义级别<br />
11、跳跃与坠落<br />
12、添加道具<br />
13、加载资源<br />
14、添加主菜单</p>
<h1>4、写一个游戏框架（二）</h1>
<p>在这篇文章里，我们继续介绍构成这个基本JavaScript游戏框架的其他必要的类。</p>
<p>前一篇文章介绍了GameObjectManager类，该类负责画布的渲染并允许GameObject类更新和删除它们自己。下面就来看一看GameObject类。</p>
<h2>GameObject.js</h2>
<pre class="brush: js; ">

/**
    游戏中出现的所有元素的基类
    @class
*/
function GameObject()
{
    /** 显示的深度次序。较小的zOrder值表示先渲染，因而会在背景中。
        @type Number
    */
    this.zOrder = 0;
    /**
        x轴的坐标
        @type Number
    */
    this.x = 0;
    /**
        y轴的坐标
        @type Number
    */
    this.y = 0;

    /**
        初始化游戏对象，并将其添加到GameObjectManager维护的对象列表中
        @param x        x轴的坐标
        @param y        y轴的坐标
        @param z        元素的z次序（背景元素的z值较小）
    */
    this.startupGameObject = function(/**Number*/ x, /**Number*/ y, /**Number*/ z)
    {
        this.zOrder = z;
        this.x = x;
        this.y = y;
        g_GameObjectManager.addGameObject(this);
        return this;
    }

    /**
        清理当前对象，将其从GameObjectManager维护的对象列表中删除
    */
    this.shutdownGameObject = function()
    {
        g_GameObjectManager.removeGameObject(this);
    }
}
</pre>
<p>这个GameObject类（是一个引擎类）的目的，是为游戏中将会出现的所有对象定义一些共有的属性，包括它们的位置（x和y）和深度（z）。需要注意的是，我们不会直接创建GameObject类的实例，而是会再创建一个类来扩展它。</p>
<p>这个类的x和y坐标值没有什么好说的——就是相应对象左上角位置在画布上的坐标。关键是GameObject中的z值，这个值定义的是对象的深度。理解这个值很重要，这个值较小的GameObject会先绘制到画布上。换句话说，z值较大的GameObject将被绘制到z值较小的GameObject上面。<br />
<span id="more-2639"></span><br />
上一篇文章里介绍过，所有类都是通过一个类似startupClassName的函数完成自身初始化的。因此，GameObject类就有一个名为startupGameObject的函数。在这个函数里，除了初始化所有变量外，还会通过addGameObject函数把当前的GameObject添加到由GameObjectManager维护的GameObject列表中。</p>
<pre class="brush: js; ">

    /**
        初始化游戏对象，并将其添加到GameObjectManager维护的对象列表中
        @param x        x轴的坐标
        @param y        y轴的坐标
        @param z        元素的z次序（背景元素的z值较小）
    */
    this.startupGameObject = function(/**Number*/ x, /**Number*/ y, /**Number*/ z)
    {
        this.zOrder = z;
        this.x = x;
        this.y = y;
        g_GameObjectManager.addGameObject(this);
        return this;
    }
</pre>
<p>函数shutdownGameObject用于清除GameObject。这里所谓的清除，是指GameObject通过removeGameObject函数将自身从GameObjectManager中删除。</p>
<pre class="brush: js; ">

    /**
        清理当前对象，将其从GameObjectManager维护的对象列表中删除
    */
    this.shutdownGameObject = function()
    {
        g_GameObjectManager.removeGameObject(this);
    }
</pre>
<h2>VisualGameObject.js</h2>
<pre class="brush: js; ">

/**
    出现在游戏中的所有元素的基类
    @class
*/
function VisualGameObject()
{
    /**
        由当前对象显示的图像
        @type Image
    */
    this.image = null;

    /**
        将当前元素绘制到后台缓冲
        @param dt 自上一帧绘制起经过的秒数
    */
    this.draw = function(/**Number*/ dt, /**CanvasRenderingContext2D*/ context, /**Number*/ xScroll, /**Number*/ yScroll)
    {
        context.drawImage(this.image, this.x - xScroll, this.y - yScroll);
    }

    /**
        初始化当前对象
        @param image 要显示的图像
    */
    this.startupVisualGameObject = function(/**Image*/ image, /**Number*/ x, /**Number*/ y, /**Number*/ z)
    {
        this.startupGameObject(x, y, z);
        this.image = image;
        return this;
    }

    /**
        清理当前对象
    */
    this.shutdownVisualGameObject = function()
    {
        this.shutdownGameObject();
    }
}
VisualGameObject.prototype = new GameObject;
</pre>
<p>VisualGameObject也是一个引擎类，它扩展了GameObject类，为将在屏幕上绘制的对象定义了更具体的属性和函数。顾名思义，可见对象显然是需要绘制的对象，因此VisualGameObject定义了一个image属性，当把当前对象绘制到后台缓冲时，将以这个属性作为图形的来源。</p>
<pre class="brush: js; ">

    /**
        由当前对象显示的图像
        @type Image
    */
    this.image = null;
</pre>
<p>此外，还需要写几行代码，以便把这个对象实际地绘制到后台缓冲——这就是draw函数了，它接受图像并基于GameObject类中定义的x和y值将其复制到后台缓冲。</p>
<pre class="brush: js; ">

    /**
        将当前元素绘制到后台缓冲
        @param dt 自上一帧绘制起经过的秒数
    */
    this.draw = function(/**Number*/ dt, /**CanvasRenderingContext2D*/ context, /**Number*/ xScroll, /**Number*/ yScroll)
    {
        context.drawImage(this.image, this.x - xScroll, this.y - yScroll);
    }
</pre>
<h2>ApplicationManager.js</h2>
<pre class="brush: js; ">

/**
    ApplicationManager用于管理应用
    @class
*/
function ApplicationManager()
{
    /**
        初始化对象
        @return 对初始化对象的引用
    */
    this.startupApplicationManager = function()
    {
        this.bounce = new Bounce().startupBounce(g_image);
        return this;
    }
}
</pre>
<p>ApplicationManager是第一个应用类，之所以将其归为应用类，是因为它用来定义应用的运行方式，而不是定义与浏览器的底层交互。这个类非常简单，只用来创建并初始化Bounce类的一个新实例。表面上看，创建一个类仅仅是为了创建一个对象有点多此一举。但在更复杂的应用中，把创建和管理游戏对象的逻辑放到一起是很有必要的。</p>
<h2>Bounce.js</h2>
<pre class="brush: js; ">

/**
    测试类，用于演示VisualGameObject类的用法
    @class
*/
function Bounce()
{
	/** x轴的运动方向
        @type Number
    */
	this.xDirection = 1;
	/** y轴的运动方向
        @type Number
    */
	this.yDirection = 1;
	/** 运动速度
        @type Number
    */
	this.speed = 10;

	/**
        初始化对象
        @return 对初始化对象的引用
    */
	this.startupBounce = function(image)
	{
		this.startupVisualGameObject(image, 0, 0, 0);
		return this;
	}

	/**
       更新对象
        @param dt 自上一帧绘制起经过的秒数
        @param context 绘制上下文
        @param xScroll x轴的全局滚动值
        @param yScroll y轴的全局滚动值
    */
	this.update = function (/**Number*/ dt, /**CanvasRenderingContext2D*/context, /**Number*/ xScroll, /**Number*/ yScroll)
	{
		this.x += dt * this.speed * this.xDirection;
		this.y += dt * this.speed * this.yDirection;

		if (this.x &gt;= 450)
		{
			this.x = 450;
			this.xDirection = -1;
		}
		else if (this.x &lt;= 0)
		{
			this.x = 0;
			this.xDirection = 1;
		}

		if (this.y &gt;= 250)
		{
			this.y = 250;
			this.yDirection = -1;
		}
		else if (this.y &lt;= 0)
		{
			this.y = 0;
			this.yDirection = 1;
		}
	}
}
Bounce.prototype = new VisualGameObject;
</pre>
<p>Bounce是第二个应用类，它扩展了VisualGameObject类，并将把自己绘制到屏幕上。Bounce类会显示一幅在屏幕上反弹的图像，效果非常类似第一篇文章中举的例子。这个类是在前面所有类的基础上实现最终动画的关键。</p>
<p>startupBounce函数接受一幅图像，通过调用startupVisualGameObject来初始化这个基本的类。</p>
<pre class="brush: js; ">

	/**
        初始化对象
        @return 对初始化对象的引用
    */
	this.startupBounce = function(image)
	{
		this.startupVisualGameObject(image, 0, 0, 0);
		return this;
	}
</pre>
<p>而update函数（将被GameObjectManager在渲染期间调用）会更新图像的位置，在图像到达画布边缘时反转方向。</p>
<pre class="brush: js; ">

	/**
       更新对象
        @param dt 自上一帧绘制起经过的秒数
        @param context 绘制上下文
        @param xScroll x轴的全局滚动值
        @param yScroll y轴的全局滚动值
    */
	this.update = function (/**Number*/ dt, /**CanvasRenderingContext2D*/context, /**Number*/ xScroll, /**Number*/ yScroll)
	{
		this.x += dt * this.speed * this.xDirection;
		this.y += dt * this.speed * this.yDirection;

		if (this.x &gt;= 450)
		{
			this.x = 450;
			this.xDirection = -1;
		}
		else if (this.x &lt;= 0)
		{
			this.x = 0;
			this.xDirection = 1;
		}

		if (this.y &gt;= 250)
		{
			this.y = 250;
			this.yDirection = -1;
		}
		else if (this.y &lt;= 0)
		{
			this.y = 0;
			this.yDirection = 1;
		}
	}
}
</pre>
<p>就这些了。你可能会想，怎么没有与绘制这个对象有关的代码呢？相应的代码都在VisualGameObject类的draw函数中了。而且，由于VisualGameObject类扩展了GameObject类，所以我们知道每渲染一帧都会调用一次update和draw函数。Bounce类中的所有代码只跟让图像反弹有关，也就是修改变量x和y。</p>
<p>好啦，我们已经创建了一批类，基于这些类也实现了与第一个示例相同的效果。而有了这个框架，再创建游戏就不必因为绘制画布等底层逻辑以及管理游戏对象等问题而重复编码了。</p>
<p>看看示例Demo吧。<a href="http://webdemos.sourceforge.net/jsplatformer3/jsplatformer3.html" target="_blank">http://webdemos.sourceforge.net/jsplatformer3/jsplatformer3.html</a></p>
<p>为之漫笔 最后编辑于：<br />
2011/08/15 @ 22:25</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cn-cuckoo.com/2011/08/15/game-development-with-javascript-and-the-canvas-element-4-2639.html/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>使用JavaScript和Canvas开发游戏（三）</title>
		<link>http://www.cn-cuckoo.com/2011/08/14/game-development-with-javascript-and-the-canvas-element-3-2604.html</link>
		<comments>http://www.cn-cuckoo.com/2011/08/14/game-development-with-javascript-and-the-canvas-element-3-2604.html#comments</comments>
		<pubDate>Sun, 14 Aug 2011 00:16:38 +0000</pubDate>
		<dc:creator>为之漫笔</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[编程技术]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://www.cn-cuckoo.com/?p=2604</guid>
		<description><![CDATA[原文作者：Matthew Casperson • 编辑：Michele McDonough 原文链接: Game Development with JavaScript and the Canvas element 1、认识一下Canvas 2、在Canvas上绘图 3、通过Canvas元素实现高级图像操作 4、写一个游戏框架（一） 5、写一个游戏框架（二） 6、通过Canvas实现视差滚动 7、动画 8、JavaScript键盘输入 9、综合运用 10、定义级别 11、跳跃与坠落 12、添加道具 13、加载资源 14、添加主菜单 4、写一个游戏框架（一） http://www.brighthub.com/internet/web-development/articles/40512.aspx 在知道了如何使用画布元素之后，接下来我教大家写一个框架，有了这个框架，我们就可以把它作为基础来创建游戏。在这第一部分，我们会介绍前两个文件/类。 编写代码之前，我们先来看一看随后几篇文章将致力于创建的示例Demo。表面上看起来，这个Demo跟第二篇文章里的那个没啥区别，但如果你看看后台（查看网页源代码）就会发现，为了更方便地创建这个最终效果，一个凝聚不少心血的基础框架已经写好了。 下面我们要介绍的JavaScript代码使用面向对象的方式来编写。对于没有编写过多少JavaScript代码的人来说，恐怕第一眼看到它们会觉得有点奇怪。如果你真的不太熟悉JavaScript的面向对象编程，建议通过Mozilla Developer Network的这个教程https://developer.mozilla.org/en/Introduction_to_Object-Oriented_JavaScript来补补课。这篇教程里解释了我们稍后会用到的一些编程技术。 从设计思想上来看，这个框架可以分成两部分：与底层的2D引擎交互的类（用于操作画布、控制渲染循环、处理输入等的代码）和用来创建对象以便构成游戏的类。前者可以归为引擎类，后者可以归为应用类。由于应用类要构建于引擎类之上，所以我们需要先来创建引擎类。 Main.js 如果你研究了前面例子中的代码，就会发现Main.js文件中包含了不少代码。 /** 每秒多少帧 @type Number */ var FPS = 30; /** 两帧间间隔的秒数 @type Number */ var SECONDS_BETWEEN_FRAMES = [...]]]></description>
			<content:encoded><![CDATA[<p>原文作者：Matthew Casperson • 编辑：Michele McDonough<br />
原文链接: <a href="http://www.brighthub.com/hubfolio/matthew-casperson/blog/archive/2009/06/29/game-development-with-javascript-and-the-canvas-element.aspx" target="_blank">Game Development with JavaScript and the Canvas element</a></p>
<p>1、认识一下Canvas<br />
2、在Canvas上绘图<br />
3、通过Canvas元素实现高级图像操作<br />
4、写一个游戏框架（一）<br />
5、写一个游戏框架（二）<br />
6、通过Canvas实现视差滚动<br />
7、动画<br />
8、JavaScript键盘输入<br />
9、综合运用<br />
10、定义级别<br />
11、跳跃与坠落<br />
12、添加道具<br />
13、加载资源<br />
14、添加主菜单</p>
<h1>4、写一个游戏框架（一）</h1>
<p><a href="http://www.brighthub.com/internet/web-development/articles/40512.aspx" target="_blank">http://www.brighthub.com/internet/web-development/articles/40512.aspx</a><br />
在知道了如何使用画布元素之后，接下来我教大家写一个框架，有了这个框架，我们就可以把它作为基础来创建游戏。在这第一部分，我们会介绍前两个文件/类。</p>
<p>编写代码之前，我们先来看一看<a href="http://webdemos.sourceforge.net/jsplatformer3/jsplatformer3.html" target="_blank">随后几篇文章将致力于创建的示例Demo</a>。表面上看起来，这个Demo跟第二篇文章里的那个没啥区别，但如果你看看后台（查看网页源代码）就会发现，为了更方便地创建这个最终效果，一个凝聚不少心血的基础框架已经写好了。<br />
<img class="colorbox-2604"  src="/cache/img/2604_1.jpg" /></p>
<p>下面我们要介绍的JavaScript代码使用面向对象的方式来编写。对于没有编写过多少JavaScript代码的人来说，恐怕第一眼看到它们会觉得有点奇怪。如果你真的不太熟悉JavaScript的面向对象编程，建议通过Mozilla Developer Network的这个教程<a href="https://developer.mozilla.org/en/Introduction_to_Object-Oriented_JavaScript" target="_blank">https://developer.mozilla.org/en/Introduction_to_Object-Oriented_JavaScript</a>来补补课。这篇教程里解释了我们稍后会用到的一些编程技术。</p>
<p>从设计思想上来看，这个框架可以分成两部分：与底层的2D引擎交互的类（用于操作画布、控制渲染循环、处理输入等的代码）和用来创建对象以便构成游戏的类。前者可以归为引擎类，后者可以归为应用类。由于应用类要构建于引擎类之上，所以我们需要先来创建引擎类。<br />
<span id="more-2604"></span></p>
<h2>Main.js</h2>
<p>如果你研究了前面例子中的代码，就会发现Main.js文件中包含了不少代码。</p>
<pre class="brush: js; ">

/** 每秒多少帧
    @type Number
*/
var FPS = 30;
/** 两帧间间隔的秒数
    @type Number
*/
var SECONDS_BETWEEN_FRAMES = 1 / FPS;
/** GameObjectManager 实例的全局引用
    @type GameObjectManager
*/
var g_GameObjectManager = null;
/** 应用中用到的图像
    @type Image
*/
var g_image = new Image();
g_image.src = &quot;jsplatformer3-smiley.jpg&quot;;

// 将应用的入口设置为init函数
window.onload = init;

/**
    应用的入口
*/
function init()
{
    new GameObjectManager().startupGameObjectManager();
}
</pre>
<p>首先是定义全局变量的代码。然后，跟以前一样，当页面加载完毕后立即运行init函数。在init函数里，创建GameObjectManager类的实例。</p>
<p>这里在GameObjectManager类的实例上调用了startupGameObjectManager函数。这篇文章以及后面的几篇文章还将多次提到几个命名上具有startupClassName形式的函数。这些函数实际上充当了各自类的构造函数，这样做有两个原因。</p>
<p>首先，JavaScript不支持函数重载（至少不容易实现）。如果你想让一个类有多个构造函数，那么这就成了问题。而通过把构造工作分配给另一组函数（如startupClassName1、startupClassName2），就可以比较容易地定义构造类的不同方式了。</p>
<p>第二个原因（很大程度上也是个人的问题）是我经常会在构造函数中引用尚未定义的变量。这可能是我使用C++、Java和C#这些语言落下的毛病，在这些语言里，类变量在源代码中的位置对其在构造函数中的可见性没有影响。拿下面这个C#类为例：</p>
<pre class="brush: js; ">

class Test
{
	public void Test() {this.a = 5;}
	public int a;
}
</pre>
<p>这些代码是合乎语法的，可以正常工作。下面再看看JavaScript中一个相同的例子：</p>
<pre class="brush: js; ">

function Test()
{
	this.a = 5;
	var a;
}
</pre>
<p>这段代码的问题在于，局部变量a在我们把数值5赋给它的时候还不存在。只有运行到var a;这一行，变量a才存在。尽管这个例子有点故意编排的意味，但的确能够说明我所遇到的问题。通过把类的创建放到一个类似startupClassName这样的函数中完成，并且在构造函数中定义（但不初始化）局部变量，然后当我在这些构建函数中引用相应的局部变量时，就能够确保它们一定是存在的。</p>
<h2>GameObjectManager.js</h2>
<pre class="brush: js; ">

/**
    管理游戏中所有对象的管理器
    @class
*/
function GameObjectManager()
{
    /** 保存游戏中对象的数组
        @type Arary
    */
    this.gameObjects = new Array();
    /** 上一次帧被渲染的时间
        @type Date
    */
    this.lastFrame = new Date().getTime();
    /** x轴的全局滚动值
        @type Number
    */
    this.xScroll = 0;
    /** y轴的全局滚动值
        @type Number
    */
    this.yScroll = 0;
    /** 对ApplicationManager实例的引用
        @type ApplicationManager
    */
    this.applicationManager = null;
    /** 对画布元素的引用
        @type HTMLCanvasElement
    */
    this.canvas = null;
    /** 对画布元素2D上下文的引用
        @type CanvasRenderingContext2D
    */
    this.context2D = null;
    /** 对内存中用作后台缓冲区的画布的引用
        @type HTMLCanvasElement
    */
    this.backBuffer = null;
    /** 对后台缓冲画布的2D上下文的引用
        @type CanvasRenderingContext2D
    */
    this.backBufferContext2D = null;

    /**
        初始化这个对象
        @return A reference to the initialised object
    */
    this.startupGameObjectManager = function()
    {
        // 设置引用this对象的全局指针
        g_GameObjectManager = this;

        // 取得画布元素及其2D上下文的引用
        this.canvas = document.getElementById(&#039;canvas&#039;);
        this.context2D = this.canvas.getContext(&#039;2d&#039;);
        this.backBuffer = document.createElement(&#039;canvas&#039;);
        this.backBuffer.width = this.canvas.width;
        this.backBuffer.height = this.canvas.height;
        this.backBufferContext2D = this.backBuffer.getContext(&#039;2d&#039;);

        // 创建一个新的ApplicationManager
        this.applicationManager = new ApplicationManager().startupApplicationManager();

        // 使用setInterval来调用draw函数
        setInterval(function(){g_GameObjectManager.draw();}, SECONDS_BETWEEN_FRAMES);

        return this;
    }

    /**
        渲染循环
    */
    this.draw = function ()
    {
        // 计算从上一帧到现在的时间
        var thisFrame = new Date().getTime();
        var dt = (thisFrame - this.lastFrame)/1000;
        this.lastFrame = thisFrame;

        // 清理绘制上下文
        this.backBufferContext2D.clearRect(0, 0, this.backBuffer.width, this.backBuffer.height);
        this.context2D.clearRect(0, 0, this.canvas.width, this.canvas.height);

        // 首先更新所有游戏对象
        for (x in this.gameObjects)
        {
            if (this.gameObjects[x].update)
            {
                this.gameObjects[x].update(dt, this.backBufferContext2D, this.xScroll, this.yScroll);
            }
        }

        // 然后绘制所有游戏对象
        for (x in this.gameObjects)
        {
            if (this.gameObjects[x].draw)
            {
                this.gameObjects[x].draw(dt, this.backBufferContext2D, this.xScroll, this.yScroll);
            }
        }

        // 将后台缓冲复制到当前显示的画布
        this.context2D.drawImage(this.backBuffer, 0, 0);
    };

    /**
        向gameObjects集合中添加一个GameObject
        @param gameObject The object to add
    */
    this.addGameObject = function(gameObject)
    {
        this.gameObjects.push(gameObject);
        this.gameObjects.sort(function(a,b){return a.zOrder - b.zOrder;})
    };

    /**
        从gameObjects集合中删除一个GameObject
        @param gameObject The object to remove
    */
    this.removeGameObject = function(gameObject)
    {
        this.gameObjects.removeObject(gameObject);
    }
}
</pre>
<p>首先看一看GameObjectManager类。GameObjectManager是一个引擎类，用于管理画布的绘制操作，还负责分派GameObject类（下一篇文章里介绍）的事件。</p>
<p>GameObjectManager类的startupGameObjectManager函数的代码如下：</p>
<pre class="brush: js; ">

    /**
        初始化这个对象
        @return A reference to the initialised object
    */
    this.startupGameObjectManager = function()
    {
        // 设置引用this对象的全局指针
        g_GameObjectManager = this;

        // 取得画布元素及其2D上下文的引用
        this.canvas = document.getElementById(&#039;canvas&#039;);
        this.context2D = this.canvas.getContext(&#039;2d&#039;);
        this.backBuffer = document.createElement(&#039;canvas&#039;);
        this.backBuffer.width = this.canvas.width;
        this.backBuffer.height = this.canvas.height;
        this.backBufferContext2D = this.backBuffer.getContext(&#039;2d&#039;);

        // 创建一个新的ApplicationManager
        this.applicationManager = new ApplicationManager().startupApplicationManager();

        // 使用setInterval来调用draw函数
        setInterval(function(){g_GameObjectManager.draw();}, SECONDS_BETWEEN_FRAMES);

        return this;
    }
</pre>
<p>前面已经说过，我们会把每个类的初始化工作放在startupClassName函数中来做。因此，GameObjectManager类将由startupGameObjectManager函数进行初始化。</p>
<p>而引用这个GameObjectManager实例的全局变量g_GameObjectManager经过重新赋值，指向了这个新实例。</p>
<pre class="brush: js; ">

        // 设置引用this对象的全局指针
        g_GameObjectManager = this;
</pre>
<p>对画布元素及其绘图上下文的引用也同样保存起来：</p>
<pre class="brush: js; ">

        // 取得画布元素及其2D上下文的引用
        this.canvas = document.getElementById(&#039;canvas&#039;);
        this.context2D = this.canvas.getContext(&#039;2d&#039;);
</pre>
<p>在前面的例子中，所有绘图操作都是直接在画布元素上完成的。这种风格的渲染一般称为单缓冲渲染。在此，我们要使用一种叫做双缓冲渲染的技术：任意游戏对象的所有绘制操作，都将在一个内存中的附加画布元素（后台缓冲）上完成，完成后再通过一次操作把它复制到网页上的画布元素（前台缓冲）。</p>
<p>双缓冲技术（<a href="http://www.brighthub.com/internet/web-development/articles/11012.aspx" target="_blank">http://www.brighthub.com/internet/web-development/articles/11012.aspx</a>）通常用于减少画面抖动。我自己在测试的时候从没发现直接向画布元素上绘制有抖动现象，但我在网上的确听别人念叨过，使用单缓冲渲染会导致某些浏览器在渲染时发生抖动。</p>
<p>不管怎么说，双缓冲还是能够避免最终用户看到每个游戏对象在绘制过程中最后一帧的组合过程。在通过JavaScript执行某些复杂绘制操作时（例如透明度、反锯齿及可编程纹理），这种情况是完全可能发生的。</p>
<p>使用附加缓冲技术占用的内存非常少，多执行一次图像复制操作（把后台缓冲绘制到前台缓冲）导致的性能损失也可以忽略不计，可以说实现双缓冲系统没有什么缺点。</p>
<p>如果将在HTML页面中定义的画布元素作为前台缓冲，那就需要再创建一个画布来充当后台缓冲。为此，我们使用了document.createElement函数在内存里创建了一个画布元素，把它用作后台缓冲。</p>
<pre class="brush: js; ">

        this.backBuffer = document.createElement(&#039;canvas&#039;);
        this.backBuffer.width = this.canvas.width;
        this.backBuffer.height = this.canvas.height;
        this.backBufferContext2D = this.backBuffer.getContext(&#039;2d&#039;);
</pre>
<p>接下来，我们创建了ApplicationManager类的一个新实例，并调用startupApplicationManager来初始化它。这个ApplicationManager类将在下一篇文章中介绍。</p>
<pre class="brush: js; ">

        // 创建一个新的ApplicationManager
        this.applicationManager = new ApplicationManager().startupApplicationManager();
</pre>
<p>最后，使用setInterval函数重复调用draw函数，这个函数是渲染循环的核心所在。</p>
<pre class="brush: js; ">

        // 使用setInterval来调用draw函数
        setInterval(function(){g_GameObjectManager.draw();}, SECONDS_BETWEEN_FRAMES);
</pre>
<p>下面来看一看draw函数。</p>
<pre class="brush: js; ">

    /**
        渲染循环
    */
    this.draw = function ()
    {
        // 计算从上一帧到现在的时间
        var thisFrame = new Date().getTime();
        var dt = (thisFrame - this.lastFrame)/1000;
        this.lastFrame = thisFrame;

        // 清理绘制上下文
        this.backBufferContext2D.clearRect(0, 0, this.backBuffer.width, this.backBuffer.height);
        this.context2D.clearRect(0, 0, this.canvas.width, this.canvas.height);

        // 首先更新所有游戏对象
        for (x in this.gameObjects)
        {
            if (this.gameObjects[x].update)
            {
                this.gameObjects[x].update(dt, this.backBufferContext2D, this.xScroll, this.yScroll);
            }
        }

        // 然后绘制所有游戏对象
        for (x in this.gameObjects)
        {
            if (this.gameObjects[x].draw)
            {
                this.gameObjects[x].draw(dt, this.backBufferContext2D, this.xScroll, this.yScroll);
            }
        }

        // 将后台缓冲复制到当前显示的画布
        this.context2D.drawImage(this.backBuffer, 0, 0);
    };
</pre>
<p>这个draw函数就是所有渲染循环的核心。在前面的例子中，渲染循环的函数会直接修改要绘制到屏幕上的对象（笑脸）。如果只需绘制一个对象，这样做没有问题。但是，一个游戏要由几十个单独的对象组成，所以这个draw函数并没有直接在渲染循环中直接处理要绘制的对象，而是维护了一个保存着这些对象的数组，让这些对象自己来更新和绘制自己。</p>
<p>首先，计算自上一帧渲染所经过的时间。即便我们在代码里写了每秒钟调用30次draw函数，但谁也无法保证事实如此。通过计算自上一帧渲染所经过的时间，可以做到尽可能让游戏的执行与帧速率无关。</p>
<pre class="brush: js; ">

        // 计算从上一帧到现在的时间
        var thisFrame = new Date().getTime();
        var dt = (thisFrame - this.lastFrame)/1000;
        this.lastFrame = thisFrame;
</pre>
<p>接着清理绘制上下文。</p>
<pre class="brush: js; ">

        // 清理绘制上下文
        this.backBufferContext2D.clearRect(0, 0, this.backBuffer.width, this.backBuffer.height);
        this.context2D.clearRect(0, 0, this.canvas.width, this.canvas.height);
</pre>
<p>然后，就是调用游戏对象（这些对象是由GameObject类定义的，下一篇文章将介绍该类）自己的更新（update）和绘制（draw）方法。注意，这两个方法是可选的（这也是我们在调用它们之前先检查它们是否存在的原因），但差不多每一个对象都需要更新和绘制自已。</p>
<pre class="brush: js; ">

        // 首先更新所有游戏对象
        for (x in this.gameObjects)
        {
            if (this.gameObjects[x].update)
            {
                this.gameObjects[x].update(dt, this.backBufferContext2D, this.xScroll, this.yScroll);
            }
        }

        // 然后绘制所有游戏对象
        for (x in this.gameObjects)
        {
            if (this.gameObjects[x].draw)
            {
                this.gameObjects[x].draw(dt, this.backBufferContext2D, this.xScroll, this.yScroll);
            }
        }
</pre>
<p>最后，把后台缓冲复制到前台缓冲，最终用户就可以看到下一帧了。</p>
<pre class="brush: js; ">

        // 将后台缓冲复制到当前显示的画布
        this.context2D.drawImage(this.backBuffer, 0, 0);
</pre>
<p>理解了draw函数，下面再分别讲一讲addGameObject和removeGameObject函数。</p>
<pre class="brush: js; ">

    /**
        向gameObjects集合中添加一个GameObject
        @param gameObject The object to add
    */
    this.addGameObject = function(gameObject)
    {
        this.gameObjects.push(gameObject);
        this.gameObjects.sort(function(a,b){return a.zOrder - b.zOrder;})
    };

    /**
        从gameObjects集合中删除一个GameObject
        @param gameObject The object to remove
    */
    this.removeGameObject = function(gameObject)
    {
        this.gameObjects.removeObject(gameObject);
    }
</pre>
<p>利用addGameObject和removeGameObject（在Utils.js文件里通过扩展Array.prototype添加）函数，可以在GameObjectManager所维护的GameObject集合（即gameObjects变量）中添加和删除游戏对象。</p>
<p>GameObjectManager类是我们这个游戏框架中最复杂的一个类。在下一篇文章中，我们会讲解游戏框架的另外几个类：GameObject、VisualGameObject、Bounce和ApplicationManager。</p>
<p>好了，现在放松一下，<a href="http://webdemos.sourceforge.net/jsplatformer3/jsplatformer3.html" target="_blank">看一看Demo吧</a>。</p>
<p>为之漫笔 最后编辑于：<br />
2011/08/14 @ 23:19</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cn-cuckoo.com/2011/08/14/game-development-with-javascript-and-the-canvas-element-3-2604.html/feed</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>使用JavaScript和Canvas开发游戏（二）</title>
		<link>http://www.cn-cuckoo.com/2011/08/11/game-development-with-javascript-and-the-canvas-element-2-2585.html</link>
		<comments>http://www.cn-cuckoo.com/2011/08/11/game-development-with-javascript-and-the-canvas-element-2-2585.html#comments</comments>
		<pubDate>Thu, 11 Aug 2011 11:41:56 +0000</pubDate>
		<dc:creator>为之漫笔</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[编程技术]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://www.cn-cuckoo.com/?p=2585</guid>
		<description><![CDATA[原文作者：Matthew Casperson • 编辑：Michele McDonough 原文链接: Game Development with JavaScript and the Canvas element 1、认识一下Canvas 2、在Canvas上绘图 3、通过Canvas元素实现高级图像操作 4、通过Canvas实现视差滚动 5、写一个游戏框架（一） 6、写一个游戏框架（二） 7、动画 8、JavaScript键盘输入 9、综合运用 10、定义级别 11、跳跃与坠落 12、添加道具 13、加载资源 14、添加主菜单 3、通过Canvas元素实现高级图像操作 http://www.brighthub.com/internet/web-development/articles/39509.aspx 这篇文章将带领大家学习使用JavaScript和Canvas元素操作图像了几种不同的方式，这些方式在Canvas元素出现之前是不可能的事儿。 上一篇文章演示了如何利用Canvas实现一个基本的图像动画。那个例子很简单，同样的效果通过修改IMG或DIV等标准HTML元素的一些属性，照样也可以轻易实现。下面我们就来演示一下画布元素的高级应用，展示一下它的真正威力。 首先，还是准备一个HTML页面。 &#60;!DOCTYPE HTML PUBLIC &#34;-//W3C//DTD HTML 4.01//EN&#34;&#62; &#60;html lang=&#34;en&#34;&#62; &#60;head&#62; &#60;title&#62;JavaScript Platformer 2&#60;/title&#62; &#60;script type=&#34;text/javascript&#34; src=&#34;jsplatformer2.js&#34;&#62;&#60;/script&#62; &#60;style type=&#34;text/css&#34;&#62; body { font-family: Arial,Helvetica,sans-serif;} &#60;/style&#62; [...]]]></description>
			<content:encoded><![CDATA[<p>原文作者：Matthew Casperson • 编辑：Michele McDonough<br />
原文链接: <a href="http://www.brighthub.com/hubfolio/matthew-casperson/blog/archive/2009/06/29/game-development-with-javascript-and-the-canvas-element.aspx" target="_blank">Game Development with JavaScript and the Canvas element</a></p>
<p>1、认识一下Canvas<br />
2、在Canvas上绘图<br />
3、通过Canvas元素实现高级图像操作<br />
4、通过Canvas实现视差滚动<br />
5、写一个游戏框架（一）<br />
6、写一个游戏框架（二）<br />
7、动画<br />
8、JavaScript键盘输入<br />
9、综合运用<br />
10、定义级别<br />
11、跳跃与坠落<br />
12、添加道具<br />
13、加载资源<br />
14、添加主菜单</p>
<h1>3、通过Canvas元素实现高级图像操作</h1>
<p><a href="http://www.brighthub.com/internet/web-development/articles/39509.aspx" target="_blank">http://www.brighthub.com/internet/web-development/articles/39509.aspx</a></p>
<p>这篇文章将带领大家学习使用JavaScript和Canvas元素操作图像了几种不同的方式，这些方式在Canvas元素出现之前是不可能的事儿。</p>
<p>上一篇文章演示了如何利用Canvas实现一个基本的图像动画。那个例子很简单，同样的效果通过修改IMG或DIV等标准HTML元素的一些属性，照样也可以轻易实现。下面我们就来演示一下画布元素的高级应用，展示一下它的真正威力。</p>
<p>首先，还是准备一个HTML页面。</p>
<pre class="brush: js; ">

  &lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01//EN&quot;&gt;
  &lt;html lang=&quot;en&quot;&gt;
     &lt;head&gt;
        &lt;title&gt;JavaScript Platformer 2&lt;/title&gt;
        &lt;script type=&quot;text/javascript&quot; src=&quot;jsplatformer2.js&quot;&gt;&lt;/script&gt;
        &lt;style type=&quot;text/css&quot;&gt;
           body { font-family: Arial,Helvetica,sans-serif;}
        &lt;/style&gt;
     &lt;/head&gt;
    &lt;body&gt;
       &lt;p&gt;
          &lt;a href=&quot;http://www.brighthub.com/internet/web-development/articles/38364.aspx&quot;&gt;
             Game Development with Javascript and the canvas element
          &lt;/a&gt;
       &lt;/p&gt;
       &lt;canvas id=&quot;canvas&quot; width=&quot;600&quot; height=&quot;400&quot;&gt;
          &lt;p&gt;Your browser does not support the canvas element.&lt;/p&gt;
       &lt;/canvas&gt;
       &lt;br /&gt;
       &lt;button onclick=&quot;currentFunction=alpha;&quot;&gt;Change Alpha&lt;/button&gt;
       &lt;button onclick=&quot;currentFunction=shear;&quot;&gt;Shear&lt;/button&gt;
       &lt;button onclick=&quot;currentFunction=scale;&quot;&gt;Scale&lt;/button&gt;
       &lt;button onclick=&quot;currentFunction=rotate;&quot;&gt;Rotate&lt;/button&gt;
    &lt;/body&gt;
 &lt;/html&gt;
</pre>
<p>与上个一例子的HTML页面相比，唯一的区别就是添加了一些按钮。单击这些按钮，就会设置currentFunction变量（稍后介绍）的值，用以改变在渲染循环中运行的函数。<br />
<span id="more-2585"></span><br />
以下是 jsplatformer2.js 的代码。</p>
<pre class="brush: js; ">

 // 每秒多少帧
 const FPS = 30;
 const SECONDSBETWEENFRAMES = 1 / FPS;
 const HALFIMAGEDIMENSION = 75;
 const HALFCANVASWIDTH = 300;
 const HALFCANVASHEIGHT = 200;
 var image = new Image();
 image.src = &quot;jsplatformer2-smiley.jpg&quot;; //还是第一个例子中的图像
 var canvas = null;
 var context2D = null;
 var currentFunction = null;
 var currentTime = 0;
 var sineWave = 0;

 window.onload = init;

 function init()
 {
    canvas = document.getElementById(&#039;canvas&#039;);
    context2D = canvas.getContext(&#039;2d&#039;);
    setInterval(draw, SECONDSBETWEENFRAMES * 1000);
    currentFunction = scale;
 }

 function draw()
 {
     currentTime += SECONDSBETWEENFRAMES;
     sineWave = (Math.sin(currentTime) + 1) / 2;

     context2D.clearRect(0, 0, canvas.width, canvas.height);

     context2D.save();

     context2D.translate(HALFCANVASWIDTH - HALFIMAGEDIMENSION, HALFCANVASHEIGHT - HALFIMAGEDIMENSION);

     currentFunction();

     context2D.drawImage(image, 0, 0);

     context2D.restore();
 }

 function alpha()
 {
     context2D.globalAlpha = sineWave;
 }

 function shear()
 {
     context2D.transform(1, 0, (sineWave - 0.5), 1, 0, 0);
 }

 function scale()
 {
     context2D.translate(HALFIMAGEDIMENSION * (1 - sineWave), HALFIMAGEDIMENSION * (1 - sineWave));
     context2D.scale(sineWave, sineWave);
 }

 function rotate()
 {
     context2D.translate(HALFIMAGEDIMENSION, HALFIMAGEDIMENSION);
     context2D.rotate(sineWave * Math.PI * 2);
     context2D.translate(-HALFIMAGEDIMENSION, -HALFIMAGEDIMENSION);
 }
</pre>
<p>跟前面一样，这个JavaScript文件先定义了一些全局变量。</p>
<ul>
<li>
FPS：每秒多少帧
</li>
<li>
SECONDSBETWEENFRAMES：两帧之间间隔的秒数（FPS的倒数）
</li>
<li>
HALFIMAGEDIMENSION：要绘制图像的宽度/高度的一半，用于把图像定位到画布的中心点
</li>
<li>
HALFCANVASWIDTH：画布宽度的一半，用于配合HALFIMAGEDIMENSION使用，以便在画布上居中图像
</li>
<li>
HALFCANVASHEIGHT：画布高度的一半，用于配合HALFIMAGEDIMENSION使用，以便在画布上居中图像
</li>
<li>
currentFunction：渲染循环（参见上一篇文章）中运行的函数
</li>
<li>
currentTime：应用已经运行了多少秒
</li>
<li>
sineWave：0到1之间的一个值，用于控制图像的运动
</li>
<li>
image：要在画布上绘制的图像
</li>
<li>
canvas：画布元素的引用
</li>
<li>
context2D：画布元素的2D上下文的引用
</li>
</ul>
<p>然后，跟前面一样，要设置在window的onload事件发生时立即调用init函数（关于init函数的介绍，请参见上一篇文章）。</p>
<h2>draw函数</h2>
<p>下面来看一看draw函数：</p>
<pre class="brush: js; ">

function draw()
{
    currentTime += SECONDSBETWEENFRAMES;
    sineWave = (Math.sin(currentTime) + 1) / 2;

    context2D.clearRect(0, 0, canvas.width, canvas.height);

    context2D.save();
    context2D.translate(HALFCANVASWIDTH - HALFIMAGEDIMENSION, HALFCANVASHEIGHT - HALFIMAGEDIMENSION);
    currentFunction();
    context2D.drawImage(image, 0, 0);
    context2D.restore();
}
</pre>
<p>这个例子要演示4种效果：修改alpha值（透明度），以及缩放、旋转和切变图像。为了展示这些效果，需要基于某一范围内的值来应用变化。变量sineWave就用来定义这个范围值的基准。</p>
<p>标准的正弦函数能够在-1到1之间产生非常完美的波形图。首先，我们通过递增currentTime变量来反映动画已经运行了多长时间，然后再利用这个值在正弦曲线上找到一个点。给正弦函数返回的值（从-1到1）先加1再除以2，就可以把它们转换成0到1这个范围内的值。</p>
<pre class="brush: js; ">

    currentTime += SECONDSBETWEENFRAMES;
    sineWave = (Math.sin(currentTime) + 1) / 2;
</pre>
<p>然后，调用clearRect方法清空画布，以便为后面的绘图准备一个干净的版面。</p>
<pre class="brush: js; ">

    context2D.clearRect(0, 0, canvas.width, canvas.height);
</pre>
<p>应用到画布上面的效果是可以累积的，因而就可以利用几个简单的函数来“组合”出效果来。例如，在向屏幕上绘制之前，可能会有一艘飞船需要旋转、变换和缩放。因为所有效果都对画布起作用，所以这些效果会应用到将被绘制在屏幕上的所有对象，而不仅仅是某一幅图像或某一个形状（比如一艘飞船）。</p>
<p>其中，save和restore函数为应用这些累积的效果提供了一种简单的机制，可以将应用了这些效果的图像或图形绘制到画布上，然后“撤销”这些改变。后台的操作是什么呢？save函数把当前的绘制状态推进栈里，而restore函数则把最后一个状态弹出栈。还拿前面提到的飞船为例，需要执行下列操作：</p>
<ul>
<li>调用save函数（保存当前的绘制状态）</li>
<li>旋转、变换和缩放上下文</li>
<li>绘制飞船</li>
<li>调用restore函数，移除自上一次调用save方法以来所添加的任何效果，也就是撤销之前的变化</li>
</ul>
<p>在这里，我们就是要组合起来使用这两个方法。首先，在把任何效果应用到画布之前，先保存绘制状态。</p>
<pre class="brush: js; ">

    context2D.save();
</pre>
<p>保存了绘制状态之后，就该应用目标效果了。为此，首先调用translate函数，从而将随后要绘制的图像在画布上居中。</p>
<pre class="brush: js; ">

    context2D.translate(HALFCANVASWIDTH - HALFIMAGEDIMENSION, HALFCANVASHEIGHT - HALFIMAGEDIMENSION);
</pre>
<p>接下来，调用由变量currentFunction引用的函数。正是这些被引用的函数，是让图像发生alpha（透明度）变化以及缩放、旋转和切变的关键。这些函数我们稍后再介绍。</p>
<pre class="brush: js; ">

    currentFunction();
</pre>
<p>为图像应用完效果之后，就可以把它绘制到画布上面了。所以，接下来就是调用drawImage来绘图。</p>
<pre class="brush: js; ">

    context2D.drawImage(image, 0, 0);
</pre>
<p>最后，再调用restore函数，把自调用save函数以来应用的所有效果从画布上移除。</p>
<pre class="brush: js; ">

    context2D.restore();
</pre>
<h2>alpha函数</h2>
<pre class="brush: js; ">

 function alpha()
 {
     context2D.globalAlpha = sineWave;
 }
</pre>
<p>通过修改上下文对象的globalAlpha属性，所有后续绘制操作的透明度都会被修改。将globalAlpha设置为0，意味着被绘制的任何对象都将完全透明，而将这个属性设置为1，则意味着任何绘制操作都会保持原有的透明度级别。在此，我们通过修改这个globalAlpha属性，可以实现笑脸的淡入和淡出效果。</p>
<h2>shear函数</h2>
<pre class="brush: js; ">

 function shear()
 {
     context2D.transform(1, 0, (sineWave - 0.5), 1, 0, 0);
 }
</pre>
<p>切变操作是通过transform函数向画布应用一个矩阵来实现的。变换矩阵本身就是一个值得研究的主题，但对我们来说，如果不想理解背后的数学原理，可以在网上找到很多标准的2D变换矩阵（<a href="http://en.wikipedia.org/wiki/Transformation_matrix#Examples_in_2D_graphics" target="_blank">http://en.wikipedia.org/wiki/Transformation_matrix#Examples_in_2D_graphics</a>），直接使用transform函数来应用它们即可。所谓切变，其实就是把图像的顶部或底部推到一边。</p>
<h2>scale函数</h2>
<pre class="brush: js; ">

 function scale()
 {
     context2D.translate(HALFIMAGEDIMENSION * (1 - sineWave), HALFIMAGEDIMENSION * (1 - sineWave));
　   context2D.scale(sineWave, sineWave);
 }
</pre>
<p>顾名思义，scale（缩放）函数修改的是图像的大小。但在此之前，我们还调用了一次transalte函数。这是为了让缩放后的图像在画布上居中。如果你把这行代码注释掉，就会发现图像会从左上角向右下角膨胀。调用translate函数就是为抵消其圆心的位移，让图像始终居中。</p>
<h2>rotate函数</h2>
<pre class="brush: js; ">

 function rotate()
 {
     context2D.translate(HALFIMAGEDIMENSION, HALFIMAGEDIMENSION);
     context2D.rotate(sineWave * Math.PI * 2);
     context2D.translate(-HALFIMAGEDIMENSION, -HALFIMAGEDIMENSION);
 }
</pre>
<p>与scale函数类似，rotate（旋转）函数的作用也正如其名：旋转图像。与scale函数同样类似的是，这里也额外调用了translate函数以确保图像围绕中心点而不是左上角旋转。建议大家把对translate函数的调用注释掉，自己看一看结果有什么不同。</p>
<p>刚刚我们看到了使用画布元素实现的4种也还算简单的效果，这些效果使用标准的HTML元素几乎是不可能做到的。其中，有的效果可以使用scale和rotate等内置函数来实现，而使用transform函数则可以完成大量的图像操作（切变只是其中之一）。</p>
<p>看看Demo吧。<a href="http://webdemos.sourceforge.net/jsplatformer2/jsplatformer2.html" target="_blank">http://webdemos.sourceforge.net/jsplatformer2/jsplatformer2.html</a></p>
<p>为之漫笔 最后编辑于：<br />
2011/08/12 @ 06:29</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cn-cuckoo.com/2011/08/11/game-development-with-javascript-and-the-canvas-element-2-2585.html/feed</wfw:commentRss>
		<slash:comments>18</slash:comments>
		</item>
		<item>
		<title>使用JavaScript和Canvas开发游戏（一）</title>
		<link>http://www.cn-cuckoo.com/2011/08/10/game-development-with-javascript-and-the-canvas-element-2554.html</link>
		<comments>http://www.cn-cuckoo.com/2011/08/10/game-development-with-javascript-and-the-canvas-element-2554.html#comments</comments>
		<pubDate>Wed, 10 Aug 2011 12:26:29 +0000</pubDate>
		<dc:creator>为之漫笔</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[编程技术]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://www.cn-cuckoo.com/?p=2554</guid>
		<description><![CDATA[原文作者：Matthew Casperson • 编辑：Michele McDonough 原文链接: Game Development with JavaScript and the Canvas element 1、认识一下Canvas 2、在Canvas上绘图 3、通过Canvas元素实现高级图像操作 4、通过Canvas实现视差滚动 5、写一个游戏框架（一） 6、写一个游戏框架（二） 7、动画 8、JavaScript键盘输入 9、综合运用 10、定义级别 11、跳跃与坠落 12、添加道具 13、加载资源 14、添加主菜单 1、认识一下Canvas http://www.brighthub.com/internet/web-development/articles/38364.aspx Canvas元素以及JavaScript引擎中新增的一些特性，让Web开发人员不必借助第三方插件，即可设计开发出精细且具有交互性的2D网页。这篇文章就向大家介绍一下Canvas元素，以及它的一些可能的用途。 JavaScript与Canvas元素 HTML是为创建静态页面而生的。HTML所能实现的动态效果，也仅限于显示GIF动画和闪烁的文本。JavaScript改变了这一切，通过它能够动态修改网页。今天，很多Web服务都利用AJAX来创建网页，为用户提供更加流畅的体验，也超越了标准HTML页面中常见的“点击－重新加载－点击”式的交互模式。 然而，JavaScript的某些功能会受到其宿主浏览器的制约。尽管可以在网页中创建和修改任何元素，但JavaScript不能（轻易地）让浏览器显示一种新对象。通过JavaScript修改文本、插入图像或者缩放表格都很容易，因为这些对象本来就是HTML所支持的。如果你想再玩得刺激一点，比如写一个网页游戏，怎么办？那恐怕就得苦心积虑地改变标准HTML元素的用途，克服种种不测才能达到目的。要么，你就得求助于Flash或Silverlight这样的插件。 Canvas元素登场了。这个新HTML元素为JavaScript开发者提供了一种无需插件即可在网页中直接绘图的机制。Canvas元素最早是由苹果公司在其WebKit框架中引入的，Safari浏览器和Dashboard微件都在使用。Canvas元素现在也被建议加入了HTML5规范，得到了最新的Chrome、Firefox、Opera以及Konqueror等浏览器的支持。Internet Explorer（至少在IE8之前）还不支持Canvas，但ExplorerCanvas项目倒是为IE提供了与Canvas元素类似的功能。 Canvas元素对做过2D图形编程的人是小菜一碟。可以在这个元素上画线、画各种形状、画渐变，甚至可以利用与其他2D API中类似的函数来修改其中的每一个像素。得益于Chrome的V8、Firefox的SpiderMonkey以及Safari的Nitro等最新JavaScript引擎的性能，创建精细且具有交互性的Web应用已经完全没有问题。 我们这一系列文章将教会大家使用JavaScript和Canvas元素创建一个简单的平台游戏。将要涉及的内容包括动画、加载资源、分层渲染、滚动和交互。通过一步一步地展示示例代码和实际效果，你可以很快学会如何驾驭强大的Canvas元素。 2、在Canvas上绘图 http://www.brighthub.com/internet/web-development/articles/38744.aspx 下面，我们就通过一个循序渐进的示例及实时演示，来介绍如何使用JavaScript在Canvas元素上绘图及实现动画。 准备工作 知道了什么是Canvas元素之后，该学习在屏幕上绘图了。首先，需要一个HTML页面来放置和显示Canvas元素。 &#60;!DOCTYPE HTML PUBLIC &#34;-//W3C//DTD HTML 4.01//EN&#34;&#62; &#60;html lang=&#34;en&#34;&#62; &#60;head&#62; &#60;title&#62;JavaScript Platformer [...]]]></description>
			<content:encoded><![CDATA[<p>原文作者：Matthew Casperson • 编辑：Michele McDonough<br />
原文链接: <a href="http://www.brighthub.com/hubfolio/matthew-casperson/blog/archive/2009/06/29/game-development-with-javascript-and-the-canvas-element.aspx" target="_blank">Game Development with JavaScript and the Canvas element</a></p>
<p>1、认识一下Canvas<br />
2、在Canvas上绘图<br />
3、通过Canvas元素实现高级图像操作<br />
4、通过Canvas实现视差滚动<br />
5、写一个游戏框架（一）<br />
6、写一个游戏框架（二）<br />
7、动画<br />
8、JavaScript键盘输入<br />
9、综合运用<br />
10、定义级别<br />
11、跳跃与坠落<br />
12、添加道具<br />
13、加载资源<br />
14、添加主菜单</p>
<h1>1、认识一下Canvas</h1>
<p><a href="http://www.brighthub.com/internet/web-development/articles/38364.aspx" target="_blank">http://www.brighthub.com/internet/web-development/articles/38364.aspx</a></p>
<p>Canvas元素以及JavaScript引擎中新增的一些特性，让Web开发人员不必借助第三方插件，即可设计开发出精细且具有交互性的2D网页。这篇文章就向大家介绍一下Canvas元素，以及它的一些可能的用途。</p>
<h2>JavaScript与Canvas元素</h2>
<p>HTML是为创建静态页面而生的。HTML所能实现的动态效果，也仅限于显示GIF动画和闪烁的文本。JavaScript改变了这一切，通过它能够动态修改网页。今天，很多Web服务都利用AJAX来创建网页，为用户提供更加流畅的体验，也超越了标准HTML页面中常见的“点击－重新加载－点击”式的交互模式。</p>
<p>然而，JavaScript的某些功能会受到其宿主浏览器的制约。尽管可以在网页中创建和修改任何元素，但JavaScript不能（轻易地）让浏览器显示一种新对象。通过JavaScript修改文本、插入图像或者缩放表格都很容易，因为这些对象本来就是HTML所支持的。如果你想再玩得刺激一点，比如写一个网页游戏，怎么办？那恐怕就得苦心积虑地改变标准HTML元素的用途，克服种种不测才能达到目的。要么，你就得求助于Flash或Silverlight这样的插件。</p>
<p>Canvas元素登场了。这个新HTML元素为JavaScript开发者提供了一种无需插件即可在网页中直接绘图的机制。Canvas元素最早是由苹果公司在其WebKit框架中引入的，Safari浏览器和Dashboard微件都在使用。Canvas元素现在也被建议加入了HTML5规范，得到了最新的Chrome、Firefox、Opera以及Konqueror等浏览器的支持。Internet Explorer（至少在IE8之前）还不支持Canvas，但ExplorerCanvas项目倒是为IE提供了与Canvas元素类似的功能。</p>
<p>Canvas元素对做过2D图形编程的人是小菜一碟。可以在这个元素上画线、画各种形状、画渐变，甚至可以利用与其他2D API中类似的函数来修改其中的每一个像素。得益于Chrome的V8、Firefox的SpiderMonkey以及Safari的Nitro等最新JavaScript引擎的性能，创建精细且具有交互性的Web应用已经完全没有问题。</p>
<p>我们这一系列文章将教会大家使用JavaScript和Canvas元素创建一个简单的平台游戏。将要涉及的内容包括动画、加载资源、分层渲染、滚动和交互。通过一步一步地展示示例代码和实际效果，你可以很快学会如何驾驭强大的Canvas元素。</p>
<h1>2、在Canvas上绘图</h1>
<p><a href="http://www.brighthub.com/internet/web-development/articles/38744.aspx" target="_blank">http://www.brighthub.com/internet/web-development/articles/38744.aspx</a></p>
<p>下面，我们就通过一个循序渐进的示例及实时演示，来介绍如何使用JavaScript在Canvas元素上绘图及实现动画。</p>
<h2>准备工作</h2>
<p>知道了什么是Canvas元素之后，该学习在屏幕上绘图了。首先，需要一个HTML页面来放置和显示Canvas元素。<br />
<span id="more-2554"></span></p>
<pre class="brush: html; ">

  &lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01//EN&quot;&gt;
  &lt;html lang=&quot;en&quot;&gt;
     &lt;head&gt;
        &lt;title&gt;JavaScript Platformer 1&lt;/title&gt;
        &lt;script type=&quot;text/javascript&quot; src=&quot;jsplatformer1.js&quot;&gt;&lt;/script&gt;
        &lt;style type=&quot;text/css&quot;&gt;
           body { font-family: Arial,Helvetica,sans-serif;}
        &lt;/style&gt;
     &lt;/head&gt;
    &lt;body&gt;
       &lt;p&gt;
          &lt;a href=&quot;http://www.brighthub.com/internet/web-development/articles/38364.aspx&quot;&gt;
             Game Development with Javascript and the canvas element
          &lt;/a&gt;
       &lt;/p&gt;
       &lt;canvas id=&quot;canvas&quot; width=&quot;600&quot; height=&quot;400&quot;&gt;
          &lt;p&gt;Your browser does not support the canvas element.&lt;/p&gt;
       &lt;/canvas&gt;
    &lt;/body&gt;
 &lt;/html&gt;
</pre>
<p>这些HTML代码很直观。其中有两个重要的元素。</p>
<pre class="brush: js; ">

&lt;script type=&quot;text/javascript&quot; src=&quot;jsplatformer1.js&quot;&gt;&lt;/script&gt;
</pre>
<p>这里包含的是将会修改Canvas元素的JavaScript代码，对应的Canvas元素的标记如下：</p>
<pre class="brush: js; ">

&lt;canvas id=&quot;canvas&quot; width=&quot;600&quot; height=&quot;400&quot;&gt;
	&lt;p&gt;Your browser does not support the canvas element.&lt;/p&gt;
&lt;/canvas&gt;
</pre>
<p>以上代码创建了一个Canvas元素。不支持Canvas的浏览器，比如Internet Explorer（IE8之前的版本），会忽略这个元素，而只显示其子元素。在这个简单的例子中，这个子元素就是一个段落，其中的文本告诉用户他们的浏览器不支持Canvas元素。而对于那些支持Canvas元素的浏览器，如Chrome、Opera和Firefox，则会忽略Canvas元素的子元素。</p>
<p>这个Canvas元素的ID属性很重要，因为后面的JavaScript将通过它来取得对该元素的引用。而width和height属性指定了画布的宽度和高度，这两个属性跟table或img等其他HTML元素中的同名属性作用一样。</p>
<p>以下是 jsplatformer1.js的代码：</p>
<pre class="brush: js; ">

//每秒钟target帧
const FPS = 30;
var x = 0;
var y = 0;
var xDirection = 1;
var yDirection = 1;
var image = new Image();
//建议读者将图片下载到本地加载（经测试，此图片响应头部的Content-Type为application/empty，浏览器无法识别）
image.src = &quot;http://javascript-tutorials.googlecode.com/files/jsplatformer1-smiley.jpg&quot;;
var canvas = null;
var context2D = null;

window.onload = init;
function init(){
	canvas = document.getElementById(&#039;canvas&#039;);
	context2D = canvas.getContext(&#039;2d&#039;);
	setInterval(draw, 1000/FPS);
}
function draw(){
	context2D.clearRect(0, 0, canvas.width, canvas.height);
	context2D.drawImage(image, x, y);
	x += 1* xDirection;
	y += 1* yDirection;

	if (x &gt;= 450) {
		x = 450;
		xDirection = -1;
	}else if(x &lt;= 0){
		x = 0;
		xDirection = 1;
	}
	if (y &gt;= 250) {
		y = 250;
		yDirection = -1;
	}else if(y &lt;= 0){
		y = 0;
		yDirection = 1;
	}
}
</pre>
<p>如果只是一个Canvas元素，也没有什么用。JavaScript必须要在这块画布上面画点什么，相应的代码保存在 jsplatformer1.js中。简单来说，JavaScript在这里先加载了一幅图像，然后将其画在画布上面，最后让它在画布上移动。</p>
<p>首先，定义一些全局变量。</p>
<pre class="brush: js; ">

const FPS = 30;
</pre>
<p>FPS定义的是画布重绘的频率。</p>
<pre class="brush: js; ">

var x = 0;
var y = 0;
var xDirection = 1;
var yDirection = 1;
</pre>
<p>变量x、y、xDirection和yDirection用于定义图像（相对于画布左上角）的位置，以及它在任意一时刻移动的方向。</p>
<pre class="brush: js; ">

var image = new Image();
image.src = &quot;http://javascript-tutorials.googlecode.com/files/jsplatformer1-smiley.jpg&quot;;
</pre>
<p>要把图像画到画布上，必须先加载一幅图像。为此，我们创建一个Image对象，将其src属性设置为一幅图像文件的URL（建议把图片下载到本地。——译者注）。</p>
<pre class="brush: js; ">

var canvas = null;
var context2D = null;
</pre>
<p>我们还需要取得对Canvas元素以及绘图上下文（稍后再详细介绍绘图上下文）的引用。稍后我们会把正确的值赋给这两个变量，现在先把它们设置为null。</p>
<pre class="brush: js; ">

window.onload = init;
</pre>
<p>最后，当页面加载完成后，我们必须知道立即运行绘制画布的代码；因此，在window对象的onload事件发生时，立即调用init函数。</p>
<h2>init函数</h2>
<pre class="brush: js; ">

function init(){
	canvas = document.getElementById(&#039;canvas&#039;);
	context2D = canvas.getContext(&#039;2d&#039;);
	setInterval(draw, 1000/FPS);
}
</pre>
<p>页面加载完毕后就会调用上面这个init函数。在这个函数中，我们先通过在HTML文件中指定的ID属性取得画布元素（毫无疑问，除了把它叫做画布，还能叫个啥？），然后再取得这个画布的2D绘图上下文对象。</p>
<p>上下文对象用于定义如何在画布上绘图。顾名思义，2D上下文嘛，支持在画布上绘制2D图形、图像和文本。支持画布元素的浏览器都支持2D上下文，除了2D上下文，还有其他试验性的上下文对象。Opera有一个专门为游戏设计的2D上下文，而Mozilla则有一个能够显示3D场景的上下文。可惜呀，目前这些上下文对象只有特定的浏览器才支持。如果你想用画布来创建Web应用，最好还是只使用常见的2D上下文。</p>
<p>因为我们在这里是想绘制一幅能移动的图像，所以必须建立渲染循环（render loop）。所谓渲染循环，实际上就是一个被重复调用的函数，渲染循环的每一次迭代，（在这个例子中）都可以让图像在屏幕上产生一点位移，如此循环往复就能给人图像在移动的感觉。为此，我们调用了setInterval函数，它的第一个参数是应该被重复调用的函数，这里的函数名是draw。setInterval函数的第二个参数指定调用函数的频率。这个参数值的单位是毫秒，而用1000除以早先定义的FPS得到的就是每次调用之间相隔的毫秒数。</p>
<p>这里需要注意一下，虽然我们指定每秒钟调用30次draw函数，但实际上不会调用30次。多长时间调用一次draw函数，取决于底层JavaScript引擎的速度和要执行的draw函数代码的复杂程度。如果系统很慢的话，很可能每秒钟只能调用一次draw函数。所以说，这里指定给setInterval的频率只是一种最理想的情况。</p>
<h2>draw函数</h2>
<p>在画布上绘图的操作实际上都是由draw函数来完成的。下面我们就一步一步地说明其中的绘图操作。</p>
<pre class="brush: js; ">

context2D.clearRect(0, 0, canvas.width, canvas.height);
</pre>
<p>所有绘图操作都是在上下文对象上发生的，并不是在画布元素上发生的。这里首先清空上下文，以便为绘制每一帧画面准备一个干净的版面。</p>
<pre class="brush: js; ">

context2D.drawImage(image, x, y);
</pre>
<p>紧接着，就把图像绘制到上下文对象中，参数x和y指定了绘制图像的左上角坐标。</p>
<pre class="brush: js; ">

x += 1 * xDirection;
y += 1 * yDirection;
</pre>
<p>为了让图像在画布上移动，需要根据xDirection和yDirection是等于1（向右或向下）还是等于-1（向左或向上），来递增或递减x与y的值。</p>
<pre class="brush: js; ">

if (x &gt;= 450){
	x = 450;
	xDirection = -1;
} else if (x &lt;= 0) {
	x = 0;
	xDirection = 1;
}
if (y &gt;= 250) {
	y = 250;
	yDirection = -1;
} else if (y &lt;= 0) {
	y = 0;
	yDirection = 1;
}
</pre>
<p>如果图像移动到了画布外面，则反转图像的移动方向。我们知道图像的大小是150×150像素，而画布的大小的是600×400像素，因而就有了450（600 &#8211; 150）和250（400 &#8211; 150）这两个值。</p>
<p>最后的效果就是笑脸图像会在画布的范围内反弹往复。此时此刻，有读者可能会想：同样的效果如果通过修改DIV元素的位置来实现可能更容易一些。这一点我不否认。但这个例子只演示了画布元素所能实现的简单效果。下一篇文章我们就会介绍使用画布元素能够实现的高级效果，同样的效果若采用其他方式，恐怕就要困难多了。</p>
<p>为之漫笔 最后编辑于：<br />
2011/08/12 @ 06:39</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cn-cuckoo.com/2011/08/10/game-development-with-javascript-and-the-canvas-element-2554.html/feed</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
		<item>
		<title>JavaScript是Web的汇编语言（二）：疯狂，亦或只是精神错乱？</title>
		<link>http://www.cn-cuckoo.com/2011/07/21/javascript-is-assembly-language-for-the-web-ii-2531.html</link>
		<comments>http://www.cn-cuckoo.com/2011/07/21/javascript-is-assembly-language-for-the-web-ii-2531.html#comments</comments>
		<pubDate>Thu, 21 Jul 2011 00:40:28 +0000</pubDate>
		<dc:creator>为之漫笔</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[编程技术]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://www.cn-cuckoo.com/?p=2531</guid>
		<description><![CDATA[原文地址：JavaScript is Assembly Language for the Web: Part 2 &#8211; Madness or just Insanity? 有些人认为“JavaScript是Web的汇编语言”完全是精神病说的话。为此，我询问了几位JavaScript权威，比如Brendan Eich（JavaScript之父）、Douglas Crockford（JSON之父），还有Mike Shaver（Mozilla技术副总裁）。以下都是从个人邮件里摘过来的，得到了以上几位的许可。 Mike Shaver： 以前我就听说过这种比较，我认为很大程度上确实如此。但是，这种说法忽视了JS开发人员与机器之间的人机工程学方面的大量努力，因为汇编语法设计得没有那么人性化（特别是现代的汇编语言）。 Brendan Eich： 几年前，我曾说过“JS是Web的x86”（好像是在一次JSConf上），不过我不敢说我是第一个这么说的。（Nick Thompson今年也在Hacker News中这么说过。） 关键在于，JS确实在按照我们想的，越来越往低级方向发展了。但它也具备高级的特性。 Shaver说得没错，汇编缺少可靠的宏处理器，因此不适合程序员，也不够安全。但JS可不是这样。所以，这个比喻需要加点限制条件，不然就要闹出笑话来了。 无论从高级函数式编程还是内存安全角这个角度看，还是从低级特性，像类型化数组以及即将成为现实的ES中类型化数组的扩展、二进制数据，等等来说，JS都是一个比汇编更加强大的编程语言。当然了，内存安全是首要的区别。 Douglas Crockford： 就这个问题来说，我觉得说JavaScript是Web的虚拟机更接近一些。过去我们一直都把Java的JVM看成是Web的虚拟机，但结果呢，JavaScript才是。 从提供代码安全的角度说，JavaScript的解析器比JVM的字节码验证器更有效。就兑现“编写一次，到处运行”这个诺言来看，JavaScript更出色；这或许正是因为它是在较高层次上运行，才得以避免触及一些底层的棘手问题。因为它把剩下的事儿都交给图灵去解决了。 当然啦，也有不少人始终不肯承认JavaScript能把一切都处理好，我过去就是这样一个人。而现在我则不断地被眼前这种百花齐放的景象震撼着。 Brendan Eich，补充： Doug说源代码强过字节码，说得太好了。很早以前，我的朋友，加州大学欧文分校的Michael Franz教授就指出了Java验证器O(n^4)级别的复杂性（计算机时钟周期失控，拒绝服务）。精简之后的JS呢，确实传输更便捷，而且词法/语法分析也相当快。 （JS）源代码作为“字节码”同样也避免了Java字节码的一个很傻的问题：冻结设计不良的Java低级形式，导致高级形式的源代码也无法解决这个问题。换句话说，Java唯恐破坏其字节码的兼容性。而这严重影响了Java内部类及其泛型的设计。——不管怎么说，Sun最后还是破坏了字节码的兼容性。 以下是前一段时间Nick Thompson在YCombinator说过的话： 这只是我个人的看法：我花了自己两年时间，想尽可能让JVM能够与JavaScript互通。当时的Netscape有不少人认为字节码作为移动代码的基础比较好。但Sun从头搭建了自己大而全的软件体系，把问题搞得很复杂。他们没有想让Java与其他语言沟通，更别提让Java能嵌入其他软件中了。他们的字符串处理代码都是用一种解释型语言来写，而不肯用C来玷污自己！有什么我就说什么，Netscape，这个当时Java唯一的一个大客户，在Sun眼里无非就是一个用来实现他们取代Windows梦想的工具而已。所有想用Java的人都是自己给自己找罪受。 在此期间，Brendan一个人干了10个工程师，外加3个客户服务人员的活儿，同时还要关注Web作者在乎的一些事，比如把JS代码混合到HTML中、即时加载、与浏览器其他模块的集成等等，此外还要协调其他浏览器厂商，以便让JS成为一个开放标准。 因此，今天的JS作为Web的x86汇编程序，并没有像它本该的那样完美，但你通过它真能把事情稿定（GWT就是一个最明显的例子）。这可以说是一个经典的“更差就是更好”的例子，只不过Java也就是从下往上那么看起来更好罢了。而JS则在此期间取得了相当不错的成就。要想取代它的地位可没那么容易。 当然，这个比喻不一定准确。JavaScript代码无论从外观到行为，肯定不像ASM。但作为一个比喻，至少可以说明： JavaScript无所不在； 它速度快而且越来越快； JavaScript酷似低级的Web编程语言； 它可以通过手工编写，也可以从另一种语言编译而来。 诸如此类的话题也经常在Hacker News中出现： “现在的JavaScript其实就是客户端的汇编语言。想改它太难了，所以得想办法开发一些工具来解决这个问题。”—— jonnycat 好啦，能听到如此有见地、有深度，而又详尽的讨论，该满足了吧。亲爱的读者，你们太棒了。]]></description>
			<content:encoded><![CDATA[<p style="text-align: right;">原文地址：<a href="http://www.hanselman.com/blog/JavaScriptIsAssemblyLanguageForTheWebPart2MadnessOrJustInsanity.aspx">JavaScript is Assembly Language for the Web: Part 2 &#8211; Madness or just Insanity?</a></p>
<p><strong>有些人认为“<a href="http://www.cn-cuckoo.com/2011/07/20/javascript-is-assembly-language-for-the-web-i-2511.html">JavaScript是Web的汇编语言</a>”完全是精神病说的话。</strong>为此，我询问了几位JavaScript权威，比如Brendan Eich（JavaScript之父）、Douglas Crockford（JSON之父），还有Mike Shaver（Mozilla技术副总裁）。以下都是从个人邮件里摘过来的，得到了以上几位的许可。</p>
<p><a href="http://en.wikipedia.org/wiki/Mike_Shaver" target="_blank">Mike Shaver</a>：</p>
<div style="border-left: 2px solid #ddd; margin-left: 1em; padding-left: 1em;">以前我就听说过这种比较，我认为很大程度上确实如此。但是，这种说法忽视了JS开发人员与机器之间的人机工程学方面的大量努力，因为汇编语法设计得没有那么人性化（特别是现代的汇编语言）。</div>
<p><a href="http://en.wikipedia.org/wiki/Brendan_Eich" target="_blank">Brendan Eich</a>：</p>
<div style="border-left: 2px solid #ddd; margin-left: 1em; padding-left: 1em;">
<p>几年前，我曾说过“JS是Web的x86”（好像是在一次JSConf上），不过我不敢说我是第一个这么说的。（Nick Thompson今年也在Hacker News中这么说过。）</p>
<p>关键在于，JS确实在按照我们想的，越来越往低级方向发展了。但它也具备高级的特性。</p>
<p>Shaver说得没错，汇编缺少可靠的宏处理器，因此不适合程序员，也不够安全。但JS可不是这样。所以，这个比喻需要加点限制条件，不然就要闹出笑话来了。</p>
<p>无论从高级函数式编程还是内存安全角这个角度看，还是从低级特性，像类型化数组以及即将成为现实的ES中类型化数组的扩展、二进制数据，等等来说，JS都是一个比汇编更加强大的编程语言。当然了，内存安全是首要的区别。</p>
</div>
<p><a href="http://en.wikipedia.org/wiki/Douglas_Crockford" target="_blank"><span id="more-2531"></span>Douglas Crockford</a>：</p>
<div style="border-left: 2px solid #ddd; margin-left: 1em; padding-left: 1em;">
<p>就这个问题来说，我觉得说JavaScript是Web的虚拟机更接近一些。过去我们一直都把Java的JVM看成是Web的虚拟机，但结果呢，JavaScript才是。</p>
<p>从提供代码安全的角度说，JavaScript的解析器比JVM的字节码验证器更有效。就兑现“编写一次，到处运行”这个诺言来看，JavaScript更出色；这或许正是因为它是在较高层次上运行，才得以避免触及一些底层的棘手问题。因为它把剩下的事儿都交给图灵去解决了。</p>
<p>当然啦，也有不少人始终不肯承认JavaScript能把一切都处理好，我过去就是这样一个人。而现在我则不断地被眼前这种百花齐放的景象震撼着。</p>
</div>
<p>Brendan Eich，补充：</p>
<div style="border-left: 2px solid #ddd; margin-left: 1em; padding-left: 1em;">
<p>Doug说源代码强过字节码，说得太好了。很早以前，我的朋友，加州大学欧文分校的Michael Franz教授就指出了Java验证器O(n^4)级别的复杂性（计算机时钟周期失控，拒绝服务）。精简之后的JS呢，确实传输更便捷，而且词法/语法分析也相当快。</p>
<p>（JS）源代码作为“字节码”同样也避免了Java字节码的一个很傻的问题：冻结设计不良的Java低级形式，导致高级形式的源代码也无法解决这个问题。换句话说，Java唯恐破坏其字节码的兼容性。而这严重影响了Java内部类及其泛型的设计。——不管怎么说，Sun最后还是破坏了字节码的兼容性。
</p></div>
<p>以下是前一段时间<a href="http://nixweb.com/" target="_blank">Nick Thompson</a>在YCombinator说过的话：</p>
<div style="border-left: 2px solid #ddd; margin-left: 1em; padding-left: 1em;">
<p>这只是我个人的看法：我花了自己两年时间，想尽可能让JVM能够与JavaScript互通。当时的Netscape有不少人认为字节码作为移动代码的基础比较好。但Sun从头搭建了自己大而全的软件体系，把问题搞得很复杂。他们没有想让Java与其他语言沟通，更别提让Java能嵌入其他软件中了。他们的字符串处理代码都是用一种解释型语言来写，而不肯用C来玷污自己！有什么我就说什么，Netscape，这个当时Java唯一的一个大客户，在Sun眼里无非就是一个用来实现他们取代Windows梦想的工具而已。所有想用Java的人都是自己给自己找罪受。</p>
<p>在此期间，Brendan一个人干了10个工程师，外加3个客户服务人员的活儿，同时还要关注Web作者在乎的一些事，比如把JS代码混合到HTML中、即时加载、与浏览器其他模块的集成等等，此外还要协调其他浏览器厂商，以便让JS成为一个开放标准。</p>
<p>因此，今天的JS作为Web的x86汇编程序，并没有像它本该的那样完美，但你通过它真能把事情稿定（GWT就是一个最明显的例子）。这可以说是一个经典的“更差就是更好”的例子，只不过Java也就是从下往上那么看起来更好罢了。而JS则在此期间取得了相当不错的成就。要想取代它的地位可没那么容易。</p>
</div>
<p>当然，这个比喻不一定准确。JavaScript代码无论从外观到行为，肯定不像ASM。但作为一个比喻，至少可以说明：</p>
<ul>
<li>JavaScript无所不在；</li>
<li>它速度快而且越来越快；</li>
<li>JavaScript酷似低级的Web编程语言；</li>
<li>它可以通过手工编写，也可以从另一种语言编译而来。</li>
</ul>
<p>诸如此类的话题也经常在Hacker News中出现：</p>
<div style="border-left: 2px solid #ddd; margin-left: 1em; padding-left: 1em;">
“现在的JavaScript其实就是客户端的汇编语言。想改它太难了，所以得想办法开发一些工具来解决这个问题。”——<br />
<a href="http://news.ycombinator.com/item?id=2451594">jonnycat</a></div>
<p>好啦，能听到如此有见地、有深度，而又详尽的讨论，该满足了吧。亲爱的读者，你们太棒了。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cn-cuckoo.com/2011/07/21/javascript-is-assembly-language-for-the-web-ii-2531.html/feed</wfw:commentRss>
		<slash:comments>24</slash:comments>
		</item>
		<item>
		<title>JavaScript是Web的汇编语言（一）：语义Web已死！</title>
		<link>http://www.cn-cuckoo.com/2011/07/20/javascript-is-assembly-language-for-the-web-i-2511.html</link>
		<comments>http://www.cn-cuckoo.com/2011/07/20/javascript-is-assembly-language-for-the-web-i-2511.html#comments</comments>
		<pubDate>Wed, 20 Jul 2011 12:59:04 +0000</pubDate>
		<dc:creator>为之漫笔</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[编程技术]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://www.cn-cuckoo.com/?p=2511</guid>
		<description><![CDATA[原文地址：JavaScript is Assembly Language for the Web: Sematic Markup is Dead! Clean vs. Machine-coded HTML （更新）有些人认为“JavaScript是Web的汇编语言”完全是精神病说的话。为此，我询问了几位JavaScript权威，比如Brendan Eich（JavaScript之父）、Douglas Crockford（JSON之父），还有Mike Shaver（Mozilla技术副总裁）。他们的评论发表在下一篇文章里。 昨天我跟Erik Meijer聊天，他说： JavaScript就是一个汇编语言。JavaScript加上生成的HTML就像是.NET汇编一样。浏览器可以执行这些代码，但没人真的关心里面到底写的是什么。 ——Erik Meijer 怎么会说起这件事儿呢？当时我正在试用Google+，就跟上大多数让我印象深刻的网站一样，我立即就查看它的源代码。不看不要紧，一看吓一跳： 咱就将就说吧，我看到了1300行代码，密密麻麻的，大约90KB。上面图片显示的只是最前面的一小部分，基本上都是“瘦身后”的JavaScript代码。再往下看，页面中间呢，全都是像下面这样的span、div以及生成的类和id： 我勒个去，满篇都是GUID（Globally Unique Identifier，全局唯一标识符）。 话又说回来了，http://msn.com、http://www.bing.com、http://.www.facebook.com，全都这样啊。就连http://www.twitter.com也都开始有点“瘦身”的迹象了。所有大点的网站好像都丝毫不在乎什么标记之美。这是为什么呢？ 这样有效率啊，性能高啊。Google很多最出色的网站背后都依赖GWT呢。在这种情况下，要是这一类网站的里头和外头全都一样漂亮，你反而会觉得不可思议了。 不能不说这可真有点讽刺的意味。曾几何时，ASP.NET的开发人员对ViewState可是怨声载道啊。“简直太笨了”的意思就是“我看不懂它都干什么了。”ViewState曾经（现在也）是一项让Web开发效率提高很多倍的技术。它跟Google Web Toolkit（GWT）不一样，但GWT与WebForms的出发点也并非完全没有相似之处。看看GWT网站自己怎么说： Google Web Toolkit（GWT）是一个开发工具包，用于构建和优化基于浏览器的复杂应用。GWT的目标是提高高性能Web应用开发的效率，而且无需开发人员熟悉浏览器的各种怪癖，以及XMLHttpRequest，还有JavaScript。 这个出发点可真是值得赞美，不对？难道不可以这样说（抱歉，开个玩笑而已）： “ASP.NET WebForms”是一个开发工具包，用于构建和优化基于浏览器的复杂应用。它的目标是提高高性能Web应用开发的效率，而且无需开发人员熟悉浏览器的各种怪癖，以及XMLHttpRequest，还有JavaScript。 本文的目的不是想夸奖WebForms，也不是给WebForms正名。WebForms对于某些应用是不二之选，正如GWT对其他一些应用那样。我真正想说的是，使用服务器端的工具包，没有办法像使用jQuery写出清晰的JavaScript，或者使用Razor或HAML写出清晰、清楚的标记一样，给Web开发带来真正的快乐。归根结底，其实就是你选择的抽象级别的问题。 所谓的语义标记在这种情况下仍然是被隐藏的，而诸如http://schema.org之类的站点也仍然非常重要，只不过可别指望你能在心仪的站点里看到缩进得像俳句一样整齐的源代码。 大家知道，精简和压缩属于正交优化。而我要说的是，一点也不在乎标记和脚本发送到客户端之后是否美观，确实太草率了。假如谁都不在乎发送到浏览器的标记，只在乎结果，那谁的标记和JS就那么不值钱啊，谁还愿意主动公开自己的源代码呢？反正，网站不是运行得挺好嘛，谁还在乎其他的？ 现在我要给亲爱的读者提个问题，你觉得自己为什么那么在乎点击“查看网页源代码”之后的结果呢？难道HTML5和JavaScript是Web的新汇编语言不成？ （更新）声明一下： 当然，这个比喻不一定准确。JavaScript代码无论从外观到行为，肯定不像ASM。但作为一个比喻，至少可以说明： JavaScript无所不在； 它速度快而且越来越快； JavaScript酷似低级的Web编程语言； 它可以通过手工编写，也可以从另一种语言编译而来。 作为开发人员或者设计人员，如果有工具提供了你需要的控制和你需要的结果，你最关心哪一个？我认为Rails、ASP.NET，甚至GWT，都没有100%做到这一点。它们都有自己的问题，但我认为将来的Web不会再专注于清晰的标记，而是夺目的用户体验和语言、工具的天下，开发人员会很享受，效率也会更高。 亲爱的读者，你愿意HTML和JavaScript再多抽象一点吗？还是希望它少抽象一点？ （再更新）为了让大家明白，我得再说一遍。本文讨论了两个独立的问题。一个当然就是源代码经过了精简和通常的混淆。但这只是第一个问题。真正的问题在于，JavaScript已经成了其他多种语言的目标语言。GWT是一个用JAVA来写Web应用的框架，它产生的字节码是“JavaScript”。GWT为原来天然的语言（HTML+JS）选择了一个设计好的高级语言，并将整个浏览器当成了一个VM。好，问题来了：我们是在写汇编呢，还是在写某种更高级点的代码？而且，我刚知道Google+是用Closure来写的，但这不影响前面的问题。]]></description>
			<content:encoded><![CDATA[<p style="text-align: right;">原文地址：<a href="http://www.hanselman.com/blog/JavaScriptIsAssemblyLanguageForTheWebSematicMarkupIsDeadCleanVsMachinecodedHTML.aspx">JavaScript is Assembly Language for the Web: Sematic Markup is Dead! Clean vs. Machine-coded HTML</a></p>
<p><strong><span style="color:red;">（更新）</span>有些人认为“JavaScript是Web的汇编语言”完全是精神病说的话。为此，我询问了几位JavaScript权威，比如Brendan Eich（JavaScript之父）、Douglas Crockford（JSON之父），还有Mike Shaver（Mozilla技术副总裁）。<a href="http://http://www.cn-cuckoo.com/2011/07/21/javascript-is-assembly-language-for-the-web-ii-2531.html">他们的评论发表在下一篇文章里</a>。</strong></p>
<p>昨天我跟Erik Meijer聊天，他说：</p>
<div style="border-left: 2px solid #ddd; margin-left: 1em; padding-left: 1em; font-weight: bold;">JavaScript就是一个汇编语言。JavaScript加上生成的HTML就像是.NET汇编一样。浏览器可以执行这些代码，但没人真的关心里面到底写的是什么。<br />
——Erik Meijer</div>
<p>怎么会说起这件事儿呢？当时我正在<strong>试用Google+</strong>，就跟上大多数让我印象深刻的网站一样，我立即就查看它的源代码。不看不要紧，一看吓一跳：<br />
<img class="colorbox-2511"  src="http://www.cn-cuckoo.com/cache/img/2511_image_1.png" alt="" /></p>
<p>咱就将就说吧，我看到了1300行代码，密密麻麻的，大约90KB。上面图片显示的只是最前面的一小部分，基本上都是“瘦身后”的JavaScript代码。再往下看，页面中间呢，全都是像下面这样的span、div以及生成的类和id：<span id="more-2511"></span></p>
<p><img class="colorbox-2511"  src="http://www.cn-cuckoo.com/cache/img/2511_image_2.png" alt="" /></p>
<p><strong>我勒个去，满篇都是GUID（Globally Unique Identifier，全局唯一标识符）。</strong></p>
<p>话又说回来了，<strong><a title="http://msn.com" href="http://msn.com" target="_blank">http://msn.com</a>、<a title="http://www.bing.com" href="http://www.bing.com" target="_blank">http://www.bing.com</a>、<a title="http://.www.facebook.com" href="http://.www.facebook.com" target="_blank">http://.www.facebook.com</a></strong>，全都这样啊。就连<strong><a title="http://www.twitter.com" href="http://www.twitter.com" target="_blank">http://www.twitter.com</a></strong>也都开始有点“瘦身”的迹象了。所有大点的网站好像都丝毫不在乎什么标记之美。这是为什么呢？</p>
<p>这样有效率啊，性能高啊。Google很多最出色的网站背后都依赖GWT呢。<strong>在这种情况下，要是这一类网站的里头和外头全都一样漂亮，你反而会觉得不可思议了。</strong></p>
<p>不能不说这可真有点讽刺的意味。曾几何时，ASP.NET的开发人员对ViewState可是怨声载道啊。“简直太笨了”的意思就是“我看不懂它都干什么了。”ViewState曾经（现在也）是一项让Web开发效率提高很多倍的技术。它跟Google Web Toolkit（GWT）不一样，但GWT与WebForms的出发点也并非完全没有相似之处。看看GWT网站自己怎么说：</p>
<div style="border-left: 2px solid #ddd; margin-left: 1em; padding-left: 1em;">Google Web Toolkit（GWT）是一个开发工具包，用于构建和优化基于浏览器的复杂应用。GWT的目标是提高高性能Web应用开发的效率，而且无需开发人员熟悉浏览器的各种怪癖，以及XMLHttpRequest，还有JavaScript。</div>
<p>这个出发点可真是值得赞美，不对？难道不可以这样说（抱歉，开个玩笑而已）：</p>
<div style="border-left: 2px solid #ddd; margin-left: 1em; padding-left: 1em;">“<strong>ASP.NET WebForms</strong>”是一个开发工具包，用于构建和优化基于浏览器的复杂应用。它的目标是提高高性能Web应用开发的效率，而且无需开发人员熟悉浏览器的各种怪癖，以及XMLHttpRequest，还有JavaScript。</div>
<p>本文的目的不是想夸奖WebForms，也不是给WebForms正名。WebForms对于某些应用是不二之选，正如GWT对其他一些应用那样。我真正想说的是，使用服务器端的工具包，没有办法像使用jQuery写出清晰的JavaScript，或者使用Razor或HAML写出清晰、清楚的标记一样，给Web开发带来真正的快乐。归根结底，其实就是你选择的抽象级别的问题。</p>
<p>所谓的语义标记在这种情况下仍然是被隐藏的，而诸如<strong><a title="http://schema.org" href="http://schema.org" target="_blank">http://schema.org</a></strong>之类的站点也仍然非常重要，只不过可别指望你能在心仪的站点里看到缩进得像俳句一样整齐的源代码。</p>
<p>大家知道，精简和压缩属于正交优化。而我要说的是，一点也不在乎标记和脚本发送到客户端之后是否美观，确实太草率了。<strong>假如谁都不在乎发送到浏览器的标记，只在乎结果，那谁的标记和JS就那么不值钱啊，谁还愿意主动公开自己的源代码呢？</strong>反正，网站不是运行得挺好嘛，谁还在乎其他的？</p>
<p>现在我要给亲爱的读者提个问题，你觉得自己为什么那么在乎点击“查看网页源代码”之后的结果呢？难道HTML5和JavaScript是Web的新汇编语言不成？</p>
<p><strong>（更新）声明一下：</strong><br />
当然，这个比喻不一定准确。JavaScript代码无论从外观到行为，肯定不像ASM。但作为一个比喻，至少可以说明：</p>
<ul>
<li>JavaScript无所不在；</li>
<li>它速度快而且越来越快；</li>
<li>JavaScript酷似低级的Web编程语言；</li>
<li>它可以通过手工编写，也可以从另一种语言编译而来。</li>
</ul>
<p>作为开发人员或者设计人员，如果有工具提供了你需要的控制和你需要的结果，你最关心哪一个？我认为Rails、ASP.NET，甚至GWT，都没有100%做到这一点。它们都有自己的问题，但<strong>我认为将来的Web不会再专注于清晰的标记，而是夺目的用户体验和语言、工具的天下，开发人员会很享受，效率也会更高。</strong></p>
<p>亲爱的读者，你愿意HTML和JavaScript再多抽象一点吗？还是希望它少抽象一点？</p>
<p><strong>（再更新）</strong>为了让大家明白，我得再说一遍。本文讨论了两个独立的问题。一个当然就是源代码经过了精简和通常的混淆。但这只是第一个问题。真正的问题在于，JavaScript已经成了其他多种语言的目标语言。GWT是一个用JAVA来写Web应用的框架，它产生的字节码是“JavaScript”。GWT为原来天然的语言（HTML+JS）选择了一个设计好的高级语言，并将整个浏览器当成了一个VM。好，问题来了：我们是在写汇编呢，还是在写某种更高级点的代码？而且，我刚知道Google+是用Closure来写的，但这不影响前面的问题。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cn-cuckoo.com/2011/07/20/javascript-is-assembly-language-for-the-web-i-2511.html/feed</wfw:commentRss>
		<slash:comments>25</slash:comments>
		</item>
		<item>
		<title>JavaScript，只有你想不到</title>
		<link>http://www.cn-cuckoo.com/2011/06/22/time-to-learn-javascript-2463.html</link>
		<comments>http://www.cn-cuckoo.com/2011/06/22/time-to-learn-javascript-2463.html#comments</comments>
		<pubDate>Wed, 22 Jun 2011 13:59:27 +0000</pubDate>
		<dc:creator>为之漫笔</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[编程技术]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://www.cn-cuckoo.com/?p=2463</guid>
		<description><![CDATA[原文地址：http://radar.oreilly.com/2011/06/time-to-learn-javascript.html作者简介：Mike Loukides 很长时间以来，JavaScript在我眼里都是编程语言中的二等公民。早先，它经常是很多安全问题的发源地，就像是胶水一样，它能把HTML应用与样式粘到一块，可没有人拿它来正正规规地写程序；这样的情形太普遍了。而Java、Ruby、Python，这些才是真正能用来写程序的语言。 过去几年间，我对JavaScript的态度有了彻底的改变。JavaScript已经“长大成人”了。我敢保证很多JavaScript开发人员都不会认同我前面的说法，他们会说JavaScript一直都是一个十分强大、成熟、深得人心的语言。或许他们说得没错，事实上只要是一门完整的编程语言，就能拿来写程序，也包括BASIC这种滥东西。而一门语言真正有用，必须一方面自身具备很强的表达能力，另一方面还要有众多的库和开发工具。显然，JavaScript的表达能力早就没有问题了，即便是创建对象的方式有点不好让人接受，其实问题也不大。直到最近，一些极其重要的扭转局面的技术出现了：jQuery、JSON、Node.js和HTML5。或许JavaScript以前就是一门完善的语言了，但却是这些重要的相关技术（以及其他一些没有在这里提及的），让JavaScript成为了每一个开发人员都知道的语言。如果明年你要学一门新语言的话，那一定就是JavaScript。 潜力无限的Node.js 说Node.js潜力无限的意思，就是它有可能引发Web开发的革命。Node.js是一个框架，用于构建高性能Web应用——即使是巨量的请求也能应对如流。虽然Node本身作为一个底层框架，能够用于构建任何应用，但它还是最适合构建Web服务器。它的异步事件驱动模式与传统的请求-响应模式相比，无疑更适合Web应用。 有两方面因素更让人看好Node。首先，Google在提升JavaScript性能方面掀起了一场革命。这句话的意思并不是说你随时随地都可以用上最好的JavaScript引擎（尽管这也是我们一个美好的期望）。但可以肯定的是，Google在其他竞争对手还没有上心的情况下，真的把JavaScript性能当成了一回事儿。如此一来，就把Mozilla、Apple、Microsoft、Opera，还有其他浏览器开发商逼到了性能竞赛的跑道上。结果导致我们现在使用的JavaScript引擎较之几年前快了不知道有多少倍，完全有能力运行复杂的大型Web应用。 其次，Node有着庞大的开发人员基础。不管大家在服务器端使用的是什么语言，但在客户端却鲜有不使用JavaScript的。有的人可能是“剪刀加浆糊”式的东拼西凑，有的人则可能用JavaScript做出了高超的Ajax应用，而有的人甚至实现了全功能的应用程序，像Twitter或Gmail。可不管怎么说，JavaScript开发人员的数量无疑是非常庞大的。而Doug Crockford等作者更是极力宣传所有人都应该把JavaScript当成一门严肃正经的编程语言来看待——尽管它还有不少缺点。 当时当下，编写Node应用相对还是个“粗”活儿，毕竟它只是一个底层库。想象一下单纯使用JavaScript写代码，对，就是这种感觉，Node当前还是一个beta版的格局，与Rails或Django这样成熟的Web开发框架还没法比。这种状况无疑会改变。一些轻量级的框架，比如Express，已经出现了；我坚信更多基于Node的全功能框架将继续不断涌现。 前面提到过一些几乎完全在浏览器中运行的高级Web应用。那些都已经不算什么新鲜事儿了，Gmail多大了？Google Maps贵庚了？不过，用JavaScript编写在浏览器中运行的应用的客户端无疑是越来越有吸引力了。HTML5则继续推高了人们对这一趋势的期许。 HTML5就是JavaScript 我不知道已经说过多少次了，HTML5实际上并没有多少与HTML有关，它其实就是JavaScript。HTML本身有什么变化？不过一些新标签而已，况且哪个新标签都不难理解。HTML5的威力在于让你能用JavaScript来创建这些标签。假如没有后台代码通过Canvas来创建动画、游戏，或者通过它来实现一些数据的可视化，这个标签也没有大用处。从浏览器开始支持Canvas开始，我已经看到了Asteroids（行星游戏）的上百个实现，那都是开发人员为熟悉这个新特性所做的练习。有的比较粗糙一些，而有的则极其精美。这些完全都要归功于JavaScript。 由此可见，HTML5并不是以尖括号为特征的标签语言的一次大的改进，其实质是赋予了JavaScript更强大的能力。WebGL库（当前还羽翼未丰）支持在HTML5的画布中绘制实时的3D图形。HTML5的地理位置支持在浏览器中实现LBS（Location Based Service）应用——这都是手机的基本配置。而持久存储以及离线功能则为开发能与桌面应用媲美，但却在浏览器中运行的全功能应用奠定了基础。目前，就连增加多点触摸事件的实验性的库也已经出现了。凡此种种，无一不是实实在在的JavaScript特性。HTML5只是为这些高级功能的发挥提供了舞台。 退一步讲，不依赖于HTML5的浏览器端开发库也取得了长足的进步。长久以来，JavaScript一直都是在HTML中实现动态效果的不二之选。可两个问题迟迟得不到解决：一是浏览器兼容性问题，二是直接操作DOM太麻烦。jQuery让这两个问题霎那间消失得无影无踪，这个库已经成为现代基于浏览器的客户端开发的基本配置。不过，并非只有jQuery。Protovis、还有D3，都可以让你直接在浏览器中创建复杂的交互性数据可视化效果，有史以来第一次让浏览器成为了展示数据的一个重要媒介。 JavaScript与数据库，编译器与语言 就连数据库里都开始广泛使用JavaScript了！当前如火如荼的NoSQL运动的三只领头羊：CouchDB、MongoDB和Riak，都是“文档数据库”。它们保存的不是表，而是文档。这几个数据库所谓的“文档”，其实就是JSON文档，而不是Word或Excel。（Riak除了JSON文档，还支持XML和纯文本。）JSON已经成为一种被广泛采用的数据交换格式（所有现代的编程语言几乎全都有解析JSON的库），不过请注意，JSON实际上不就是一种序列化JavaScript对象的格式嘛！因此，虽然你可以在任何语言中使用JSON，但在JavaScript开发中使用它则是再自然不过的事了。况且，JSON 这个格式成为一种跨语言的标准，而不是Python、Ruby或Java等语言的序列化格式，这个事实本身足以说明JavaScript将在更加广阔的舞台上大显身手。还不仅仅如此，上述三个数据库都内置了支持JavaScript查询的能力。未来几年，更多的人都将会惊讶地发现，JavaScript和JSON还会内置到其他应用程序中！ JavaScript时代的大幕才刚刚拉开。在今年的JSConf上，一个核心主题就是“JavaScript到JavaScript的编译器”，也被人们看成是未来的一个主要趋势。Google在“编译生成JavaScript代码”方面是首开先河者。据我所知，GWT（Google Web Toolkit）应该是通过编译（从Java代码）生成JavaScript代码的第一个框架。以前我对GWT并没有太重视，只是觉得它是一个致力于拯救那些Java程序员的框架，好让他们不必因为（学习）编写JavaScript而浪费时间。可是，GWT在编译过程中对JavaScript做了那么多的优化，简直是太神了。Closure就是一个“JavaScript到JavaScript的编译器”，能够实现同样级别的优化。Traceur，这是几个星期前才冒出来的一个框架，通过它能够试验JavaScript的新特性，换句话说，它可以把带有实验性语言特性的JavaScript代码编译成可以在所有现代平台中运行的JavaScript代码。 最后，我们也开始看到了当初Java大旗下JVM语言的蓬勃景象：很多语言都在致力于编译成JavaScript！其中有一些语言比较有意思，像Coffeescript和Kaffeine，它们在风格上酷似JavaScript，但更关注弥补JavaScript的一些不够完善的地方。是不是觉得JavaScript的对象模型特有意思，可怎么看怎么有点笨笨滴，有木有？是不是一想到基于原型创建一个实际的对象都需要反反复复地定义这定义那，就望而却步了，有木有？Coffeescript对此作了明显的改进。除了完善对象模型，Coffeescript 还添加了类似列表解析（list comprehensions）的新特性，去掉了大部分花括号。就像在Python中一样，要使用缩进来区分代码块。 未来的Web服务器、取之不尽的客户端库、HTML5、数据库，乃至基于JavaScript的语言——我现在一睁眼看到的就是JavaScript！假如你曾经对JavaScript敬而远之，今年可是该学习它了。没有任何理由，真的，再不学，恐怕你就没机会跟上时代了！]]></description>
			<content:encoded><![CDATA[<p style="text-align: right;">原文地址：<a href="http://radar.oreilly.com/2011/06/time-to-learn-javascript.html">http://radar.oreilly.com/2011/06/time-to-learn-javascript.html</a><br />作者简介：<a href="http://radar.oreilly.com.cn/user/michael_loukides">Mike Loukides </a></p>
<p><a href="http://radar.oreilly.com.cn/user/michael_loukides"><img class="colorbox-2463"  src="/images/loukides.jpg" style="float:left;margin:0 1em 1em 0;" /></a>很长时间以来，JavaScript在我眼里都是编程语言中的二等公民。早先，它经常是很多安全问题的发源地，就像是胶水一样，它能把HTML应用与样式粘到一块，可没有人拿它来正正规规地写程序；这样的情形太普遍了。而Java、Ruby、Python，这些才是真正能用来写程序的语言。</p>
<p>过去几年间，我对JavaScript的态度有了彻底的改变。JavaScript已经“长大成人”了。我敢保证很多JavaScript开发人员都不会认同我前面的说法，他们会说JavaScript一直都是一个十分强大、成熟、深得人心的语言。或许他们说得没错，事实上只要是一门完整的编程语言，就能拿来写程序，也包括BASIC这种滥东西。而一门语言真正有用，必须一方面自身具备很强的表达能力，另一方面还要有众多的库和开发工具。显然，JavaScript的表达能力早就没有问题了，即便是创建对象的方式有点不好让人接受，其实问题也不大。直到最近，一些极其重要的扭转局面的技术出现了：jQuery、JSON、Node.js和HTML5。或许JavaScript以前就是一门完善的语言了，但却是这些重要的相关技术（以及其他一些没有在这里提及的），让JavaScript成为了每一个开发人员都知道的语言。如果明年你要学一门新语言的话，那一定就是JavaScript。</p>
<h2>潜力无限的Node.js</h2>
<p>说<a href="http://nodejs.org/">Node.js</a>潜力无限的意思，就是它有可能引发Web开发的革命。Node.js是一个框架，用于构建高性能Web应用——即使是巨量的请求也能应对如流。虽然Node本身作为一个底层框架，能够用于构建任何应用，但它还是最适合构建Web服务器。它的异步事件驱动模式与传统的请求-响应模式相比，无疑更适合Web应用。<span id="more-2463"></span></p>
<p>有两方面因素更让人看好Node。首先，Google在提升JavaScript性能方面掀起了一场革命。这句话的意思并不是说你随时随地都可以用上最好的JavaScript引擎（尽管这也是我们一个美好的期望）。但可以肯定的是，Google在其他竞争对手还没有上心的情况下，真的把JavaScript性能当成了一回事儿。如此一来，就把Mozilla、Apple、Microsoft、Opera，还有其他浏览器开发商逼到了性能竞赛的跑道上。结果导致我们现在使用的JavaScript引擎较之几年前快了不知道有多少倍，完全有能力运行复杂的大型Web应用。</p>
<p>其次，Node有着庞大的开发人员基础。不管大家在服务器端使用的是什么语言，但在客户端却鲜有不使用JavaScript的。有的人可能是“剪刀加浆糊”式的东拼西凑，有的人则可能用JavaScript做出了高超的Ajax应用，而有的人甚至实现了全功能的应用程序，像Twitter或Gmail。可不管怎么说，JavaScript开发人员的数量无疑是非常庞大的。而<a href="http://www.crockford.com/">Doug Crockford</a>等作者更是极力宣传所有人都应该把JavaScript当成一门严肃正经的编程语言来看待——尽管它还有不少缺点。</p>
<p>当时当下，编写Node应用相对还是个“粗”活儿，毕竟它只是一个底层库。想象一下单纯使用JavaScript写代码，对，就是这种感觉，Node当前还是一个beta版的格局，与Rails或Django这样成熟的Web开发框架还没法比。这种状况无疑会改变。一些轻量级的框架，比如<a href="http://expressjs.com/">Express</a>，已经出现了；我坚信更多基于Node的全功能框架将继续不断涌现。</p>
<p>前面提到过一些几乎完全在浏览器中运行的高级Web应用。那些都已经不算什么新鲜事儿了，<a href="http://en.wikipedia.org/wiki/History_of_Gmail">Gmail多大了</a>？<a href="http://en.wikipedia.org/wiki/Google_Maps#History">Google Maps贵庚了</a>？不过，用JavaScript编写在浏览器中运行的应用的客户端无疑是越来越有吸引力了。HTML5则继续推高了人们对这一趋势的期许。</p>
<h2>HTML5就是JavaScript</h2>
<p>我不知道已经说过多少次了，HTML5实际上并没有多少与HTML有关，它其实就是JavaScript。HTML本身有什么变化？不过一些新标签而已，况且哪个新标签都不难理解。HTML5的威力在于让你能用JavaScript来创建这些标签。假如没有后台代码通过Canvas来创建动画、游戏，或者通过它来实现一些数据的可视化，这个标签也没有大用处。从浏览器开始支持Canvas开始，我已经看到了<a href="http://www.kevs3d.co.uk/dev/asteroids/">Asteroids</a>（行星游戏）的上百个实现，那都是开发人员为熟悉这个新特性所做的练习。有的比较粗糙一些，而有的则极其精美。这些完全都要归功于JavaScript。</p>
<p>由此可见，HTML5并不是以尖括号为特征的标签语言的一次大的改进，其实质是赋予了JavaScript更强大的能力。<a href="http://en.wikipedia.org/wiki/WebGL">WebGL</a>库（当前还羽翼未丰）支持在HTML5的画布中绘制实时的3D图形。HTML5的地理位置支持在浏览器中实现LBS（Location Based Service）应用——这都是手机的基本配置。而持久存储以及离线功能则为开发能与桌面应用媲美，但却在浏览器中运行的全功能应用奠定了基础。目前，就连<a href="http://ajaxian.com/archives/iphone-web-multitouch-javascript-virtual-light-table">增加多点触摸事件的实验性的库</a>也已经出现了。凡此种种，无一不是实实在在的JavaScript特性。HTML5只是为这些高级功能的发挥提供了舞台。</p>
<p>退一步讲，不依赖于HTML5的浏览器端开发库也取得了长足的进步。长久以来，JavaScript一直都是在HTML中实现动态效果的不二之选。可两个问题迟迟得不到解决：一是浏览器兼容性问题，二是直接操作DOM太麻烦。<a href="http://jquery.com/">jQuery</a>让这两个问题霎那间消失得无影无踪，这个库已经成为现代基于浏览器的客户端开发的基本配置。不过，并非只有jQuery。<a href="http://vis.stanford.edu/protovis/">Protovis</a>、<a href="https://github.com/mbostock/d3">还有D3</a>，都可以让你直接在浏览器中创建复杂的交互性数据可视化效果，有史以来第一次让浏览器成为了展示数据的一个重要媒介。</p>
<h2>JavaScript与数据库，编译器与语言</h2>
<p>就连数据库里都开始广泛使用JavaScript了！当前如火如荼的NoSQL运动的三只领头羊：<a href="http://couchdb.apache.org/">CouchDB</a>、<a href="http://www.mongodb.org/">MongoDB</a>和<a href="http://wiki.basho.com/">Riak</a>，都是“文档数据库”。它们保存的不是表，而是文档。这几个数据库所谓的“文档”，其实就是<a href="http://www.json.org/">JSON</a>文档，而不是Word或Excel。（Riak除了JSON文档，还支持XML和纯文本。）JSON已经成为一种被广泛采用的数据交换格式（所有现代的编程语言几乎全都有解析JSON的库），不过请注意，JSON实际上不就是一种序列化JavaScript对象的格式嘛！因此，虽然你可以在任何语言中使用JSON，但在JavaScript开发中使用它则是再自然不过的事了。况且，JSON 这个格式成为一种跨语言的标准，而不是Python、Ruby或Java等语言的序列化格式，这个事实本身足以说明JavaScript将在更加广阔的舞台上大显身手。还不仅仅如此，上述三个数据库都内置了支持JavaScript查询的能力。未来几年，更多的人都将会惊讶地发现，JavaScript和JSON还会内置到其他应用程序中！</p>
<p>JavaScript时代的大幕才刚刚拉开。在今年的<a href="http://2011.jsconf.us/">JSConf</a>上，一个核心主题就是“JavaScript到JavaScript的编译器”，也被人们看成是未来的一个主要趋势。Google在“编译生成JavaScript代码”方面是首开先河者。据我所知，<a href="http://code.google.com/webtoolkit/">GWT（Google Web Toolkit）</a>应该是通过编译（从Java代码）生成JavaScript代码的第一个框架。以前我对GWT并没有太重视，只是觉得它是一个致力于拯救那些Java程序员的框架，好让他们不必因为（学习）编写JavaScript而浪费时间。可是，GWT在编译过程中对JavaScript做了那么多的优化，简直是太神了。<a href="http://code.google.com/closure/compiler/">Closure</a>就是一个“JavaScript到JavaScript的编译器”，能够实现同样级别的优化。<a href="http://code.google.com/p/traceur-compiler/">Traceur</a>，这是几个星期前才冒出来的一个框架，通过它能够试验JavaScript的新特性，换句话说，它可以把带有实验性语言特性的JavaScript代码编译成可以在所有现代平台中运行的JavaScript代码。</p>
<p>最后，我们也开始看到了当初Java大旗下JVM语言的蓬勃景象：<a href="https://github.com/jashkenas/coffee-script/wiki/List-of-languages-that-compile-to-JS">很多语言都在致力于编译成JavaScript</a>！其中有一些语言比较有意思，像<a href="http://jashkenas.github.com/coffee-script/">Coffeescript</a>和<a href="http://weepy.github.com/kaffeine/">Kaffeine</a>，它们在风格上酷似JavaScript，但更关注弥补JavaScript的一些不够完善的地方。是不是觉得JavaScript的对象模型特有意思，可怎么看怎么有点笨笨滴，有木有？是不是一想到基于原型创建一个实际的对象都需要反反复复地定义这定义那，就望而却步了，有木有？Coffeescript对此作了明显的改进。除了完善对象模型，Coffeescript 还添加了类似列表解析（list comprehensions）的新特性，去掉了大部分花括号。就像在Python中一样，要使用缩进来区分代码块。</p>
<p>未来的Web服务器、取之不尽的客户端库、HTML5、数据库，乃至基于JavaScript的语言——我现在一睁眼看到的就是JavaScript！假如你曾经对JavaScript敬而远之，今年可是该学习它了。没有任何理由，真的，再不学，恐怕你就没机会跟上时代了！</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cn-cuckoo.com/2011/06/22/time-to-learn-javascript-2463.html/feed</wfw:commentRss>
		<slash:comments>63</slash:comments>
		</item>
		<item>
		<title>2010年美国计算机图书市场报告二：分类市场</title>
		<link>http://www.cn-cuckoo.com/2011/02/22/2010-book-market-of-usa-2-2329.html</link>
		<comments>http://www.cn-cuckoo.com/2011/02/22/2010-book-market-of-usa-2-2329.html#comments</comments>
		<pubDate>Tue, 22 Feb 2011 15:27:54 +0000</pubDate>
		<dc:creator>为之漫笔</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[出版]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[移动开发]]></category>
		<category><![CDATA[编程技术]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://www.cn-cuckoo.com/?p=2329</guid>
		<description><![CDATA[http://radar.oreilly.com/2011/02/2010-book-market-2.html Mike Hendrickson 2011-2-14 报告内容 第一部分：市场综述 第二部分：分类市场 第三部分：出版商 第四部分：编程语言 第五部分：完结篇及数字出版 下载完整版（PDF） 在这一部分，我们按照技术门类来分析一下计算机图书的销售情况。 在上一部分，我们把数据分成六大“门类”：系统与程序设计、Web设计与开发、商业应用、数字媒体应用、消费者操作系统与设备、IT人文（Computer Topics）。 这六大门类下面，是一级分类、二级分类、三级分类、四级分类，一共5层。比如说，系统与程序设计门类下面的一级分类有编程语言、数据库、软件工程、通用程序设计、安全，等等。 本部分将对比2010年与2009年的第四季度，也会将2010年与2009年的情况进行对比。 为了方便起见，下面给出了上一部分中展示过的Treemap，其中包含各个门类与一级门类2010年与2009年第四季度的对比。 这张图中的红、绿、黑色方块基本上反映了市场的波动情况。其中，代表高度增长领域的浅绿色方块非常少。但不要忘了这是2010年第四季度与2009年第四季度的对比。两个最大、最亮的绿色区域是“Android编程”和“Android消费者应用”，这两类图书从2008年微不足道的小方块成长为2010年相当可观的大市场。 下面的两张图可以反映出各图书门类历年的增长情况。第一张图是历年构成Top 3000的图书品种，而第二张图是历年来的图书销量。从中可以看出，“商业应用/人文”和“系统与程序设计”类图书的品种在2010年都增加了，但这两类图书的销量却是双双下跌的。“消费者操作系统与设备”是唯一一个出书品种和销量在2010年双增的门类。“系统与程序设计”是最大的一个门类，但其销售业绩也更加不稳定，2010年经历了最大的一次整体下滑。“系统与程序设计”是计算机图书市场的风向标，计算机（纸质）图书市场整体也是下滑的。在随后关于数字发行的部分中，我们还会展示一些更积极的信息。 历年的图书品种 历年的图书销量 下面这张表格列出了各个门类2009年到2010年的增长情况（YoY）、2009和2010年的排名情况（09Rand/10Rank）以及2009、2010年的市场份额百分比（09Share/10Share）。 门类 YoY Growth 09Rank 10Rank 09Share 10Share 商业应用 -05.10% 2nd 2nd 20.60% 21.00% IT人文及其他 04.09% 6th 6th 02.82% 03.15% 消费者操作系统 04.22% 4th 3rd 15.44% 17.27% 数字媒体 -18.32% 5th 5th 10.66% 09.65% 系统与程序设计 [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://radar.oreilly.com/2011/02/2010-book-market-2.html">http://radar.oreilly.com/2011/02/2010-book-market-2.html</a><br />
Mike Hendrickson<br />
2011-2-14</p>
<div style="float:right; border:1px solid #ddd;border-width:0 0 1px 1px;padding:0 .5em;margin:0 0 0 .5em;">
<p style="font-weight:bold;">报告内容</p>
<ol>
<li><a href="http://www.cn-cuckoo.com/2011/02/26/2010-book-market-of-usa-1-2287.html">第一部分：市场综述</a></li>
<li><a href="http://www.cn-cuckoo.com/2011/02/23/2010-book-market-of-usa-2-2329.html">第二部分：分类市场</a></li>
<li><a href="http://www.cn-cuckoo.com/2011/02/23/2010-book-market-of-usa-3-2270.html">第三部分：出版商</a></li>
<li><a href="http://www.cn-cuckoo.com/2011/02/23/2010-book-market-of-usa-4-2265.html">第四部分：编程语言</a></li>
<li><a href="http://www.cn-cuckoo.com/2011/02/25/2010-book-market-of-usa-5-2279.html">第五部分：完结篇及数字出版</a></li>
</ol>
<div style="text-align:center;">
<a href="http://u.115.com/file/f661fc6f86"><br />
<img class="colorbox-2329"  style="border:1px solid #eee;" src="http://ww1.sinaimg.cn/large/61baa48djw6deqves2ryvj.jpg"/><br />
</a><br />
<a href="http://u.115.com/file/f661fc6f86">下载完整版（PDF）</a>
</div>
</div>
<p>在这一部分，我们按照技术门类来分析一下计算机图书的销售情况。</p>
<p>在上一部分，我们把数据分成六大“门类”：系统与程序设计、Web设计与开发、商业应用、数字媒体应用、消费者操作系统与设备、IT人文（Computer Topics）。</p>
<p>这六大门类下面，是一级分类、二级分类、三级分类、四级分类，一共5层。比如说，系统与程序设计门类下面的一级分类有编程语言、数据库、软件工程、通用程序设计、安全，等等。</p>
<p>本部分将对比2010年与2009年的第四季度，也会将2010年与2009年的情况进行对比。</p>
<p>为了方便起见，下面给出了上一部分中展示过的Treemap，其中包含各个门类与一级门类2010年与2009年第四季度的对比。</p>
<p><img class="colorbox-2329"  src="http://radar.oreilly.com/upload/2011/02/cat_yoy_QTR4.jpg"/></p>
<p>这张图中的红、绿、黑色方块基本上反映了市场的波动情况。其中，代表高度增长领域的浅绿色方块非常少。但不要忘了这是2010年第四季度与2009年第四季度的对比。两个最大、最亮的绿色区域是“Android编程”和“Android消费者应用”，这两类图书从2008年微不足道的小方块成长为2010年相当可观的大市场。<br />
<span id="more-2329"></span><br />
下面的两张图可以反映出各图书门类历年的增长情况。第一张图是历年构成Top 3000的图书品种，而第二张图是历年来的图书销量。从中可以看出，“商业应用/人文”和“系统与程序设计”类图书的品种在2010年都增加了，但这两类图书的销量却是双双下跌的。“消费者操作系统与设备”是唯一一个出书品种和销量在2010年双增的门类。“系统与程序设计”是最大的一个门类，但其销售业绩也更加不稳定，2010年经历了最大的一次整体下滑。“系统与程序设计”是计算机图书市场的风向标，计算机（纸质）图书市场整体也是下滑的。在随后关于数字发行的部分中，我们还会展示一些更积极的信息。</p>
<h2>历年的图书品种</h2>
<p><img class="colorbox-2329"  src="http://radar.oreilly.com/upload/2011/01/Cat_family_Titles.jpg"/></p>
<h2>历年的图书销量</h2>
<p><img class="colorbox-2329"  src="http://radar.oreilly.com/upload/2011/01/Cat_family_Units.jpg"/></p>
<p>下面这张表格列出了各个门类2009年到2010年的增长情况（YoY）、2009和2010年的排名情况（09Rand/10Rank）以及2009、2010年的市场份额百分比（09Share/10Share）。</p>
<table border="1">
<tbody>
<tr>
<td align=center><strong>门类</strong></td>
<td><strong>YoY Growth</strong></td>
<td><strong>09Rank</strong></td>
<td><strong>10Rank</strong></td>
<td><strong>09Share</strong></td>
<td><strong>10Share</strong></td>
</tr>
<tr>
<td>商业应用</td>
<td align=right>-05.10%</td>
<td align=right>2nd</td>
<td align=right>2nd</td>
<td align=right>20.60%</td>
<td align=right>21.00%</td>
</tr>
<tr>
<td>IT人文及其他</td>
<td align=right>04.09%</td>
<td align=right>6th</td>
<td align=right>6th</td>
<td align=right>02.82%</td>
<td align=right>03.15%</td>
</tr>
<tr>
<td>消费者操作系统</td>
<td align=right>04.22%</td>
<td align=right>4th</td>
<td align=right>3rd</td>
<td align=right>15.44%</td>
<td align=right>17.27%</td>
</tr>
<tr>
<td>数字媒体</td>
<td align=right>-18.32%</td>
<td align=right>5th</td>
<td align=right>5th</td>
<td align=right>10.66%</td>
<td align=right>09.65%</td>
</tr>
<tr>
<td>系统与程序设计</td>
<td align=right>-03.32%</td>
<td align=right>1st</td>
<td align=right>1st</td>
<td align=right>33.39%</td>
<td align=right>34.62%</td>
</tr>
<tr>
<td>Web 设计与开发</td>
<td align=right>-28.01%</td>
<td align=right>3rd</td>
<td align=right>4th</td>
<td align=right>17.10%</td>
<td align=right>14.32%</td>
</tr>
</tbody>
</table>
<p>在继续深入分析各门类之前，我们先来看看2010年出版的所有计算机图书的书名中出现的关键词。这是一个非常有意思的角度，因为这些关键词会出现在图书封面上、在线搜索中，以及任何相关内容的元数据中。说明一点：我把the、and、it、with等停顿词都过滤掉了。此外，Microsoft这个词因为被用于描述很多种产品，重复次数太多，也被我忽略了。下面就是这张图书市场的“书名关键词”图。</p>
<p><img class="colorbox-2329"  src="http://radar.oreilly.com/upload/2011/01/titles.jpg"/></p>
<p>深入分析各门类图书后，我们发现在排名前10的二级分类中，有7个在2010年销量少于2009年，前20个二级分类销量净减少了244,936册。换句话说，在相对较大而且一般也较为稳定的领域，图书销量在2010年明显下降。2010年上半年，有49个二级分类销量领先于2009年上半年，而其中有6个二级分类下半年增长放缓、优势尽丧，最终导致全年销量下降。结果，2010年有43个二级分类的销量超过2009年。按照销量增长多少排序，这些二级分类分别是：平板电脑、移动编程、Windows应用、安全、硬件、社交网站、计算机与安全、云计算、信息技术和数据处理。其中平板电脑类图书2010年上半年的销量大约为15,000册，而下半年销量猛增至100,000册。图书品种的增多加快了这种增长——2010年上半年版权输出7种，而下半年底达到22种，是上半年的3倍。而图书销量下降幅度最大的领域依次是：网页制作、数字图像、Mac OS、Flash、Web程序设计、网页设计工具、个人电脑、Linux、软件项目管理和个人数据库。最让我吃惊的领域是Web程序设计。2010年上榜的Web程序设计类图书减少了16种，只有7%的图书销量过千，而这个比例在2009年是11%。</p>
<p>在市场持续下滑的同时，很多出版商的反应就是增加出书的数量，希望通过品种增加来获得市场份额。下面两张图显示的分别是Bookscan监控到的图书品种数，以及所有图书的单品平均销量。有一点似乎并不是显而易见：在没有必要多出那么多种书的情况下，居然有那么多新书说出就出了。这一切可能就要归结为上榜的门槛太低了。换句话说，有几周Top 3000中图书的销量都低到了只有6册。这个问题可以相对来看。前两年，低门槛的问题已经显现了，导致打榜的图书品种虽多，但单品的平均销量却不尽人意。如果市场良性发展，门槛自然会提高，因而只有销售业绩真好的图书才能进入Top 3000。低门槛的结果就是所有出版商的单品平均销量都在明显减少。除了22家最大的出版公司之外，2010年榜上有名的另外18家出版公司也增加了出书品种。然而，这18家出版公司中只有6家在多出书的同时也做到了单品平均销量的增长。因此，关键在于，进入Top 3000行列的图书品种可以增加，但如果进入的门槛太低，那么平均销量和总销量照样也会跟着低。</p>
<h2>图书品种</h2>
<p><img class="colorbox-2329"  src="http://radar.oreilly.com/upload/2011/01/TitlesPerYear.jpg"/></p>
<h2>平均销量</h2>
<p><img class="colorbox-2329"  src="http://radar.oreilly.com/upload/2011/01/AvgUnitsYear.jpg"/></p>
<p>下面这张表格显示了市场被稀释的结果。平均最低值意味着给定年度内每周的“低门槛”水平。平均最高值则是给定年度内每周的最高销量。品种数的含义不言自明。数据显示，平均最低值越高，对应的年度图书品种数越少。总而言之，投入市场的图书品种越多，品种多销量少的稀释效应就会越明显。</p>
<table border="1">
<tbody>
<tr>
<td align=center><strong>年份</strong></td>
<td><strong>平均最低值</strong></td>
<td><strong>平均最高值</strong></td>
<td><strong>品种数</strong></td>
</tr>
<tr>
<td>2004</td>
<td align=right>9.2</td>
<td align=right>1,133</td>
<td align=right>7,451</td>
</tr>
<tr>
<td>2005</td>
<td align=right>9.6</td>
<td align=right>1,099</td>
<td align=right>7,123</td>
</tr>
<tr>
<td>2006</td>
<td align=right>9.6</td>
<td align=right>1,315</td>
<td align=right>6,881</td>
</tr>
<tr>
<td>2007</td>
<td align=right>9.4</td>
<td align=right>1,348</td>
<td align=right>7,092</td>
</tr>
<tr>
<td>2008</td>
<td align=right>8.2</td>
<td align=right>1,534</td>
<td align=right>7,310</td>
</tr>
<tr>
<td>2009</td>
<td align=right>7.3</td>
<td align=right>1,057</td>
<td align=right>7,557</td>
</tr>
<tr>
<td>2010</td>
<td align=right>6.7</td>
<td align=right>1,112</td>
<td align=right>7,792</td>
</tr>
</table>
<p>因此，可以说我们现在正处于技术创新的低迷阶段。有什么技术、平台、方法、理论或者什么新点子，能让我们走出这个市场低迷期吗？还是说，出版商只能一味地多出书，而不管码洋是不是受损失，放任既有的市场空间被多出来的书稀释掉，难道真的就只能这样原地打转、束手无策吗？我认为是后一种情况。只能等有一天，突然大量的需求出现，才能把现在的市场托起来。我说不好这股需求到底是来自云计算、移动应用，还是社会化平台，当然也可能来自其他蓄势待发的潜力领域。未来5年哪个领域可能会有大的增长？有没有酝酿已久的将会对技术世界产生巨大影响的事物？</p>
<p>现在，我们来分析一下构成各大门类的细分类别。下面首先给出了一组趋势图，显示了从2009年1月到2010年12月24个月期间各个主要类别的市场表现。以24个月为周期，能够更清楚地看出某个特定领域是否会受到季节性因素的影响，该领域是不是在持续增长，还是持续下跌。大家在看图的时候，别忘记图中的曲线反映的是相对市场规模，因此纵轴上的市场规模绝对值不容忽视。另外，还有一种简便的判断方法，即曲线在方框图中的位置越高，说明其市场规模越大，反之市场规模越小。有意思的是，消费者操作系统、数字媒体、商业应用与设备这些类别在1月份都有一个很高的起点，这很可能是因为不少读者会因为买了新电脑、新设备或新操作系统，需要看一些入门指南类的图书。这其实就是明显的季节性特征。</p>
<table border=0>
<tr>
<td align=right>IT人文</td>
<td align=right>数字媒体</td>
<td align=right>Web开发与设计</td>
<tr>
<td>
<div class="ap_r"><a href="http://radar.oreilly.com/upload/2011/01/CT.png" class="highslide" onclick="return hs.expand(this)"><img class="colorbox-2329"  src="http://radar.oreilly.com/upload/2011/01/CT.png" alt="CT.png"/></a></div>
</td>
<td>
<div class="ap_r"><a href="http://radar.oreilly.com/upload/2011/01/DM.png" class="highslide" onclick="return hs.expand(this)"><img class="colorbox-2329"  src="http://radar.oreilly.com/upload/2011/01/DM.png" alt="DM.png"/></a></div>
</td>
<td>
<div class="ap_r"><a href="http://radar.oreilly.com/upload/2011/01/WD.png" class="highslide" onclick="return hs.expand(this)"><img class="colorbox-2329"  src="http://radar.oreilly.com/upload/2011/01/WD.png" alt="WD.png"/></a></div>
</td>
</tr>
<td align=right>消费者操作系统与设备</td>
<td align=right>商业应用</td>
<td align=right>系统与程序设计</td>
<tr>
<td>
<div class="ap_r"><a href="http://radar.oreilly.com/upload/2011/01/CO.png" class="highslide" onclick="return hs.expand(this)"><img class="colorbox-2329"  src="http://radar.oreilly.com/upload/2011/01/CO.png" alt="CO.png"/></a></div>
</td>
<td>
<div class="ap_r"><a href="http://radar.oreilly.com/upload/2011/01/ba.png" class="highslide" onclick="return hs.expand(this)"><img class="colorbox-2329"  src="http://radar.oreilly.com/upload/2011/01/ba.png" alt="ba.png"/></a></div>
</td>
<td>
<div class="ap_r"><a href="http://radar.oreilly.com/upload/2011/01/SP.png" class="highslide" onclick="return hs.expand(this)"><img class="colorbox-2329"  src="http://radar.oreilly.com/upload/2011/01/SP.png" alt="SP.png"/></a></div>
</td>
</tr>
</table>
<h1>细分门类分析（以24个月为周期，从2009年1月到2010年12月）</h1>
<p>在理解下面给出的细分门类的相关图表时，请参考上面的各大门类的趋势图。通过这些图表，可以更深入地了解细分门类的市场规模以及季节变化规律。</p>
<h2>门类：消费者操作系统与设备</h2>
<p>以下是消费者操作系统与设备门类下的4个细分门类的趋势线。</p>
<p><img class="colorbox-2329"  src="http://radar.oreilly.com/upload/2011/01/CO_1.jpg"/><br />
<img class="colorbox-2329"  src="http://radar.oreilly.com/upload/2011/01/CO_2.jpg"/></p>
<p>这是一个中等规模的门类，也是两个跨年度增长的门类之一。这个门类的增长主要由Windows 7和便携设备（Port Dev）子类别驱动。便携设备子类别2010年由Android领衔，2009年则是iPhone挂帅。前面我们提到过，平板电脑子类别在2010年下半年的表现非常突出，曲线上扬得很快。Andy Rathbone的新书Windows 7 For Dummies名列榜首，另外两本Windows 7的图书排名第二和第三。婵连销售冠军的<a href="http://oreilly.com/catalog/9780596153298"><em>Mac OS X Snow Leopard: The Missing Manual</em></a>下落到第四位，由于Snow Leopard并非苹果公司的一个重要OS版本，因而相关主题的图书没有像往年一样拉动所属类别的增长。</p>
<p>虽然在Mac OS X爆炸性增长的带动下，这个市场也曾经增长过，但仍然还是不能与Windows图书相比，后者一直都稳居畅销排行榜之列，而且近两年也实现了增长。下面这张柱形图显示了Mac OS与Windows图书历年累计销量的对比情况。你使用PC还是Mac？这张图说明，还是使用PC的读者更多！</p>
<p><img class="colorbox-2329"  src="http://radar.oreilly.com/upload/2011/01/MacOSxWindows.jpg"/></p>
<h2>门类：商业/办公应用</h2>
<p>2009与2010年商业应用类图书相比，有8个一级分类的表现好于上一年，有23个表现不如上一年。而这23个表现不佳的分类减少的销量比8个增长的分类多卖的销量还要多，相比之下，净损失67,000册，总体增长率为-5.10%。</p>
<p>两个最健康的一级分类是电子表格（Excel）和社交网络（Facebook），分别实现了2.42%和11.49%的增长率。两个最后进的一级分类是图形应用（Graphics Applications）和电子商务，增长率分别是-1.80%和-47.00%。最让我不理解的是，CMS（Content Management Systems，内容管理系统）没有像我想象得那样增长。为此，我查了几年的数据，发现CMS图书增长最快的时期是2006至2009年。而在过去的两年，这个分类的市场保持稳定，与整体市场下滑相比表现还是不错的。下面就是CMS图书历年的销量柱形图。</p>
<h3>CMS图书历年销量</h3>
<p><img class="colorbox-2329"  src="http://radar.oreilly.com/upload/2011/01/CMS_Units_Years.jpg"/></p>
<p>以下是商业/办公门类中三个主要领域的趋势图。</p>
<p><img class="colorbox-2329"  src="http://radar.oreilly.com/upload/2011/01/BA_1.jpg"/></p>
<p>注意，“办公应用”这个分类的市场规模与另外两个分类（“一般商业应用”和“设计”）相比有多么大。但这个分类的市场表现略有下降，销量从2009年的196,722册下降到2010年的187,968册，增长率为-4.66%。这个增长率（下降率）与计算机整体市场的增长率（-4.54%）相差无几。办公应用类图书的王者是“阿呆系列”（Dummies）。2010年排名前三的都是阿呆系列，而且前10名的位子中阿呆系列占到了7席。想想也难怪，Excel之类的软件又不是什么高端技术，因此阿呆系列图书受到了各类读者的广泛青睐，其中既有闻技术而色变的普通老百姓，也不乏满脑子前沿技术的高端学者。对办公应用这个领域，即使称它为“阿呆帝国”恐怕也不过分。</p>
<h2>门类：Web设计与开发</h2>
<p>2010年与2009年相比，Web设计与开发类图书的销量下降了28.01%，251,000册。但是别忘了，2009年可是整体市场最差的一年了。这个门类中只有两个一级分类实现了增长：JavaScript和社交网站，增长率分别是7.81%和7.18%。我们出的<a href="http://oreil.ly/egQEmN"><em>Learning PHP, MySQL, and JavaScript</em></a>是这个门类中卖得最好的一本书。最令人吃惊的是，网页制作类图书的销量与2009相比，骤减70,000册（别忘了，2009年已经很糟糕了）。是人们的兴趣从HTML转移到PHP、JavaScript和CMS上面去了吗？还是大家都跑去开发能访问自己网页的移动应用了呢？</p>
<p>以下三张趋势图展示的是Web设计与开发门类中三个主要的分类。</p>
<p><img class="colorbox-2329"  src="http://radar.oreilly.com/upload/2011/01/WD_1.jpg"/></p>
<p>显然，最大的子类别是“网站建设”。这个子类别中占主导地位的图书，讨论的都是性能、可扩展性、可靠性以及调优等，都是能在我们的<a href="http://velocityconf.com/velocity2011">Velocity Conference</a>和<a href="http://bit.ly/bundles/mikehatora/3">推荐书目</a>中找到的话题。富Web界面在各子类别中位居第二，但总体是下滑趋势。在这个类别中，Flash和Silverlight的下降幅度最大。Flash下降幅度为-84.43%，Silverligth是-8.29%。不过，Flash的市场规模仍然是Silverlight的4倍。难道是HTML5让这两种技术失宠了吗？</p>
<h2>门类：系统与程序设计</h2>
<p>这是计算机图书市场中最大的一个门类。这个门类囊括了绝大多数编程语言、数据库和软件开发类的图书。这个门类的正常趋势是年初有一个不错的开端，而后到9月份（大学生开学）又会冲到一个高点。这个门类包含67个子类别，2010年有44个领域出现了负增长，只有23个领域是正增长，正负相抵，2010年整个门类的销量净减少72,024册。算下来，下降幅度只有-3.32%，因此这个大门类的实际市场表现还是好于整体市场的。在增长的二级分类中，位列前5的依次是移动编程、安全、云计算、信息技术和数据处理。业绩最差的二级分类中，前5名分别是：Linux、软件项目管理、个人数据库、Visual Basic和SQL Server。在增长率最高的移动编程领域，iPhone编程是2009年主流，而Android编程则是2010年的热门。注意，这些图书谈论的不是怎么玩iPhone或Droid手机，而是怎么开发移动应用。2009年，iOS类图书的市场规模是Android的9倍，而2010年大约是2.5倍。</p>
<p>以下是系统与程序设计门类中9个一级分类的前3名的趋势图。</p>
<p><img class="colorbox-2329"  src="http://radar.oreilly.com/upload/2011/01/SyPro_1.jpg"/></p>
<p>注意一下每个分类的整体规模。编程语言（prog lang）仍然是最大的一级分类，而程序设计（prog）已经从第三跃居第二。算上2010年，数据库已经连续下滑了三年了。如前所述，软件项目管理是2010年最大的失败者，但它仍然还是系统与程序设计门类中的第三大二级分类，前面的两个二级分类是移动编程和安全。不过，与SPM（系统与程序设计市场）的整体下滑相对应，移动编程和安全也都是下滑的。另一个从名不见经传成长为可观的二级分类的是数据处理。这个类别中的很多书与我们<a href="http://bit.ly/bundles/mikehatora/4"> Strata Conference及Data Science 资源</a>中的一些访谈、对话和文章是类似的。</p>
<p>第二组一级分类的趋势图与其他门类的一级分类相比，波动不是那么大。这组曲线的趋势虽然平缓，但都带有明显的季节性销售的特征。</p>
<p><img class="colorbox-2329"  src="http://radar.oreilly.com/upload/2011/01/SyPro_2.jpg"/></p>
<p>对比2009年与2010年全年的数据可以发现，软件工程（sw engr）是这一组中最大的一级分类，经典著作<em>The Mythical Man-Month: Essays on Software Engineering, Anniversary Edition</em>和新经典<em>Coders at Work: Reflections on the Craft of Programming</em>是软件工程类的榜首图书。网络类图书由CompTIA（Computer Technology Industry Association，美国计算机行业协会）的资格认证图书占据，前10名中有5本书都是它们的，包括前2名。</p>
<p>第三组趋势线由CISSP（Certified Information System Security Professional，信息系统安全认证专业人员）、电脑入侵及CompTIA安全类图书主导。</p>
<p><img class="colorbox-2329"  src="http://radar.oreilly.com/upload/2011/01/SyPro_3.jpg"/></p>
<p>接下来的第三部分，将分析出版商，包括赢家和输家。第四部分将对编程语言类图书市场进行更深入的分析。而第五部分将关注数字出版。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cn-cuckoo.com/2011/02/22/2010-book-market-of-usa-2-2329.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>2010年美国计算机图书市场报告一：市场综述</title>
		<link>http://www.cn-cuckoo.com/2011/02/21/2010-book-market-of-usa-1-2287.html</link>
		<comments>http://www.cn-cuckoo.com/2011/02/21/2010-book-market-of-usa-1-2287.html#comments</comments>
		<pubDate>Mon, 21 Feb 2011 04:59:35 +0000</pubDate>
		<dc:creator>为之漫笔</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[交互设计]]></category>
		<category><![CDATA[出版]]></category>
		<category><![CDATA[编程技术]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://www.cn-cuckoo.com/?p=2287</guid>
		<description><![CDATA[http://radar.oreilly.com/2011/02/2010-book-market-1.html Mike Hendrickson 2011-2-10 报告内容 第一部分：市场综述 第二部分：分类市场 第三部分：出版商 第四部分：编程语言 第五部分：完结篇及数字出版 下载完整版（PDF） 自从上一次计算机图书市场报告发表之后的两年来，技术图书市场经历了一些重大的变化。恐怕不少读者根据图书市场日益疲软的征兆，已经看到未来发展的某些趋势了。实际上，我们早就断言过计算机图书销售情况预示着技术发展的趋势，大家也可以搜索一下有关计算机图书市场的其他文章。 本报告的数据来自Bookscan每周监控到的Top 3000图书的销售情况。Bookscan计量的是书店收银机的实际销售数据。换句话说，只要你在美国的书店里买过一本技术书，那么你购买这本书的信息十有八九已经进入了Bookscan的数据库里。Borders、Barnes &#038; Noble以及Amazon等零售商实现了绝大多数技术图书的销售。 图书市场业绩综述 在讨论细分的计算机图书市场之前，我们先来了解一下截止到2011年1月2日这个周末，整个图书市场的表现情况。下面这张表涵盖了从The Girl with the Dragon Tatoo and Eat, Pray, Love to Decision Points到The Ugly Truth的所有图书，只要是印刷、装订并以书的形式销售的，都包含在里面。 整体图书市场表现（所有图书，数据截止日期2011年1月2日） 所有图书，所有题材 青少年非虚构 -0.44% 青少年虚构 -3.46% 青少图书整体 -2.88% 成人非虚构 -1.91% &#160;&#160;&#160;&#160;计算机及互联网 -3.99% 成人虚构 -7.20% 其他 -13.12% 整体市场 -4.54% 从表中可以看出，计算机图书市场较上年下滑了4%。需要注意的是，计算机图书的销售量只占实体和在线书店所有图书总销量的1%。下面这张图展示的整体图书市场各门类的业绩增长情况。其中，幽默（Humor）类图书的增长在普遍低迷的市场背景下显得独树一帜（14.45%）。另一个增长的领域是青少年非虚构类中的教材/教辅类（21.55%）。我很奇怪，为什么教材/教辅类图书居然有这么高的增长率。 整体图书市场增长情况 下面言归正传，看看技术图书市场。下面这张柱形图展示的是各年份累计图书销量的对比情况。从图中可以看出，每年的总销量从2007年开始逐年递减。2007年的时候，不少人认为市场会中止2001年以来一路下跌的态势，开始进入恢复期，但2009年较上一年的跌幅达到了历年最大值。 而下面这张折线图展示的是自2004年以来计算机图书市场每周的市场表现情况（根据我们从Bookscan获得的第一手数据生成）。请注意，这个图反映的是所有出版商，而不仅仅是O&#8217;Reilly。图中稍粗一点的红线表示2010年的数据。 从图中可以看出，我们提到过的明显的季节性特征依然存在。换句话说，每年开始都会强势上扬，然后一直到夏季逐步走低，到了秋天“返校”的季节开始止跌回升，到了年底又强势收尾。图中每年的趋势线都与上一年的趋势线非常接近，甚至连每周的涨跌都十分一致。在24个月来乏善可陈的市场表现中，唯一能让人感到一点慰藉的是，2009年每周销量与上一年度比有10-15%是下降的，而这个比例在2010年减少到了3-6%。但这能说明市场已经见底了吗，还是说我们也像读者思考着怎样才能学到新技术一样处于观望状态？如今，销售图书的方式更多了（后面几部分中会介绍），不少出版商通过不同数字格式来销售相同的内容实现了码洋与销量的双增长。而有些出版商纸质书发行量的降低，也通过数字发行和销售得到了补偿。 [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://radar.oreilly.com/2011/02/2010-book-market-1.html">http://radar.oreilly.com/2011/02/2010-book-market-1.html</a><br />
Mike Hendrickson<br />
2011-2-10</p>
<div style="float:right; border:1px solid #ddd;border-width:0 0 1px 1px;padding:0 .5em;margin:0 0 0 .5em;">
<p style="font-weight:bold;">报告内容</p>
<ol>
<li><a href="http://www.cn-cuckoo.com/2011/02/26/2010-book-market-of-usa-1-2287.html">第一部分：市场综述</a></li>
<li><a href="http://www.cn-cuckoo.com/2011/02/23/2010-book-market-of-usa-2-2329.html">第二部分：分类市场</a></li>
<li><a href="http://www.cn-cuckoo.com/2011/02/23/2010-book-market-of-usa-3-2270.html">第三部分：出版商</a></li>
<li><a href="http://www.cn-cuckoo.com/2011/02/23/2010-book-market-of-usa-4-2265.html">第四部分：编程语言</a></li>
<li><a href="http://www.cn-cuckoo.com/2011/02/25/2010-book-market-of-usa-5-2279.html">第五部分：完结篇及数字出版</a></li>
</ol>
<div style="text-align:center;">
<a href="http://u.115.com/file/f661fc6f86"><br />
<img class="colorbox-2287"  style="border:1px solid #eee;" src="http://ww1.sinaimg.cn/large/61baa48djw6deqves2ryvj.jpg"/><br />
</a><br />
<a href="http://u.115.com/file/f661fc6f86">下载完整版（PDF）</a>
</div>
</div>
<p>自从上一次计算机图书市场报告发表之后的两年来，技术图书市场经历了一些重大的变化。恐怕不少读者根据图书市场日益疲软的征兆，已经看到未来发展的某些趋势了。实际上，我们早就断言过<a href="http://radar.oreilly.com/archives/2005/04/book_sales_as_a.html">计算机图书销售情况预示着技术发展的趋势</a>，大家也可以搜索一下有关计算机图书市场的其他文章。</p>
<p>本报告的数据来自Bookscan每周监控到的Top 3000图书的销售情况。Bookscan计量的是书店收银机的实际销售数据。换句话说，只要你在美国的书店里买过一本技术书，那么你购买这本书的信息十有八九已经进入了Bookscan的数据库里。Borders、Barnes &#038; Noble以及Amazon等零售商实现了绝大多数技术图书的销售。</p>
<h1>图书市场业绩综述</h1>
<p>在讨论细分的计算机图书市场之前，我们先来了解一下截止到2011年1月2日这个周末，整个图书市场的表现情况。下面这张表涵盖了从<em>The Girl with the Dragon Tatoo and Eat, Pray, Love to Decision Points</em>到<em>The Ugly Truth</em>的所有图书，只要是印刷、装订并以书的形式销售的，都包含在里面。</p>
<p>整体图书市场表现（所有图书，数据截止日期2011年1月2日）</p>
<table border=1 cellpadding=1 cellspacing=3 width=245>
<tr height=13>
<td align=center><strong>所有图书，所有题材</strong></td>
</tr>
</table>
<table border=1 cellpadding=1 cellspacing=3 width=245>
<tr>
<td><strong>青少年非虚构</strong></td>
<td align=right>-0.44%</td>
<tr height=13>
<td height=13  ><strong>青少年虚构<strong></td>
<td align=right>-3.46%</td>
<tr height=13>
<td height=13><strong>青少图书整体</strong></td>
<td align=right>-2.88%</td>
</tr>
<tr height=13>
<td   height=13><strong>成人非虚构</strong></td>
<td align=right>-1.91%</td>
<tr height=13>
<td height=13><font color="red"><strong>&nbsp;&nbsp;&nbsp;&nbsp;计算机及互联网</strong></font></td>
<td align=right>-3.99%</td>
<tr height=13>
<td  ><strong>成人虚构</strong></td>
<td align=right>-7.20%</td>
</tr>
<tr height=13>
<td  ><strong>其他</strong></td>
<td align=right>-13.12%</td>
</tr>
<td align=center><strong>整体市场</strong></td>
<td align=right><strong>-4.54%</strong></td>
</tr>
</table>
<p>从表中可以看出，计算机图书市场较上年下滑了4%。需要注意的是，计算机图书的销售量只占实体和在线书店所有图书总销量的1%。下面这张图展示的整体图书市场各门类的业绩增长情况。其中，幽默（Humor）类图书的增长在普遍低迷的市场背景下显得独树一帜（14.45%）。另一个增长的领域是青少年非虚构类中的教材/教辅类（21.55%）。我很奇怪，为什么教材/教辅类图书居然有这么高的增长率。<br />
<span id="more-2287"></span></p>
<h2>整体图书市场增长情况</h2>
<p><img class="colorbox-2287"  src="http://radar.oreilly.com/WholeMarket.jpg"/></p>
<p>下面言归正传，看看技术图书市场。下面这张柱形图展示的是各年份累计图书销量的对比情况。从图中可以看出，每年的总销量从2007年开始逐年递减。2007年的时候，不少人认为市场会中止2001年以来一路下跌的态势，开始进入恢复期，但2009年较上一年的跌幅达到了历年最大值。</p>
<p><img class="colorbox-2287"  src="http://radar.oreilly.com/upload/2011/02/allYears.jpg"/></p>
<p>而下面这张折线图展示的是自2004年以来计算机图书市场每周的市场表现情况（根据我们从Bookscan获得的第一手数据生成）。请注意，这个图反映的是所有出版商，而不仅仅是O&#8217;Reilly。图中稍粗一点的红线表示2010年的数据。</p>
<p><img class="colorbox-2287"  src="http://radar.oreilly.com/upload/2011/01/sync_2010.jpg"/></p>
<p>从图中可以看出，我们提到过的明显的季节性特征依然存在。换句话说，每年开始都会强势上扬，然后一直到夏季逐步走低，到了秋天“返校”的季节开始止跌回升，到了年底又强势收尾。图中每年的趋势线都与上一年的趋势线非常接近，甚至连每周的涨跌都十分一致。在24个月来乏善可陈的市场表现中，唯一能让人感到一点慰藉的是，2009年每周销量与上一年度比有10-15%是下降的，而这个比例在2010年减少到了3-6%。但这能说明市场已经见底了吗，还是说我们也像读者思考着怎样才能学到新技术一样处于观望状态？如今，销售图书的方式更多了（后面几部分中会介绍），不少出版商通过不同数字格式来销售相同的内容实现了码洋与销量的双增长。而有些出版商纸质书发行量的降低，也通过数字发行和销售得到了补偿。</p>
<p>从上面图中看不来的是，计算机图书市场从2001年开始走下坡路，随后连续3年以20%的比例收缩，直到2004年趋于稳定，规模保持在2000年时的一半左右。（我们手中只有上溯到2004年的可靠数据。）如今，市场从2008年下半年开始又进入下跌通道，一直延续到2010年。前6年的整体市场增长率分别为：2005年1.48%、2006年3.17%、2007年-2.00%、2008年-4.27%、2009年-15.31%、2010年-4.29%。</p>
<p>那么，2010年有什么好消息吗？2010年，有11周的图书销量超过了上一年度。2009年，只有两周的销量超过了上一年度。因此，从这一点来说，似乎能看到市场复苏的某种迹象。2010年最终收关收在了2008年的销量水平上，而且整体市场降速比2009年慢了很多。持乐观态度的人认为，2010年市场已经触底；但持悲观态度的人则认为，这种情况早已有之：看起来好像市场已经跌无可跌了，但随后照样出现了大跌。因此，到底市场会再次走低，还是稳步复苏，都是没有办法确定的。</p>
<p>Treemap工具能够将数据可视化，通过它可以从另一个角度观察市场的表现。Treemap有助于迅速捕捉到市场的趋势信息，即使是几千种图书也不在话下。它的使用方法如下：</p>
<p>图中一个方块表示一个门类的市场份额和相对规模，颜色表示销量变化的速度。红色意味着下降，绿色意味着上升，而颜色的深浅表示变化的幅度（越深越大）。下面这张Treemap的屏幕截图显示了2010年第四季度与2009年第四季度相比，计算机图书市场各门类的损益情况。</p>
<p><img class="colorbox-2287"  src="http://radar.oreilly.com/upload/2011/02/cat_yoy_QTR4.jpg"/></p>
<p>从这些彩色方块中能看出什么来呢？首先别忘了它反映的是2010年第四季度与2009年第四季度的一个对比。这张屏幕截图已经不像去年那张那样“血流成河”了（去年的Treemap到处都是红色），与去年同期相比，2010年第四季度的亮点（浅绿色）不少。位于左上方的Android类图书，与2009年第四季度相比，增长了2,413%。你可能会注意到上部中间还有一个Android方块，呈浅绿色，区别在于中部上方的是面向消费者的书，左上角是Android编程的书。这两类书2010年都比2009年有很大的增长。左上角的iPad图书方块是黑色的，因为2009年还没有iPad图书。不过，方块的大小表明其发展规模一开始就令人印象深刻。</p>
<p>2010年，Windows 7图书增幅最大，其次是iPad，然后是Android（面向消费者的）和Android编程类图书。这是从销量增长来看的，而且这些技术之所以表现如此不俗，很大程度上是因为它们都是相对新的技术，没有大块的市场份额作为比较的基础。对于那些历史较长的技术，安全及网络安全、数字图像类图书的销量增长比较明显。</p>
<p>要看明白图中表示的趋势，可以按照颜色对这些门类加以分组：浅绿色代表“高度增长门类”，深绿及黑色代表“中度增长门类”，所有颜色都是“待观察门类”，红色及浅红色代表“下降门类”。除了“待观察门类”，其他都无须解释。“待观察门类”中包含那些不容易受季节性因素影响的，以及我们O&#8217;Reilly Radar关注的一些门类。您可以把希望添加到我们待观察范围的门类告诉我们。</p>
<p>下面这个表格分析并解释了上面Treemap中的某些数据，数据年份为2010年。其中Share（份额）一栏显示的是相应门类的市场份额，ROC一栏显示的是变化的速度（Rate of Change，RoC = (本期-上期)/上期）。举例来说，Mac OS类图书占整个计算机图书市场的份额为2.95%，收缩速度（RoC）为32.12%。</p>
<table border="1" cellpadding="5" cellspacing="1">
<col />
<col />
<col />
<col />
<tbody>
<tr>
<td><strong>高度增长</strong></td>
<td><strong>Share</strong></td>
<td><strong>ROC</strong></td>
<td><strong>Notes</strong></td>
</tr>
<tr>
<td>Windows 7</td>
<td align="right">05.53%</td>
<td align="right">217.38%</td>
<td>取代了XP和Vista自成一大类。Windows 7是操作系统中的大哥大。</td>
</tr>
<tr>
<td>iPad</td>
<td align="right">01.74%</td>
<td align="right">xx.yy%</td>
<td>这个类别在2009年的时候还没有，但现在已经成为市场份额排名第7的类别了。</td>
</tr>
<tr>
<td>Android编程</td>
<td align="right">00.68%</td>
<td align="right">292.65%</td>
<td>这个类别从2008年开始稳定增长，目前排名第42位，在最快RoC中排名第3位。</td>
</tr>
<tr>
<td>可用性</td>
<td align="right">00.11%</td>
<td align="right">491.50%</td>
<td>这个领域已经不像昔日那么巨大了，但高RoC加速了其增长，使其成为相当大的一个类别。</td>
</tr>
<tr>
<td>Android</td>
<td align="right">00.55%</td>
<td align="right">2493.88%</td>
<td>主要是面向Android消费者的领域，包括用户手册、最佳应用，等等。2008年起从无到有，2009年稳定增长，2010年名列前茅。</td>
</tr>
<tr>
<td><strong>中度增长</strong></td>
<td><strong>Share</strong></td>
<td><strong>ROC</strong></td>
<td><strong>Notes</strong></td>
</tr>
<tr>
<td>jQuery</td>
<td align="right">00.41%</td>
<td align="right">83.79%</td>
<td>规模相当大的一个类别，版权输出从2009年的9本降至2010年的6本，不过销量仍在稳定增长。</td>
</tr>
<tr>
<td>云计算</td>
<td align="right">00.22%</td>
<td align="right">63.58%</td>
<td>一个看涨的门类，2010年8本新书就取得如此成绩。当下出版的主要还是介绍性图书。</td>
</tr>
<tr>
<td>Windows 管理</td>
<td align="right">00.32%</td>
<td align="right">36.29%</td>
<td>中等规模的门类，2010年新书19本，2009年新书16本（2009年出版的图书也含在2010年销售数据中）。</td>
</tr>
<tr>
<td>社交网站</td>
<td align="right">00.21%</td>
<td align="right">30.27%</td>
<td>此类图书在过去两年中翻了一倍，2010年的新书增长了61%，创历年新高。</td>
</tr>
<tr>
<td>网络安全</td>
<td align="right">00.90%</td>
<td align="right">24.25%</td>
<td>安全类图书在2010年表现不错，新书版权稳定输出。</td>
</tr>
<tr>
<td><strong>待观察门类</strong></td>
<td><strong>Share</strong></td>
<td><strong>ROC</strong></td>
<td><strong>Notes</strong></td>
</tr>
<tr>
<td>Office 应用</td>
<td align="right">2.71%</td>
<td align="right">-3.54%</td>
<td>非常大的一个门类，市场一如既往地稳定。即使有所下滑，仍不像整体市场下滑得那样厉害。</td>
</tr>
<tr>
<td>图形图像</td>
<td align="right">05.97%</td>
<td align="right">-17.20%</td>
<td>非常大的一个门类（在Windows之后位居第2），有4本书销量过万；2010年新增图书10本，但销量下降64,581册。</td>
</tr>
<tr>
<td>电子表格</td>
<td align="right">02.99%</td>
<td align="right">-4.66%</td>
<td>第三大门类，有4本书销量过万；2010年新增打榜图书11种，但销量较2009年减少8,754册。</td>
</tr>
<tr>
<td>软件项目管理</td>
<td align="right">02.10%</td>
<td align="right">-15.14%</td>
<td>规模较大也较稳定的一个门类，销量略有下降。PMP及敏捷项目管理类图书最好卖。</td>
</tr>
<tr>
<td><strong>下降门类</strong></td>
<td><strong>Share</strong></td>
<td><strong>ROC</strong></td>
<td><strong>Notes</strong></td>
</tr>
<tr>
<td>Flash</td>
<td align="right">01.12%</td>
<td align="right">-84.43%</td>
<td>在Apple的冲击下，这个门类已经进退维谷，2010年销量比2009年减少59,340册，而2009年销量较2008年减少55,187册。</td>
</tr>
<tr>
<td>Mac OS</td>
<td align="right">02.95%</td>
<td align="right">-32.12%</td>
<td>很大的一个类别，2010年销量减少59,668册。2009年销量比2008年少67,642册。显然是Snow Leopard不给力带来的恶果。</td>
</tr>
<tr>
<td>Web 设计工具</td>
<td align="right">01.37%</td>
<td align="right">-53.20%</td>
<td>这个类别遭受了打击，主要因为Dreamweaver CS5没有随CS4图书的退场而及时跟上。2010年销量减少45,709册。</td>
</tr>
<tr>
<td>Web 程序设计</td>
<td align="right">02.01%</td>
<td align="right">-41.32%</td>
<td>规模较大，2010年新书品种减少了16种。2009年，有56个品种销量过千，而2010年销量过千的品种只有37种。.</td>
</tr>
<tr>
<td>网页制作</td>
<td align="right">04.09%</td>
<td align="right">-27.37%</td>
<td>拥有较大规模，2010年只有4个品种销量过万，而2009年过这个线的有9种。2010年的销量减少了70,492册。.</td>
</tr>
</tbody>
</table>
<p>本报告的第二部分将深入分析这些门类中的各种技术。第三部分将关注出版商，包括赢家和输家。第四部分将主要分析编程语言，第五部分将关注数字销售。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cn-cuckoo.com/2011/02/21/2010-book-market-of-usa-1-2287.html/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>现代浏览器揭秘（草）</title>
		<link>http://www.cn-cuckoo.com/2011/02/18/how-broswers-work-2257.html</link>
		<comments>http://www.cn-cuckoo.com/2011/02/18/how-broswers-work-2257.html#comments</comments>
		<pubDate>Fri, 18 Feb 2011 13:53:46 +0000</pubDate>
		<dc:creator>为之漫笔</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[编程技术]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://www.cn-cuckoo.com/?p=2257</guid>
		<description><![CDATA[原文地址：How browsers work 简介 Web浏览器恐怕是用户最多的软件了。本文将介绍浏览器的工作原理。想知道从你在地址栏中输入“google.com”，到窗口中显示Google主页的过程中都发生了什么？本文会为你揭开这个秘密。 要讨论的浏览器 今天，人们主要使用5种浏览器：Internet Explorer、Firefox、Safari、Chrome和Opera。这篇文章的分析源自开源浏览器——Firefox、Chrome和Safari，Safari是部分开源的。根据W3C对浏览器使用情况的统计信息，当前（2009年10）Firefox、Safari和Chrome共同的市场占有率已接近60%。因此，可以说开源浏览器已经占据了浏览器市场的半壁江山。 浏览器的主要功能 浏览器的主要功能就是呈现你选择的网络资源，换句话说，就是你向服务器请求资源，然后浏览器把它们显示在自己的窗口中。资源的格式通常是HTML，当然也有PDF、图像等等。资源的位置是使用URI（Uniform Resource Indentifier，统一资源标识符）来指定的。与此相关的内容在后面讨论网络的时候还会详细介绍。 浏览器如何解释HTML文件是由HTML和CSS规范规定的。这些规范是由W3C（World Wide Web Consortium，万维网联盟）维护的，W3C是负责制定Web标准的组织。 HTML当前的版本号是4（http://www.w3.org/TR/html401/），HTML5还在制定中。CSS当前的版本号是2（http://www.w3.org/TR/CSS2/），CSS3也正在制定过程中。 多少年来，浏览器厂商各自为战，纷纷埋头开发自己的扩展，对规范的支持始终不给力。结果就给Web开发人员带来了生死攸关的兼容性问题。而今天，大多数浏览器对规范的支持程度仍然参差不齐。 浏览器的用户界面大同小异，其中相同的界面元素包括： 用于输入URI的地址栏 后退和前进按钮 书签选项 用于刷新和停止加载当前文档的刷新及停止按钮 返回主页的主页按钮 说来也怪，并没有哪个正式公布的规范对浏览器的用户界面作出规定，浏览器目前的外观是多年来浏览器厂商之间互相模仿和不断改进的结果。HTML5规范中没有定义浏览器必须具备的UI元素，但列出了一些公共元素，其中就包括地址栏、状态栏和工具栏。当然，有些浏览器还有自己专有的一些功能，如Firefox的下载管理器。相关的更多内容将在后面讨论用户界面时介绍。 浏览器的主要构成 以下是构成浏览器的主要组件（参考1.1）。 1、用户界面——包括地址栏、后退/前进按钮、书签菜单等等，也就是除了显示所请求页面的主窗口之外的其他所有部分。 2、浏览器引擎——用于查询和操作呈现（rendering）引擎的接口。 3、呈现引擎——负责显示请求的内容，例如请求的内容是HTML，它就负责解析HTML和CSS并将解析后的内容显示到屏幕上。 4、网络模块——用于完成网络调用，如HTTP请求。具有平台中立的接口和针对不同平台的底层实现。 5、UI后端——用于绘制基本的组合选择框及对话框之类的基本部件。具有不特定于某个平台的界面样式，在底层使用的是操作系统的用户界面方法。 6、JavaScript解释器——用户解释和执行JavaScript代码。 7、数据存储模块——属于持久层；浏览器需要在硬盘中保存各种数据，如Cookie。HTML5还为客户端存储定义了新的技术。 图1 浏览器的主要组件 需要特别指出的是，Chrome会为每个新建的标签页创建一个新的呈现引擎的实例，并且每个标签页也运行在独立的进程当中，这一点与其他浏览器不一样。对构成浏览器的这些组件，我们会逐一详细讨论。 组件之间的通信 Firefox和Chroem都具有联系各个组件的组件。后面也将讨论这些组件。 呈现引擎 呈现引擎主要负责……呈现，也就是把请求的内容显示到浏览器屏幕上。 默认情况下，呈现引擎可以显示HTML和XML文档以及图像。而借助插件（一种浏览器扩展）它还可以显示其他类型的内容，比如使用PDF阅读器插件可以显示PDF。后面我们还会专门讨论插件和扩展，但这里我们只讨论呈现引擎的主要用途——显示使用CSS格式化之后的HTML及图像。 呈现引擎 前面提到的浏览器（Firefox、Chrome和Safari）是构建在两个呈现引擎之上的。Firefox使用Gecko——Mozilla自己开发的一个呈现引擎；Safari和Chrome都使用Webkit。 Webkit是一个开源的呈现引擎，最早是为Linux平台开发的，后来由苹果公司移植到Mac和Windows平台。有关内容请参考http://webkit.org。 主流程 呈现引擎首先通过网络层取得被请求文档的内容。通常是以8K分块的方式完成。 取得内容之后，呈现引擎的基本工作流如下图所示： 图2 呈现引擎的基本工作流 呈现引擎会开始解析HTML文档，并将HTML标签转换成“内容树”中的DOM节点。然后，它开始解析样式数据，包括外部CSS文件和style元素中的样式。解析后的样式信息，再加上HTML中的视觉指令，将被用于创建另一个树——呈现器树。 呈现器树中包含着各种矩形，每个矩形都有颜色和大小等属性。这些矩形都按照显示在屏幕上的顺序排列好了。 在构建完呈现器树之后，呈现引擎要完成一个“布局”过程。在这个过程中，它会精确地确定每个节点在屏幕上出现时的坐标。紧接着的一个阶段就是绘制——遍历呈现器树，并使用UI后端层将所有节点逐个绘制出来。 上述过程是逐步完成的，认识到这一点很重要。为了获得更好的用户体验，呈现引擎会尽可能早地将内容呈示到屏幕上。换句话说，它不会等到把所有HTML标签都解析完毕之后再去构建和布局呈现器树，而是解析完一部分内容，就显示一部分内容；与此同时，剩余内容可能还在通过网络不断下载的过程中。 主流程示例 [...]]]></description>
			<content:encoded><![CDATA[<p>原文地址：<a href="http://taligarsiel.com/Projects/howbrowserswork1.htm">How browsers work</a></p>
<h2>简介</h2>
<p>Web浏览器恐怕是用户最多的软件了。本文将介绍浏览器的工作原理。想知道从你在地址栏中输入“google.com”，到窗口中显示Google主页的过程中都发生了什么？本文会为你揭开这个秘密。</p>
<h4>要讨论的浏览器</h4>
<p>今天，人们主要使用5种浏览器：Internet Explorer、Firefox、Safari、Chrome和Opera。这篇文章的分析源自开源浏览器——Firefox、Chrome和Safari，Safari是部分开源的。根据W3C对浏览器使用情况的统计信息，当前（2009年10）Firefox、Safari和Chrome共同的市场占有率已接近60%。因此，可以说开源浏览器已经占据了浏览器市场的半壁江山。</p>
<h4>浏览器的主要功能</h4>
<p>浏览器的主要功能就是呈现你选择的网络资源，换句话说，就是你向服务器请求资源，然后浏览器把它们显示在自己的窗口中。资源的格式通常是HTML，当然也有PDF、图像等等。资源的位置是使用URI（Uniform Resource Indentifier，统一资源标识符）来指定的。与此相关的内容在后面讨论网络的时候还会详细介绍。</p>
<p>浏览器如何解释HTML文件是由HTML和CSS规范规定的。这些规范是由W3C（World Wide Web Consortium，万维网联盟）维护的，W3C是负责制定Web标准的组织。</p>
<p>HTML当前的版本号是4（http://www.w3.org/TR/html401/），HTML5还在制定中。CSS当前的版本号是2（http://www.w3.org/TR/CSS2/），CSS3也正在制定过程中。</p>
<p>多少年来，浏览器厂商各自为战，纷纷埋头开发自己的扩展，对规范的支持始终不给力。结果就给Web开发人员带来了生死攸关的兼容性问题。而今天，大多数浏览器对规范的支持程度仍然参差不齐。</p>
<p>浏览器的用户界面大同小异，其中相同的界面元素包括：</p>
<ul>
<li>用于输入URI的地址栏</li>
<li>后退和前进按钮</li>
<li>书签选项</li>
<li>用于刷新和停止加载当前文档的刷新及停止按钮</li>
<li>返回主页的主页按钮</li>
</ul>
<p>说来也怪，并没有哪个正式公布的规范对浏览器的用户界面作出规定，浏览器目前的外观是多年来浏览器厂商之间互相模仿和不断改进的结果。HTML5规范中没有定义浏览器必须具备的UI元素，但列出了一些公共元素，其中就包括地址栏、状态栏和工具栏。当然，有些浏览器还有自己专有的一些功能，如Firefox的下载管理器。相关的更多内容将在后面讨论用户界面时介绍。<br />
<span id="more-2257"></span></p>
<h4>浏览器的主要构成</h4>
<p>以下是构成浏览器的主要组件（参考<a href="#2257-1">1.1</a>）。<br />
1、用户界面——包括地址栏、后退/前进按钮、书签菜单等等，也就是除了显示所请求页面的主窗口之外的其他所有部分。<br />
2、浏览器引擎——用于查询和操作呈现（rendering）引擎的接口。<br />
3、呈现引擎——负责显示请求的内容，例如请求的内容是HTML，它就负责解析HTML和CSS并将解析后的内容显示到屏幕上。<br />
4、网络模块——用于完成网络调用，如HTTP请求。具有平台中立的接口和针对不同平台的底层实现。<br />
5、UI后端——用于绘制基本的组合选择框及对话框之类的基本部件。具有不特定于某个平台的界面样式，在底层使用的是操作系统的用户界面方法。<br />
6、JavaScript解释器——用户解释和执行JavaScript代码。<br />
7、数据存储模块——属于持久层；浏览器需要在硬盘中保存各种数据，如Cookie。HTML5还为客户端存储定义了新的技术。</p>
<p><img class="colorbox-2257"  src="http://cache.cn-cuckoo.com/img/2257_layers.png"/><br />
图1 浏览器的主要组件</p>
<p>需要特别指出的是，Chrome会为每个新建的标签页创建一个新的呈现引擎的实例，并且每个标签页也运行在独立的进程当中，这一点与其他浏览器不一样。对构成浏览器的这些组件，我们会逐一详细讨论。</p>
<h4>组件之间的通信</h4>
<p>Firefox和Chroem都具有联系各个组件的组件。后面也将讨论这些组件。</p>
<h2>呈现引擎</h2>
<p>呈现引擎主要负责……呈现，也就是把请求的内容显示到浏览器屏幕上。</p>
<p>默认情况下，呈现引擎可以显示HTML和XML文档以及图像。而借助插件（一种浏览器扩展）它还可以显示其他类型的内容，比如使用PDF阅读器插件可以显示PDF。后面我们还会专门讨论插件和扩展，但这里我们只讨论呈现引擎的主要用途——显示使用CSS格式化之后的HTML及图像。</p>
<h4>呈现引擎</h4>
<p>前面提到的浏览器（Firefox、Chrome和Safari）是构建在两个呈现引擎之上的。Firefox使用Gecko——Mozilla自己开发的一个呈现引擎；Safari和Chrome都使用Webkit。<br />
Webkit是一个开源的呈现引擎，最早是为Linux平台开发的，后来由苹果公司移植到Mac和Windows平台。有关内容请参考http://webkit.org。</p>
<h4>主流程</h4>
<p>呈现引擎首先通过网络层取得被请求文档的内容。通常是以8K分块的方式完成。</p>
<p>取得内容之后，呈现引擎的基本工作流如下图所示：</p>
<p><img class="colorbox-2257"  src="http://cache.cn-cuckoo.com/img/2257_flow.jpg"/><br />
图2 呈现引擎的基本工作流</p>
<p>呈现引擎会开始解析HTML文档，并将HTML标签转换成“内容树”中的<a href="#dom">DOM</a>节点。然后，它开始解析样式数据，包括外部CSS文件和style元素中的样式。解析后的样式信息，再加上HTML中的视觉指令，将被用于创建另一个树——<a href="render_tree">呈现器树</a>。</p>
<p>呈现器树中包含着各种矩形，每个矩形都有颜色和大小等属性。这些矩形都按照显示在屏幕上的顺序排列好了。</p>
<p>在构建完呈现器树之后，呈现引擎要完成一个“<a href="layout">布局</a>”过程。在这个过程中，它会精确地确定每个节点在屏幕上出现时的坐标。紧接着的一个阶段就是<a href="painting">绘制</a>——遍历呈现器树，并使用UI后端层将所有节点逐个绘制出来。</p>
<p>上述过程是逐步完成的，认识到这一点很重要。为了获得更好的用户体验，呈现引擎会尽可能早地将内容呈示到屏幕上。换句话说，它不会等到把所有HTML标签都解析完毕之后再去构建和布局呈现器树，而是解析完一部分内容，就显示一部分内容；与此同时，剩余内容可能还在通过网络不断下载的过程中。</p>
<h6>主流程示例</h6>
<p><img class="colorbox-2257"  src="http://cache.cn-cuckoo.com/img/2257_webkitflow.png" /><br />
图3　Webkit的主流程</p>
<p><img class="colorbox-2257"  src="http://cache.cn-cuckoo.com/img/2257_geckoflow.jpg" /><br />
图4　Mozilla的Gecko呈现引擎的主流程</p>
<p>从图3和图4可以看出，Webkit和Gecko使用的术语稍有不同，但整个流程基本上是相同的。</p>
<p>Gecko把可见的格式化元素的树叫做“框架树”（Frame tree），每个元素都是一个框架。而Webkit使用的则是“呈现器树”（Render tree），这个树由“呈现器对象”构成。Webkit把排列元素叫做“布局”，而Gecko则称该过程为“重排”（Reflow）。同样，“附加”（Attachment）则是Webkit对连接DOM节点与样式信息以创建呈现器树的称呼。Gecko还有一个与语义无关的小差别，它在HTML与DOM树之间加了一层，叫做“内容渗入”（Content Sink），相当于一个制造DOM元素的工厂。下面我们就来解释流程中的每个阶段。</p>
<h6>基本解析</h6>
<p>由于解析是呈现引擎的一项非常重要的工作，因此我们会讨论得比较深入一些。首先来简单地介绍一下解析。</p>
<p>所谓的解析文档，就是把文档转换成具有某种意义的结构，以便代码能够被理解和使用。解析之后的结果通常是一个节点树，与文档的结构对应。这个节点树叫做解析树或语法树。</p>
<p>举个例子，解析表达式“2+3-1”会返回下面这个树：</p>
<p><img class="colorbox-2257"  src="http://cache.cn-cuckoo.com/img/2257_nodetree.png"/><br />
图5 算术表达式的节点树</p>
<h6>文法</h6>
<p>解析是依据文档所遵循的语法规则进行的，取决于编写文档的语言和格式。每一个要解析的格式都必须具有由词汇表和语法规则构成的文法。这种文法称为<a href="#context_free_grammer">上下文无关的文法</a>。人类语言不具备上下文无关的文法，因此无法使用通常的解析技术来解析。</p>
<h6>解析器——加上词法分析器</h6>
<p>解析可以分为两个步骤：词法分析（lexical analysis）和语法分析（syntax analysis）。</p>
<p>词法分析指的是把输入分解成符号。符号来自语言的词汇表——基本有效单元的集合。对人类语言来说，符号就相当于我们字典中的那些单词。</p>
<p>语法分析就是使用语言的语法规则进行分析。</p>
<p>解析器通常把这两项工作交给两个组件来完成：词法分析器（有时也叫分词器）负责把输入分解成符号，而解析器则负责依据语言的语法规则来分析文档结构，然后构建起解析树。词法分析器知道如何剥离空格、换行等无关字符。</p>
<p><img class="colorbox-2257"  src="http://cache.cn-cuckoo.com/img/2257_parsetree.png"/><br />
图6 从源文档到解析树</p>
<p>解析过程是迭代进行的。解析器通常会要求词法分析器给出一个新的符号，然后使用该符号去匹配某种语法规则。如果匹配成功，则将与该符号对应的节点添加到解析树中，然后继续要求词法分析器再提供另一个符号。</p>
<p>如果匹配不成功，解析器会在内部保存当前符号，然后继续从词法分析器那里获取符号，直到所有内部保存的符号能够匹配一项语法规则为止。如果最终都没有找到匹配的规则，解析器就会抛出异常。这就意味着文档无效，或者说包含语法错误。</p>
<h6>转换</6><br />
（待续2011/2/20）</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cn-cuckoo.com/2011/02/18/how-broswers-work-2257.html/feed</wfw:commentRss>
		<slash:comments>28</slash:comments>
		</item>
		<item>
		<title>解构JavaScript库：jQuery、Prototype、Mootools</title>
		<link>http://www.cn-cuckoo.com/2011/01/06/javascript-libraries-deconstructed-2231.html</link>
		<comments>http://www.cn-cuckoo.com/2011/01/06/javascript-libraries-deconstructed-2231.html#comments</comments>
		<pubDate>Thu, 06 Jan 2011 15:25:09 +0000</pubDate>
		<dc:creator>为之漫笔</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[编程技术]]></category>

		<guid isPermaLink="false">http://www.cn-cuckoo.com/?p=2231</guid>
		<description><![CDATA[JavaScript库“解构”系列旨在以可视化和可交互的方式剖析JavaScript库的源代码，包括 jQuery、Prototype 和 MooTools。 通过将 JavaScript 源代码以可见块元素的方式标记出来，可以更方便查找和学习。点开每个块元素，即可查看相应的代码。点击代码中的链接，即可在程序流中纵情畅游。 ——Dave Stewart 这么好的东西，还用多说吗？你懂的。（见下图） 唯一需要说明的是，Dave Stewart原创的这个JavaScript库解构系列不知何故被挡在“墙”外头了，我只是把它搬到了“墙”里面来而已。换句话说，这个解构系列并非出自我手，我只是在自己的站点上提供了它的一个镜像，以方便“墙”内的JavaScript学习者参考。 现在就开始：解构JavaScript库!]]></description>
			<content:encoded><![CDATA[<div style="padding:1em;background:#eee;">JavaScript库“解构”系列旨在以可视化和可交互的方式剖析JavaScript库的源代码，包括 jQuery、Prototype 和 MooTools。<br />
通过将 JavaScript 源代码以可见块元素的方式标记出来，可以更方便查找和学习。点开每个块元素，即可查看相应的代码。点击代码中的链接，即可在程序流中纵情畅游。</p>
<div style="text-align:right;margin-right:2em;font-family:Arial, Helvetica, sans-serif;">——Dave Stewart</div>
</div>
<p>这么好的东西，还用多说吗？你懂的。（见下图）<br />
唯一需要说明的是，Dave Stewart原创的这个JavaScript库解构系列不知何故被挡在“墙”外头了，我只是把它搬到了“墙”里面来而已。换句话说，这个解构系列并非出自我手，我只是在自己的站点上提供了它的一个镜像，以方便“墙”内的JavaScript学习者参考。</p>
<p>现在就开始：<a href="http://www.cn-cuckoo.com/deconstructed/">解构JavaScript库</a>!<br />
<a href="http://www.cn-cuckoo.com/main/wp-content/uploads/2011/01/jquery.png"><img src="http://www.cn-cuckoo.com/main/wp-content/uploads/2011/01/jquery_small.png" alt="" title="jquery" class="aligncenter size-full wp-image-2239 colorbox-2231" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.cn-cuckoo.com/2011/01/06/javascript-libraries-deconstructed-2231.html/feed</wfw:commentRss>
		<slash:comments>27</slash:comments>
		</item>
		<item>
		<title>HTML5设计原理</title>
		<link>http://www.cn-cuckoo.com/2010/10/21/the-design-of-html5-2151.html</link>
		<comments>http://www.cn-cuckoo.com/2010/10/21/the-design-of-html5-2151.html#comments</comments>
		<pubDate>Thu, 21 Oct 2010 15:09:40 +0000</pubDate>
		<dc:creator>为之漫笔</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://www.cn-cuckoo.com/?p=2151</guid>
		<description><![CDATA[Jeremy Keith在 Fronteers 2010 上的主题演讲 特别感谢以下朋友指出翻译错误。 rukey67指出了一个翻译错误（另一个没有翻错）。 梁海指出了一个翻译错误。 小乐指出了一个错别字。 Rui指出了一个错别字。 Gavin指出译文少了一个“是”字。 下载PPT（PDF） 观看视频 今天我想跟大家谈一谈HTML5的设计。主要分两个方面：一方面，当然了，就是HTML5。我可以站在这儿只讲HTML5，但我并不打算这样做，因为如果你想了解HTML5的话，你可以Google，可以看书，甚至可以看规范。 实际上，确实有人会谈到规范的内容。史蒂夫·福克纳（Steve Faulkner）会讲HTML5与可访问性。而保罗·艾里什（Paul Irish）则会讲HTML5提供的各种API。因此，我今天站在这里，不会光讲一讲HTML5就算完事了。 说老实话，在正式开始之前，我想先交待清楚我所说的HTML5到底是什么意思。这话听起来有点搞笑：这会子你一直在说HTML5，难道我们还不知道什么是HTML5吗？大家知道，有一个规范，它的名字叫HTML5。我所说的HTML5，指的就是这个规范。但问题是，有些人所说的HTML5，指的不仅仅是这个规范，还有别的意思。比如说，用HTML5来代指CSS3就是一种常见的叫法。我可不是这样的。我所说的HTML5，不包含CSS3，就是HTML5。 类似的术语问题以前也有过。Ajax本来是一种含义明确的技术，但过了不久，它的含义就变成了“用JavaScript来做一切好玩的东西”。这就是Ajax，对不对？今天，HTML5也面临同样的问题，它本来指的是一个特定的规范，但如今含义却成了“在Web上做一切好玩的事。”我说的不是这种HTML5，不是这种涵盖了最近刚刚出现的各种新东东的HTML5。我说的仅仅是规范本身：HTML5。 刚才已经说了，我今天想要讲的内容不多，也没有打算介绍HTML5都包含什么。今天我要讲的是它的另一方面，即HTML5的设计。换句话说，我要讲的不是规范里都包含什么，而是规范里为什么会包含它们，以及在设计这个规范的时候，设计者们是怎么看待这些东西的。 设计原理 设计原理本质上是一种信念、一种想法、一个概念，是你行动的支柱。不管你是制定规范，还是制造一种有形的物品，或者编写软件，甚至发明编程语言。你都能找到背后的一个或者多个设计原理，多人协作的任何成果都是例证。不仅仅Web开发领域是这样。纵观人类历史，像国家和社会这样大规模的构建活动背后，同样也有设计原理。 就拿美国为例吧，美国的设计原理都写在了《独立宣言》中了。 我们认为这些真理是不言而喻的，人人生而平等，造物主赋予了每个人不可剥夺的权利，包括生存、自由和追求幸福。 这里有一句口号：生存、自由和追求幸福。这是被写进宪法中的核心理念，它关系到我们所有人的一切，也就是我们构建自己社会的原则。 还有一个例子，就是卡尔·马克思（Karl Marx），他的著作在20世纪曾被奉为建设社会主义的圭臬。其基本思想大致可以归结为下面这条设计原理： 各尽所能，各取所需。 这其实就是一种经济体系背后的设计原理。 还有一个例子，比前面两个的历史更久远一些，不过大同小异： 人人为我，我为人人。 这个极为简单的设计原理，是两千年前的拿撒勒犹太人耶稣基督提出来的。而这条原则成为了后来许多宗教的核心教义。原理与实践有时候并不是同步的。 下面是小说中的一个例子。英国小说家乔治·奥威尔（George Orwell）笔下的《动物庄园》，就是在一条设计原理的基础上构建起来的虚拟社会。这条设计原理是： 四条腿的都是好人，两条腿的都是坏蛋！ 《动物庄园》中有意思的是，随着社会的变迁——变得越来越坏，这条设计原理也跟着发生了改变，变成了“四条腿的都是好人，两条腿的就更好了。”最关键的是，即使是在虚构的作品里，设计原理都是存在的。 还有一套虚构的作品是以三条设计原理为基础构建起来的，那就是美国著名小说家艾萨克·阿西莫夫（Issac Asimov）的机器人经典系列。阿西莫夫发明了机器人学这个术语，并提出了机器人学三大法则，然后在这三个简单的设计原理基础上创作了一系列经典作品——大约有50本书。无论作品的情节如何变化，实际上都是从不同的角度来阐释这三大设计原理。我想，在座各位对机器人三大法则都不应该陌生。 机器人不得伤害人类，或袖手旁观人类受伤害。 机器人必须服从人类命令，除非命令违反第一法则。 机器人必须自卫，只要不违背第一和第二法则。 这些恐怕是第一次出现在小说中的针对软件的设计原理了。虽然基于这三个设计原理的软件运行在虚构的机器人的“正电子脑”中，但我想这应该是软件设计原理的事实开端。从此以后，我们才看到大量优秀软件背后的设计原理。 蒂姆·伯纳斯-李（Tim Berners-Lee），Web的发明者，在W3C的网站上发表过一份文档，其中有一个URL给出了他自己的一套设计原理。这些设计原理并不那么容易理解，不仅多，而且随着时时间推移，他还会不断补充、修改和删除。不过我还是觉得把自己认同的设计原理写出来放在某个地方真是个不错的主意。 实际上，CSS的发明人之一伯特·波斯（Bert Bos），也在W3C的网站上放着一份文档，其中讲的都是基本的设计原理，比如怎样设计并构建一种格式，无论是CSS还是其他格式。推荐大家看一看。 只要你在W3C的站点中随便找一找，就可以发现非常多的这种设计原理，包括蒂姆·伯纳斯-李个人的。当然，你还会看到他从软件工程学校里借用的一些口号：分权（decentalisation）、容忍（tolerance）、简易（simplicity）、模块化（modularity）。这些都是在他发明新格式的时候，头脑中无时无刻不在想的那些关键词。 在座各位对蒂姆·伯纳斯-李的贡献都是非常熟悉的，因为大家每天都在用。他发明了Web，与罗伯特·卡里奥（Robert Cailliau）共同发明了Web，而且在发明Web的同时，也发明了我们每天都在Web上使用的语言。当然，这门语言就是HTML：超文本标记语言。 HTML HTML最早是从2.0版开始的。从来就没有1.0版。如果有人告诉你说，他最早是从HTML 1.0开始使用HTML的，那他绝对是在忽悠你。从前确实有一个名叫HTML Tags的文档，其中的部分标签一直用到现在，但那个文档并非官方的规范。 使用标签、尖括号、p或h1，等等，并不是蒂姆·伯纳斯-李首创的想法。当时的SGML里就有了这些概念，而且当时的CERN（Conseil Europeen [...]]]></description>
			<content:encoded><![CDATA[<h2><a href="http://adactio.com/articles/1704/">Jeremy Keith在 Fronteers 2010 上的主题演讲</a></h2>
<div style="background:#eee;border:1px dashed orange;padding:1em 0 0 1em;float:right;margin:0 0em 1em 1em;">
特别感谢以下朋友指出翻译错误。</p>
<ul>
<li><a href="http://www.rukey.cn/" title="rukey67的个人网站">rukey67</a>指出了<a href="http://www.cn-cuckoo.com/2010/10/21/the-design-of-html5-2151.html/comment-page-1#comment-3384">一个翻译错误（另一个没有翻错）</a>。</li>
<li><a href="https://twitter.com/lianghai" title="梁海的Twitter">梁海</a>指出了<a href="http://www.cn-cuckoo.com/2010/10/21/the-design-of-html5-2151.html#comment-3446">一个翻译错误</a>。</li>
<li><a href="#" title="小乐没有留下链接">小乐</a>指出了<a href="http://www.cn-cuckoo.com/2010/10/21/the-design-of-html5-2151.html#comment-3621">一个错别字。</a></li>
<li><a href="#" title="Rui没有留下链接">Rui</a>指出了<a href="http://www.cn-cuckoo.com/2010/10/21/the-design-of-html5-2151.html#comment-3758">一个错别字。</a></li>
<li><a href="#" title="Rui没有留下链接">Gavin</a>指出译文<a href="http://www.cn-cuckoo.com/2010/10/21/the-design-of-html5-2151.html#comment-4450">少了一个“是”字</a>。</li>
</ul>
</div>
<div style="text-align:right;">
<a href="http://adactio.com/extras/slides/designofhtml5.pdf">下载PPT（PDF）</a><br />
<a href="http://fronteers.nl/congres/2010/sessions/the-design-of-html5-jeremy-keith">观看视频</a>
</div>
<p>今天我想跟大家谈一谈HTML5的设计。主要分两个方面：一方面，当然了，就是HTML5。我可以站在这儿只讲HTML5，但我并不打算这样做，因为如果你想了解HTML5的话，你可以Google，可以看书，甚至可以看规范。</p>
<p>实际上，确实有人会谈到规范的内容。史蒂夫·福克纳（Steve Faulkner）会讲HTML5与可访问性。而保罗·艾里什（Paul Irish）则会讲HTML5提供的各种API。因此，我今天站在这里，不会光讲一讲HTML5就算完事了。</p>
<p>说老实话，在正式开始之前，我想先交待清楚我所说的HTML5到底是什么意思。这话听起来有点搞笑：这会子你一直在说HTML5，难道我们还不知道什么是HTML5吗？大家知道，有一个规范，它的名字叫HTML5。我所说的HTML5，指的就是这个规范。但问题是，有些人所说的HTML5，指的不仅仅是这个规范，还有别的意思。比如说，用HTML5来代指CSS3就是一种常见的叫法。我可不是这样的。我所说的HTML5，不包含CSS3，就是HTML5。</p>
<p>类似的术语问题以前也有过。Ajax本来是一种含义明确的技术，但过了不久，它的含义就变成了“用JavaScript来做一切好玩的东西”。这就是Ajax，对不对？今天，HTML5也面临同样的问题，它本来指的是一个特定的规范，但如今含义却成了“在Web上做一切好玩的事。”我说的不是这种HTML5，不是这种涵盖了最近刚刚出现的各种新东东的HTML5。我说的仅仅是规范本身：HTML5。</p>
<p>刚才已经说了，我今天想要讲的内容不多，也没有打算介绍HTML5都包含什么。今天我要讲的是它的另一方面，即HTML5的设计。换句话说，我要讲的不是规范里都包含什么，而是规范里为什么会包含它们，以及在设计这个规范的时候，设计者们是怎么看待这些东西的。</p>
<h2>设计原理</h2>
<p>设计原理本质上是一种信念、一种想法、一个概念，是你行动的支柱。不管你是制定规范，还是制造一种有形的物品，或者编写软件，甚至发明编程语言。你都能找到背后的一个或者多个设计原理，多人协作的任何成果都是例证。不仅仅Web开发领域是这样。纵观人类历史，像国家和社会这样大规模的构建活动背后，同样也有设计原理。</p>
<p>就拿美国为例吧，美国的设计原理都写在了《独立宣言》中了。</p>
<p style="padding:2em;background:#eee;">
我们认为这些真理是不言而喻的，人人生而平等，造物主赋予了每个人不可剥夺的权利，包括生存、自由和追求幸福。
</p>
<p>这里有一句口号：生存、自由和追求幸福。这是被写进宪法中的核心理念，它关系到我们所有人的一切，也就是我们构建自己社会的原则。<br />
<span id="more-2151"></span><br />
还有一个例子，就是卡尔·马克思（Karl Marx），他的著作在20世纪曾被奉为建设社会主义的圭臬。其基本思想大致可以归结为下面这条设计原理：</p>
<p style="padding:2em;background:#eee;">
各尽所能，各取所需。
</p>
<p>这其实就是一种经济体系背后的设计原理。</p>
<p>还有一个例子，比前面两个的历史更久远一些，不过大同小异：</p>
<p style="padding:2em;background:#eee;">
人人为我，我为人人。
</p>
<p>这个极为简单的设计原理，是两千年前的拿撒勒犹太人耶稣基督提出来的。而这条原则成为了后来许多宗教的核心教义。原理与实践有时候并不是同步的。</p>
<p>下面是小说中的一个例子。英国小说家乔治·奥威尔（George Orwell）笔下的《动物庄园》，就是在一条设计原理的基础上构建起来的虚拟社会。这条设计原理是：</p>
<p style="padding:2em;background:#eee;">
四条腿的都是好人，两条腿的都是坏蛋！
</p>
<p>《动物庄园》中有意思的是，随着社会的变迁——变得越来越坏，这条设计原理也跟着发生了改变，变成了“四条腿的都是好人，两条腿的就更好了。”最关键的是，即使是在虚构的作品里，设计原理都是存在的。</p>
<p>还有一套虚构的作品是以三条设计原理为基础构建起来的，那就是美国著名小说家艾萨克·阿西莫夫（Issac Asimov）的机器人经典系列。阿西莫夫发明了机器人学这个术语，并提出了机器人学三大法则，然后在这三个简单的设计原理基础上创作了一系列经典作品——大约有50本书。无论作品的情节如何变化，实际上都是从不同的角度来阐释这三大设计原理。我想，在座各位对机器人三大法则都不应该陌生。</p>
<p style="padding:2em;background:#eee;">
机器人不得伤害人类，或袖手旁观人类受伤害。<br />
机器人必须服从人类命令，除非命令违反第一法则。<br />
机器人必须自卫，只要不违背第一和第二法则。
</p>
<p>这些恐怕是第一次出现在小说中的针对软件的设计原理了。虽然基于这三个设计原理的软件运行在虚构的机器人的“正电子脑”中，但我想这应该是软件设计原理的事实开端。从此以后，我们才看到大量优秀软件背后的设计原理。</p>
<p>蒂姆·伯纳斯-李（Tim Berners-Lee），Web的发明者，在W3C的网站上发表过一份文档，其中有一个URL给出了他自己的一套设计原理。这些设计原理并不那么容易理解，不仅多，而且随着时时间推移，他还会不断补充、修改和删除。不过我还是觉得把自己认同的设计原理写出来放在某个地方真是个不错的主意。</p>
<p>实际上，CSS的发明人之一伯特·波斯（Bert Bos），也在W3C的网站上放着一份文档，其中讲的都是基本的设计原理，比如怎样设计并构建一种格式，无论是CSS还是其他格式。推荐大家看一看。</p>
<p>只要你在W3C的站点中随便找一找，就可以发现非常多的这种设计原理，包括蒂姆·伯纳斯-李个人的。当然，你还会看到他从软件工程学校里借用的一些口号：分权（decentalisation）、容忍（tolerance）、简易（simplicity）、模块化（modularity）。这些都是在他发明新格式的时候，头脑中无时无刻不在想的那些关键词。</p>
<p>在座各位对蒂姆·伯纳斯-李的贡献都是非常熟悉的，因为大家每天都在用。他发明了Web，与罗伯特·卡里奥（Robert Cailliau）共同发明了Web，而且在发明Web的同时，也发明了我们每天都在Web上使用的语言。当然，这门语言就是HTML：超文本标记语言。</p>
<h2>HTML</h2>
<p>HTML最早是从2.0版开始的。从来就没有1.0版。如果有人告诉你说，他最早是从HTML 1.0开始使用HTML的，那他绝对是在忽悠你。从前确实有一个名叫HTML Tags的文档，其中的部分标签一直用到现在，但那个文档并非官方的规范。</p>
<p>使用标签、尖括号、p或h1，等等，并不是蒂姆·伯纳斯-李首创的想法。当时的SGML里就有了这些概念，而且当时的CERN（Conseil Europeen pour la Recherche Nucleaire，欧洲核子研究委员会）也在使用SGML的一个特定的版本。也就是说，即便在那个时代，他也没有白手起家；这一点在HTML后来的发展过程中也体现了出来：继往开来、承前启后，而不是另立门户、从头开始。</p>
<p>换句话说，这篇名为HTML Tags的文档可以算作HTML的第一个版本，但它却不是一个正式的版本。第一个正式版本，HTML 2.0，也不是出自W3C之手。HTML 2.0是由IETF，因特网工程任务组（Internet Engineering Task Force）制定的。在W3C成立之前，IETF已经发布了不少标准。但从第三个版本开始往后，W3C，万维网联盟（World Wide Web Consortium）开始接手，并负责后续版本的制定工作。</p>
<p>20世纪九十年代HTML有过几次快速的发展。众所周知，在那个时代要想构建网站，可是一项十分复杂的工程。浏览器大战曾令人头疼不已。市场竞争的结果就是各家浏览器里都塞满了各种专有的特性，都试图在专有特性上胜人一筹。当时的混乱程度不堪回首，HTML到底还重不重要，或者它作为Web格式的前景如何，谁都说不清楚。</p>
<p>从1997年到1999年，HTML的版本从3.2到4.0到4.01，经历了非常快的发展。问题是到了4.01的时候，W3C的认识发生了倒退，他们说“好了，这个版本就这样了，HTML也就这样了；HTML 4.01是HTML的最后一个版本了，我们用不着HTML工作组了。”</p>
<p>W3C并没有停止开发这门语言，只不过他们对HTML不再感兴趣了。在HTML 4.01之后，他们提出了XHTML 1.0。虽然听起来完全不同，但XHTML 1.0与HTML 4.01其实是一样的。我的意思是说，从字面上看这两个规范的内容是一样的，词汇表是一样的，所有的元素是一样，所有的属性也都是一样的。唯一一点不同之处，就是XHTML 1.0要求使用XML语法。也就是说，所有属性都必须使用小写字母，所有元素也必须使用小写字母，所有属性值都必须加引号，你还得记着使用结束标签，记着对img和br要使用自结束标签。</p>
<p>从规范本身的内容来看，实际上是相同的，没有什么不同。不同之处就是编码风格，因为对浏览器来说，读取符合HTML 4.01、HTML 3.2，或者XHTML 1.0规范的网页都没有问题，对浏览器来说这些网页都是一样的，都会生成相同的DOM树。只不过人们会比较喜欢XHTML 1.0，因为不少人认同它比较严格的编码风格。</p>
<p>到了2000年，Web标准项目（Web Standards Project）的活动开展得如火如荼，开发人员对浏览器里包含的那些乱七八糟的专有特性已经忍无可忍了。大家都很生气，就骂那些浏览器厂商“遵守个规范就他妈的真有那么难吗？”当时CSS有了长足的发展，而且与XHTML 1.0结合得也很紧密，CSS加XHTML 1.0基本上就可以算是“最佳实践”了。虽然在我看来HTML 4.01与XHTML 1.0没有本质上的不同，但大家都接受了。专业的开发人员能做到元素全部小写，属性全部小写，属性值也全部加引号：由于专业人员起到了模范带头作用，越来越多的人也都开始支持这种语法。</p>
<p>我就是一个例子！过去的10年，我一直都使用XHTML 1.0文档类型，原因是这样一来验证器就能给我帮上很大的忙，对不对？只要我写的是XHTML 1.0，然后用验证器测试，它就能告诉我是不是忘了给属性值加引号，是不是没有结束某个标签，等等等等。而如果我写的是HTML 4.01，同样的问题就变成了有效的了，验证器就不一定会提醒我了。</p>
<p>这就是我一直使用XHTML 1.0的原因。我估计很多人都……使用XHTML 1.0的朋友，请把手举起来。好的。HTML 4.01呢？人少多了。一直没有举手的呢，大声点，你们用什么？HTML5，也很好！更早的呢，还有人使用更早的文档类型吗？没有了？</p>
<p>10年来我一直使用XHTML 1.0，就是因为验证器能够真正帮到我。有人用XHTML 1.1吗？你知道有人用吗？请举手，别放下。有人把网页标记为XML文档吗？有吗？那你们使用的就不是XHTML 1.1。</p>
<p>这就是个大问题。XHTML 1.0之后是XHTML 1.1，只是小数点后面的数字加了一个1，而且从词汇表的角度看，规范本身没有什么新东西，元素也都相同，属性也都相同。但对XHTML 1.1来说，唯一的变化是你必须把自己的文档标记为XML文档。在使用XHTML 1.0的时候，还可以把文档标记为HTML，而我们也正是这样做的，否则把文档标记为XML没准真会把人逼疯的。</p>
<p>为什么这么说呢？首先，把文档标记为XML后，Internet Explorer不能处理。当然，IE9是可以处理了。恐怕有人会讲“真是太可爱了”，他们到现在居然都没有忘了这件事。这艘船终于靠岸了！不过那时候，作为全球领先的浏览器，IE无法处理接收到的XML文档类型的文档，而规范又要求你以XML文档类型来发送文档，这不把人逼疯才怪呢。</p>
<p>所以说XHTML 1.1有点脱离现实，而你不想把文档以XML格式发送给那些能够理解XML的浏览器，则是因为XML的错误处理模型。XML的语法，无论是属性小写，元素小写，还是始终要给属性值加引号，这些都没有问题，都很好，事实上我也喜欢这样做，但XML的错误处理模型却是这样的：解析器如果遇到错误，停止解析。规范里就是这么写的。如果你把XHTML 1.1标记为XML文档类型，假设你用Firefox打开这个文档，而文档中有一个和号（&#038;）没有正确编码，就算整个页面中就这一处错误，你看到的也将是黄屏，浏览器死掉了。Firefox会说：“没戏了，页面中有一个错误，你看不到这个网页了。”根据XML规范，这样处理是正确的，对Firefox而言，遇到错误就停止解析，并且不呈现其他任何内容是严格按照XML规范做的。因为它不是HTML，HTML根本就没有错误处理模型，但根据XML规范，这样做没错。</p>
<p>这就是为什么你不会把文档标记为XML的另一个原因。接下来，新的版本是XHTML 2，大家注意后面没有日期，因为这个规范并没有完成。</p>
<p>现在就说说XHTML 2，我很愿意把问题说清楚，XHTML 2实际上真是一个非常非常好的规范，确实非常好……从理论的角度来说。我的意思是说，制定这个规范的人都是非常非常有头脑的。直说吧，领导制定这个规范的家伙是斯蒂芬·彭伯顿（Stephen Pemberton），他应该是本地人，是一个聪明过人的家伙。规范本身也很了不起，如果所有人都同意使用的话，也一定是一个非常好的格式。只不过，还不够实际。</p>
<p>首先，XHTML 2仍然使用XML错误处理模型，你必须保证以XML文档类型发送文档；这一点不言自明：没人愿意这样做。其次，XHTML 2有意不再向后兼容已有的HTML的各个版本。他们甚至曾经讨论过废除img元素，这对每天都在做Web开发的人来说确实有点疯了的味道。但我们知道，他们之所以这样做，理论上确实有充足的理由——使用object元素可能会更好。</p>
<p>因此，无论XHTML 2在理论上是多么完美的一种格式，但却从未有机会付诸实践。而之所以难以将其付诸实践，就是因为像你我这样的开发人员永远不会支持它，它不向后兼容。同样，浏览器厂商也不会，浏览器厂商必须要保证向后兼容。</p>
<p>为什么XHTML 1.1没有像XML那样得到真正广泛地应用，为什么XHTML 2从未落到实处？因为它违反了一条设计原理，这条设计原理就是著名的伯斯塔尔法则（Postel&#8217;s Law）。大家都知道：</p>
<p style="padding:2em;background:#eee;">
发送时要保守；接收时要开放。
</p>
<p>没错，接收的时候要开放，而这也正是Web得以构建的基础。开发浏览器的人必须敞开胸怀，接收所有发送给浏览器的东西，因为它们过去一直都在接收那些不够标准的东西，对不对？Web上的很多文档都不规范，但那正是Web发展的动力。从某种角度讲，Web走的正是一条混沌发展之路，虽然混沌，但却非常美丽诱人。在Web上，格式不规范的文档随处可见，但那又怎样呢？如果所有人都能够写出精准的XML，所有文档的格式都十分正确，那当然好了。可是，那不现实。现实是伯斯塔尔法则。</p>
<p>作为专业人士，在发送文档的时候，我们会尽量保守一些，尽量采用最佳实践，尽量确保文档格式良好。但从浏览器的角度说，它们必须以开放的姿态去接收任何文档。</p>
<p>有人可能会说XML有错误处理模型，XHTML 1.1和XHTML 2都使用该模型，但那个错误处理模型太苛刻了。它绝对不符合接收时开放这个法则，遇到一个错误就停止解析怎么能叫开放呢？我们只能说它与健壮性法则（也就是伯斯塔尔法则）是对立的。</p>
<h2>HTML5</h2>
<p>之后，就到了HTML5，但HTML5并不是由W3C直接制定的。故事的经过是这样的，到20世纪末的时候，还没有HTML工作组，W3C内部的一些人就开始琢磨了，“HTML也许还可以更长寿一点，只要我们对它稍加扩展就行了。只要把我们放在XHTML上的时间和精力拿出一部分来，就可以提升一下HTML中的表单，可以让HTML更接近编程语言，就可以让它更上一层楼。”</p>
<p>于是，在2004年W3C成员内部的一次研讨会上，当时Opera公司的代表伊恩·希克森（Ian Hickson）提出了一个扩展和改进HTML的建议。他建议新任务组可以跟XHTML 2并行，但是在已有HTML的基础上开展工作，目标是对HTML进行扩展。W3C投票表决的结果是——“反对”，因为HTML已经死了，XHTML 2才是未来的方向。然后，Opera、Apple等浏览器厂商，以及其他一些成员说：“那好吧，不指望他们了，我们自已一样可以做这件事，我们脱离W3C。”他们成立了Web Hypertext Applications Technology Working Group（Web超文本应用技术工作组，WHATWG）——可巧的是，他们自称工作组，而不是特别小组（task force），这就为HTML5将来的命运埋下了伏笔。</p>
<p>WHATWG决定完全脱离W3C，在HTML的基础上开展工作，向其中添加一些新东西。这个工作组的成员里有浏览器厂商，因此他们不仅可以说加就加，而且还能够一一实现。结果，大家不断提出一些好点子，并且逐一做到了浏览器中。</p>
<p>WHATWG的工作效率很高，不久就初见成效。在此期间，W3C的XHTML 2没有什么实质性的进展。特别是，如果从实现的角度来说，用原地踏步形容似乎也不为过。</p>
<p>结果，一件有意思的事情发生了。那是在2006年，蒂姆·伯纳斯-李写了一篇博客，说：“你们知道吗？我们错了。我们错在企图一夜之间就让Web跨入XML时代，我们的想法太不切实际了，是的，也许我们应该重新组建HTML工作组了。”善哉斯言，后来的故事情节果真就是这样发展的。W3C在2007年组建了HTML5工作组。这个工作组面临的第一个问题，毫无疑问就是“我们是从头开始做起呢，还是在2004年成立的那个叫WHATWG的工作组既有成果的基础上开始工作呢？”答案是显而易见的，他们当然希望从已经取得的成果着手，以之为基础展开工作。于是他们又投了一次票，同意“在WHATWG工作成果的基础上继续开展工作”。好了，这下他们要跟WHATWG并肩战斗了。</p>
<p>第二个问题就是如何理顺两个工作组之间的关系。W3C这个工作组的编辑应该由谁担任？是不是还让WHATWG的编辑，也就是现在Google的伊恩·希克森来兼任？于是他们又投了一次票，赞成“让伊恩·希克森担任W3C HTML5规范的编辑，同时兼任WHATWG的编辑，更有助于新工作组开展工作。”</p>
<p>这就是他们投票的结果，也就是我们今天看到的局面：一种格式，两个版本。WHATWG的网站上有这个规范，而W3C的站点上同样也有一份。</p>
<p>如果你不了解内情，很可能会产生这样的疑问：“哪个版本才是真正的规范？”当然，这两个版本内容是一样的……基本上相同。实际上，这两个版本将来还会分道扬镳。现在已经有了分道扬镳的迹象了。我的意思是说，W3C最终要制定一个具体的规范，这个规范会成为一个工作草案，定格在某个历史时刻。</p>
<p>而WHATWG呢，他们还在不断地迭代。即使目前我们说的HTML5，也不能完全涵盖WHATWG正在从事的工作。最准确的理解是他们正在开发一项简单的HTML或Web技术，因为这才是他们工作的核心目标。然而，同时存在两个这样的工作组，这两个工作组同时开发一个基本相同的规范，这无论如何也容易让人产生误解。误解就可能造成麻烦。</p>
<p>其实这两个工作组背后各自有各自的流程，因为它们的理念完全不同。在WHATWG，可以说是一种独裁的工作机制。我刚才说了，伊恩·希克森是编辑。他会听取各方意见，在所有成员各抒己见，充分陈述自己的观点之后，他批准自己认为正确的意见。</p>
<p>W3C则截然相反，可以说是一种民主的工作机制。所有成员都可以发表意见，而且每个人都有投票表决的权利。这个流程的关键在于投票表决。从表面上看，WHATWG的工作机制让人不好接受。岂止是不好接受，简直是历史的倒退。相信谁都会认为“运作任何项目都不能采取这种方式！”</p>
<p>W3C的工作机制听起来让人很舒服。至少体现了人人平等嘛。但在实践中，WHATWG的工作机制运行得非常非常好。我认为之所以会这样，主要归功于伊恩·希克森。他的的确确是一个非常称职的编辑。他在听取各方意见时，始终可以做到丝毫不带个人感情色彩。</p>
<p>从原理上讲，W3C的工作机制很公平，而实际上却非常容易在某些流程或环节上卡壳，造成工作停滞不前，一件事情要达成决议往往需要花费很长时间。那到底哪种工作机制最好呢？我认为，最好的工作机制是将二者结合起来。而事实也是两个规范制定主体在共同制定一份相同的规范，我想，这倒是非常有利于两种工作机制相互取长补短。</p>
<p>两个工作组之所以能够同心同德，主要原因是HTML5的设计思想。因为他们从一开始就确定了设计HTML5所要坚持的原则。结果，我们不仅看到了一份规范，也就是W3C站点上公布的那份文档，即HTML5语言规范，还在W3C站点上看到了另一份文档，也就是HTML设计原理。而这份文档的一位编辑今天也来到了我们大会的现场，<del datetime="2011-01-29T15:26:47+00:00" title="感谢 @梁海 指出这个翻译错误">她</del>他就是安妮·奇泰丝（Anne Van Kesteren）。如果大家对这份文档有问题，可以请教安妮。</p>
<p>这份文档非常好，真的非常出色。这份文档，可以说见证了W3C与WHATWG同心协力共谋发展的历程。难道你们不觉得他们像是一对欢喜冤家吗？那他们还怎么同心同德呢？这份文档忠实地记录了他们一道做了什么，他们共同拥护什么。</p>
<p>接下来，我想要讲的就是这份文档。因为，既然他们能就这份文档达成共识，那么我相信，HTML5必将是一个伟大的规范，而他们已经认可这就是他们的共同行动纲领。为此，你才会看到诸如兼容性、实用性、互用性之类的概念。即便W3C与WHATWG之间再有多大的分歧——确实相当多——至少他们还有这份文档中记录的共识。这一点才是至关重要的。正因为他们有了共识，才有了这份基于共识描述设计原理的文档。</p>
<h2>避免不必要的复杂性</h2>
<p>下面我就给大家介绍一些这份文档中记载的设计原理。第一个，非常简单：避免不必要的复杂性。好像很简单吧。我用一个例子来说明。</p>
<p>假设我使用HTML 4.01规范，我打开文档，输入doctype。这里有人记得HTML 4.01的doctype吗？好，没有，我猜没有。除非……我的意思是说，你是傻冒。现场恐怕真有人背过，这就是HTML 4.01的doctype：</p>
<pre class="brush: html; ">

&lt;!DOCTYPE html PUBLIC &quot;-//W3C/DTD HTML 4.01//EN&quot;
&quot;http://www.w3.org/TR/html4/strict.dtd&quot;&gt;
</pre>
<p>我不记这个两行代码，不然还要记事本、要Google、要模板有什么用呢？</p>
<p>要是我使用XHTML 1.0呢，这个规范我都已经用了10年了。有谁记得住这个doctype吗？没错，它的长度跟HTML 4.01的差不太多：</p>
<pre class="brush: html; ">

&lt;!DOCTYPE html PUBLIC &quot;-//W3C/DTD XHTML 1.0 Strict//EN&quot;
&quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&quot;&gt;
</pre>
<p>是不是，基本上相同。它要告诉浏览器的是：这个文档是XHTML 1.0的文档。那么在HTML 5中，省掉不必要的复杂性，doctype就简化成了：</p>
<pre class="brush: html; ">

&lt;!DOCTYPE html&gt;
</pre>
<p>仅此而已。好了，就连我也能过目不忘了。我用不着把这几个字符记在记事本里了。我得说，在我第一次看到这个doctype的时候——我当然以为这是一个HTML文档的doctype——被它吓了一跳：“是不是还少一个数字5啊？”我心里想：“这个doctype想告诉浏览器什么呢？就说这个文档是HTML吗？难道这是有史以来唯一一个HTML版本吗，这件事我得首先搞清楚，HTML今后永远不会再有新版本了吗？”好一副唯我独尊的架式！我错了，因为这个doctype并没有这个意思。为此，必须先搞清楚为什么文档一开头就要写doctype。它不是写给浏览器看的。Doctype是写给验证器看的。也就是说，我之所以要在文档一开头写那行XHTML 1.0的doctype，是为了告诉验证器，让验证器按照该doctype来验证我的文档。</p>
<p>浏览器反倒无所谓了。假设我写的是HTML 3.2文档，文档开头写的是HTML 3.2的doctype。而在文档中某个地方，我使用了HTML 4.01中才出现的一个元素。浏览器会怎么处理这种情况？它会因为这个元素出现在比doctype声明的HTML版本更晚的规范中，就不解释呈现该元素吗？不会，当然不会！它照样会解释呈现该元素，别忘了伯斯塔尔法则，别忘了健壮性。浏览器在接收的时候必须要开放。因此，它不会检查任何格式类型，而验证器会，验证器才关心格式类型。这才是存在doctype的真正原因。</p>
<p>而按照HTML5的另一个设计原理，它必须向前向后兼容，兼容未来的HTML版本——不管是HTML6、HTML7，还是其他什么——都要与当前的HTML版本，HTML5，兼容。因此，把一个版本号放在doctype里面没有多大的意义，即使对验器证也一样。</p>
<p>刚才，我说doctype不是为浏览器写的，这样说大多数情况下没有问题。在有一种情况下，你使用的doctype会影响到浏览器，相信在座诸位也都知道。但在这种情况下，Doctype并非真正用得其所，而只是为了达到某种特殊的目的才使用doctype。当初微软在引入CSS的时候，走在了标准的前头，他们率先在浏览器中支持CSS，也推出了自己的盒模型——后来标准发布了，但标准中使用了不一样的盒模型。他们怎么办？他们想支持标准，但也想向后兼容自己过去推出的编码方式。他们怎么知道网页作者想使用标准，还是想使用他们过去的方式？</p>
<p>于是，他们想出了一个非常巧妙的主意。那就是利用doctype，利用有效的doctype来触发标准模式，而不是兼容模型（quiks mode）。这个主意非常巧妙。我们今天也都是这样在做，在我们向文档中加入doctype时，就相当于声明了“我想使用标准模式”，但这并不是发明doctype的本意。这只是为了达到特殊的目的在利用doctype。</p>
<p>下面我出一道有奖抢答题，听好：“一分钟后开始，如果你手快的话，第一个在文档前面写完<span class="inline-code">doctype html</span>，然后我用Internet Explorer打开你的文档，会触发它的标准模式，还是会触发它的兼容模式？”</p>
<p>答案是，这是在Internet Explorer中触发标准模式的最少字符数目。我认为这也说明了HTML5规范的本质：它不追求理论上的完美。HTML5所体现的不是“噢，给作者一个简短好记的doctype不好吗？”，没错，简短好记是很好，但如果这个好记的doctype无法适应现有的浏览器，还不如把它忘了更好。因此，这个平衡把握得非常好，不仅理论上看是个好主意——简短好记的doctype，而且实践中同样也是个好主意——仍然可以触发标准模式。应该说，Doctype是一个非常典型的例子。</p>
<p>还有一个例子，同样可以说明规范是如何省略不必要的复杂性，避免不必要的复杂性的。如果前面的文档使用的是HTML 4.01，假设我要指定文档的字符编码。理想的方式，是通过服务器在头部信息中发送字符编码，不过也可以在文档这个级别上指定：</p>
<pre class="brush: html; ">

&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot;&gt;
</pre>
<p>同样，我也不会把这行代码背下来。我还想省下自己的脑细胞去记点别的更有价值的东西呢。不过，如果我想指定文档使用UTF-8编码，只能添加这行代码。这是在HTML 4.01中需要这样做。要是你在XHTML 1.0指定同样的编码，就得多敲一下键盘，因为你还得声明meta元素位于一个开始的XML标签中。</p>
<pre class="brush: html; ">

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?&gt;
&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot; /&gt;
</pre>
<p>在HTML5中，你要敲的字符只有：</p>
<pre class="brush: html; ">

&lt;meta charset=&quot;utf-8&quot;&gt;
</pre>
<p>简短好记。我能背下来。</p>
<p>同样，这样写也是有效的。它不仅适用于最新版本的浏览器，只要是今天还有人在用的浏览器都同样有效。为什么？因为在我们把这些meta元素输入浏览器时，浏览器会这样解释它：“元数据（meta）点点点点点，字符集（charset）utf-8。”这就是浏览器在解释那行字符串时真正看到的内容。它必须看到这些内容，根据就是伯斯塔尔法则，对不对？</p>
<p>我多次提到健壮性原理，但总有人不理解。我们换一种说法，浏览器会想“好，我觉得作者是想要指定一个字符集……看，没错，utf-8。”这些都是规范里明文规定的。如今，不仅那个斜杠可以省了，而且总共只要写<span class="inline-code">meta charset=&#8221;utf-8&#8243;</span>就行了。</p>
<p>关于省略不必要的复杂性，或者说避免不必要的复杂性的例子还有不少。但关键是既能避免不必要的复杂性，还不会妨碍在现有浏览器中使用。比如说，在HTML5中，如果我使用link元素链接到一个样式表，我说了<span class="inline-code">rel=&#8221;stylesheet&#8221;</span>，然后再说<span class="inline-code">type=&#8221;text/css&#8221;</span>，那就是重复自己了。对浏览器而言，我就是在重复自己。浏览器用不着同时看到这两个属性。浏览器只要看到<span class="inline-code">rel=&#8221;stylesheet&#8221;</span>就够了，因为它可以猜出来你要链接的是一个CSS样式表。所以就不用再指定type属性了。你不是已经说了这是一个样式表了嘛；不用再说第二次了。当然，愿意的话，你可以再说；如果你想包含type属性，请便。</p>
<p>同样地，如果你使用了script元素，你说<span class="inline-code">type=&#8221;text/javascript&#8221;</span>，浏览器差不多就知道是怎么回事了。对Web开发而言，你还使用其他的脚本语言吗？如果你真想用其他脚本语言，没人会阻拦你。但我要奉劝你一句，任何浏览器都不会支持你。</p>
<p>愿意的话，你可以添加一个type属性。不过，也可以什么都不写，浏览器自然会假设你在使用JavaScript。避免-不必要的-复杂性。</p>
<h2>支持已有的内容</h2>
<p>支持已有的内容。这一点非常重要，因为很多人都认为HTML5很新，很闪亮；它应该代表着未来发展的方向，应该把Web推向一个新的发展阶段。这就是HTML5，对吗？显然，我们都会考虑让Web的未来发展得更好，但他们则必须考虑过去。别忘了W3C这个工作组中有很多人代表的是浏览器厂商，他们肯定是要考虑支持已有内容的。只要你想构建一款浏览器，就必须记住这个原则：必须支持已有的内容。</p>
<p>下面我们就来看一个HTML5支持已有内容的例子。</p>
<p>这个例子展示了编写同样内容的四种不同方式。上面是一个img元素，下面是带一个属性的段落元素。四种写法唯一的不同点就是语法。把其中任何一段代码交给浏览器，浏览器都会生成相同的DOM树，没有任何问题。从浏览器的角度看，这四种写法没有区别。因而在HTML5中，你可以随意使用下列任何语法。</p>
<pre class="brush: html; ">

&lt;img src=&quot;foo&quot; alt=&quot;bar&quot; /&gt;
&lt;p class=&quot;foo&quot;&gt;Hello world&lt;/p&gt;

&lt;img src=&quot;foo&quot; alt=&quot;bar&quot;&gt;
&lt;p class=&quot;foo&quot;&gt;Hello world

&lt;IMG SRC=&quot;foo&quot; ALT=&quot;bar&quot;&gt;
&lt;P CLASS=&quot;foo&quot;&gt;Hello world&lt;/P&gt;

&lt;img src=foo alt=bar&gt;
&lt;p class=foo&gt;Hello world&lt;/p&gt;
</pre>
<p>好了，看到这几段代码，恐怕有人会说“不对不对不对。其中只有一个是对的，另外三个——说不好。”不对，应该给属性值加引号！拜托，我们可是一直都给属性值加引号的！元素名大写对吗？这种做法10年不是就被抛弃了吗？</p>
<p>看到HTML5同时允许这些写法，我心里忍不住一阵阵想吐。我写了10年的XHTML 1.0，已经非常适应严格的语法了。但你必须明白，站在浏览器的角度上，这些写法实际上都是一样的。确实没有什么问题。</p>
<p>还有谁也感到不舒服了吗？有谁看到这些之后想“噢，这不是乱写嘛，这样做不对”？只有我这样想吗？还有别人吗？</p>
<p>但是，HTML5必须支持已经存在的内容，而已有的内容就是这个样子的。不是吗？根据伯斯塔尔法则，浏览器没有别的选择。</p>
<p>有人可能会说“这样不行。我觉得语言本身应该提供一种开关，让作者能够表明自己想做什么。”比如说，想使用某种特定的语法，像XHTML，而不是使用其他语法。我理解这些人的想法。但我不赞成在语言里设置开关。因为我们讨论的只是编码风格或者写作风格，跟哪种语法正确无关。对于像我们这样的专业人士，我认为可以使用lint工具（一种软件质量保证工具，或者说是一种更加严格的编译器。它不仅可以象普通编译器那样检查出一般的语法错误，还可以检查出那些虽然完全合乎语法要求，但很可能是潜在的、不易发现的错误），对其他技术我们不是也在使用lint工具嘛。</p>
<p>比如说对JavaScript使用lint工具。JavaScript同样也是比较混乱、不严谨的例子，但它非常强大，原因恰恰是它混乱、不严谨，而且有很多不同的编码方式。在JavaScript，你可以在每条语句末尾加上分号，但不是必需的，因为JavaScript会自动插入分号……是不是听起来有点不好接受？</p>
<p>正因为如此，才有了像JSlint这样的工具，在道格拉斯·克劳克福德（Douglas Crockford）的网站jslint.org上面。有个网页上写着“JSlint可能会伤害你的感情。”但这确实是个非常棒的工具，它可以把JavaScript代码变得完美无瑕。如果你通过JSlint运行JavaScript，它会告诉你“好，你的JavaScript代码有效，但写法不妥。你这种编码风格啊，我不喜欢。不赞成你这样写。这样写不好。”特别是对团队，对于要使用统一的编码风格的团队，JSlint是非常方便的工具。</p>
<p>我个人认为，不仅对团队来说，就算是你自己写代码，也要坚持一种语法风格。从浏览器解析的角度讲，不存在哪种语法比另一种更好的问题，但我认为，作为专业人士，我们必须能够自信地讲“这就是我的编码风格。”然而，我不认为语言里应该内置这种开关。你可以使用lint工具来统一编码风格。现在就来说说lint工具。大家可以登录htmllint.com，在其中运行你的HTML5文档，它会帮你检查属性值是否加了引号，元素是否小写，你还可以通过勾选复选框来设置其他检查项。</p>
<p>但这不意味着拒绝粗心大意的标记，做不做清理完全取决于你自己。我说过，因为浏览器必须支持已有的内容，HTML5自然也不能例外。归根结底还是伯斯塔尔法则。我们始终离不开伯斯塔尔法则。</p>
<h2>解决现实的问题</h2>
<p>HTML5的另一个设计原理是解决现实的问题。显而易见的是，解决各种问题的格式和规范已经比比皆是了，<del datetime="2011-04-07T05:12:24+00:00" title="感谢 @rukey67 指出这个翻译错误">因此在我看来，这个原理其实是要解决理论问题，而非解决现实的问题。这条设计原理是要从理论上承认人们普遍存在的问题，消除敏感问题。</del>但是在我看来，那些格式和规范要解决的都是理论问题，而非现实问题。这条设计原理才是真正要解决今天的人们所面临的现实问题、令人头疼的问题。</p>
<p>下面我来举个例子。相信这个例子有不少人都遇到过。假设我使用HTML 4或XHTML 1，页面中已经有了一块内容，我想给整块内容加个链接，怎么办？问题是这块内容里包含一个标题，一个段落，也许还有一张图片。如果我想给它们全部都可以点击，必须使用3个链接元素。于是，我得先把光标放在标题（比如说h2元素）中，写一个链接标签，然后再选中所有要包含到链接里面来的文本。接着，再把光标放在段落里，写一个链接标签，然后把段落中的文本放在链接里……</p>
<pre class="brush: js; ">

&lt;h2&gt;&lt;a href=&quot;/path/to/resource&quot;&gt;Headline text&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;/path/to/resource&quot;&gt;Paragraph text.&lt;/a&gt;&lt;/p&gt;
</pre>
<p>在HTML5中，我只要简单地把所有内容都包装在一个链接元素中就行了。</p>
<pre class="brush: js; ">

&lt;a href=&quot;/path/to/resource&quot;&gt;
&lt;h2&gt;Headline text&lt;/h2&gt;
&lt;p&gt;Paragraph text.&lt;/p&gt;
&lt;/a&gt;
</pre>
<p>没错，链接包含的都是块级元素，但现在我可以用一个元素包含它们。这样太好了。因为我碰到过类似的情形，必须给几个块级元素加上相同的链接，所有能这样写就太好了。为此，我就非常欢迎HTML5这个新标准。</p>
<p>它解决了一个现实的问题。我敢说在座不少朋友都曾遇到过这个问题。</p>
<p>那这到底解决的是什么问题呢？浏览器不必因此重新写代码来支持这种写法。这种写法其实早就已经存在于浏览器中了，因为早就有人这样写了，当然以前这样写是不合乎规范的。所以，说HTML5解决现实的问题，其本质还是“你都这样写了很多年了吧？现在我们把标准改了，允许你这样写了。”<br />
<img class="colorbox-2151"  src="http://fronteers.nl/_img/congres/2009/attendees-2.jpg" alt="Fronteers 2009" /></p>
<h2>求真务实</h2>
<p>在所有设计原理中，这一条恐怕是最响亮的了——求真务实。不知道大家有没有在公司里开会时听到过这种口号：“开拓进取，求真务实。”实际上，除了作为企业的口号，它还是一条非常重要的设计原理，因为求真务实对于HTML的含义是：在解决那些令人头痛的问题之前，先看看人们为应对这些问题都想出了哪些办法。集中精力去理解这些“民间的”解决方案才是当务之急。</p>
<p>HTML5中新的语义元素就是遵循求真务实原理的反映。新增的元素不算多，谈不上无限的扩展性，但却不失为一件好事。尽管数量屈指可数，但意义却非同一般。这些新元素涉及头部（header）、脚部（footer）、分区（section）、文章（article）……，相信大家都不会觉得陌生。我的意思是说，即便你不使用HTML5，也应该熟悉这些称呼，这些都是你曾经使用过的类名，比如<span class="inline-code">class=&#8221;header&#8221;</span>/<span class="inline-code">&#8220;head&#8221;</span>/<span class="inline-code">&#8220;heading&#8221;</span>，或<span class="inline-code">class=&#8221;footer&#8221;</span>/<span class="inline-code">&#8220;foot&#8221;</span>。当然，也可能是ID，<span class="inline-code">id=&#8221;header&#8221;</span>，<span class="inline-code">id=&#8221;footer&#8221;</span>。这些不都是我们已经司空见惯了的嘛。</p>
<p>好，举个例子吧，假设你今天写了下面这个文档。</p>
<pre class="brush: js; ">

&lt;body&gt;
&lt;div id=&quot;header&quot;&gt;...&lt;/div&gt;
&lt;div id=&quot;navigation&quot;&gt;...&lt;/div&gt;
&lt;div id=&quot;main&quot;&gt;...&lt;/div&gt;
&lt;div id=&quot;sidebar&quot;&gt;...&lt;/div&gt;
&lt;div id=&quot;footer&quot;&gt;...&lt;/div&gt;
&lt;/body&gt;
</pre>
<p>这里有一个div使用了<span class="inline-code">id=&#8221;header&#8221;</span>，另一个div使用了<span class="inline-code">id=&#8221;navigation&#8221;</span>，……。怎么样，都轻车熟路了吧？在HTML5中，这些元素都可以换掉。说起新增的语义元素，它们价值的一方面可以这样来体现：“嘿，看啊，这样多好，用HTML5新增的元素可以把这些div都替换掉。”</p>
<pre class="brush: js; ">

&lt;body&gt;
&lt;header&gt;...&lt;/header&gt;
&lt;nav&gt;...&lt;/nav&gt;
&lt;div id=&quot;main&quot;&gt;...&lt;/div&gt;
&lt;aside&gt;...&lt;/aside&gt;
&lt;footer&gt;...&lt;/footer&gt;
&lt;/body&gt;
</pre>
<p>当然了，你可以这样做。在文档级别上使用这些元素没有问题。但是，假如新增这些元素的目的仅仅是为了取代原来的div，那就真有点多此一举了。</p>
<p>虽然在这个文档中，我们用这些新元素来替换的是ID，但在我个人看来，将它们作为类的替代品更有价值。为什么这么说呢？因为这些元素在一个页面中不止可以使用一次，而是可以使用多次。没错，你可以为文档添加一个头部（header），再添加一个脚部（footer）；但文档中的每个分区（section）照样也都可以有一个头部和一个脚部。而每个分区里还可以嵌套另一个分区，被嵌套的分区仍然可以有自己的头部和脚部，是这样吧？</p>
<p>这四个新元素：section、article、aside和nav，之所以说它们强大，原因在于它们代表了一种新的内容模型，一种HTML中前所未有的内容模型——给内容分区。迄今为止，我们一直都在用div来组织页面中的内容，但与其他类似的元素一样，div本身并没有语义。但section、article、aside和nav实际上是在明确地告诉你——这一块就像文档中的另一个文档一样。位于这些元素中的任何内容，都可以拥有自己的概要、标题，自己的脚部。</p>
<p>其中最为通用的section，可以说是与内容最相关的一个。而article则是一种特殊的section。Aside呢，是一种特殊的section。最后，Nav也是一种特殊的section。</p>
<p>好，即便是现在，你照样可以使用div和类来描述页面中不同的部分，就像下面这样：</p>
<pre class="brush: js; ">

&lt;div class=&quot;item&quot;&gt;
&lt;h2&gt;...&lt;/h2&gt;
&lt;div class=&quot;meta&quot;&gt;...&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
...
&lt;/div&gt;
&lt;div class=&quot;links&quot;&gt;...&lt;/div&gt;
&lt;/div&gt;
</pre>
<p>其中包含可能是有关内容作者的元数据，而下面会给出一些链接，差不多就这样。在HTML5中，我完全可以说这块内容就是一个文档，通过对内容分区，使用section或article或aside，我可以说“这一块完全是可以独立存在的。”因此，我当然可以使用header和footer。</p>
<pre class="brush: js; ">

&lt;section class=&quot;item&quot;&gt;
&lt;header&gt;&lt;h1&gt;...&lt;/h1&gt;&lt;/header&gt;
&lt;footer class=&quot;meta&quot;&gt;...&lt;/footer&gt;
&lt;div class=&quot;content&quot;&gt;
...
&lt;/div&gt;
&lt;nav class=&quot;links&quot;&gt;...&lt;/nav&gt;
&lt;/section&gt;
</pre>
<p>请注意，即便是footer，也不一定非要出现在下面，不是吗？这几个元素，header、footer、aside、nav，最重要的是它们的语义；跟位置没有关系。一想到footer这个词，我们总会不由自主地想，“噢，应该放在下面。”同样，我们把aside想象成一个侧边栏。可是，如果你看一看规范，就会发现这些元素只跟内容有关。因此，放在footer中的内容也可以是署名，文章作者之类的，它只是你使用的一个元素。这个元素并没有说“必须把我放在文档或者分区的下面。”</p>
<p>这里，请注意，最重要的还不是我用几个新元素替换了原来的div加类，而是我把原来的H2换成了H1——震撼吧，我看到有人发抖了。我碰到过不少职业的Web开发人员，多年来他们一直认为规范里说一个文档中只能有一个H1。还有一些自诩为万能的SEO秘诀同样说要这样。很多SEO的技巧其实是很教条的。所谓教条，意思就是不相信数据。过去，这种教条表现为“不行，页面中包含两个以上的H1，你就会死掉的。”在HTML5中，只要你建立一个新的内容块，不管用section、article、aside、nav，还是别的元素，都可以在其中使用H1，而不必担心这个块里的标题在整个页面中应该排在什么级别；H2、H3，都没有问题。</p>
<p>这个变化太厉害了。想一想吧，这个变化对内容管理是革命性的。因为现在，你可以把每个内容分区想象一个独立的、能够从页面中拿出来的部分。此时，根据上下文不同，这个独立部分中的H1，在整个页面中没准会扮演H2或H3的角色——取决于它在文档中出现的位置。面对这个突如其来的变化，也许有人的脑子会暂时转不过弯来。不要紧，但我可以告诉你，我认为这才是HTML5中这些新语义标记的真正价值所在。换句话说，我们现在有了独立的元素了，这些元素中的标题级别可以重新定义。</p>
<p>我的文档中可能会包含一个分区，这个分区中可能会嵌套另一个分区，或者一篇文章，然后文章再嵌套分区，分区再嵌套文章、嵌套分区，文章再嵌套文章。而且每个分区和文章都可以拥有自己的H1到H6。从这个意义上讲，H元素真可谓“子子孙孙，无穷匮也”了。但是，在你编写内容或者内容管理系统的时候，它们又都是独立的，完全独立的内容块。这才是真正的价值所在。</p>
<p>实际上，这个点子并不是HTML5工作组拍脑门想出来的，也不是W3C最近才提出来的。下面这几句话摘自蒂姆·伯纳斯-李1991年的一封邮件，邮件是发给丹·康纳利（Dan Connolly）的。他在邮件中解释了对HTML的理解，他说：“你知道……知道我的想法，我认为H1、H2这样单调地排下去不好，我希望它成为一种可以嵌套的元素，或者说一个通用的H元素，我们可以在其中嵌套不同的层次。”但后来，我们没有看到通用的H元素，而是一直在使用H1和H2——那是因为我们一直在支持已有的内容。20年后的今天，这个理想终于实现了。</p>
<h2>平稳退化</h2>
<p>下一条原理大家应该都很熟悉了，那就是平稳退化。毕竟，我们已经遵守这条规则好多年了。渐进增强的另一面就是平稳退化。</p>
<p>有关HTML5遵循这条原理的例子，就是使用type属性增强表单。下面列出了可以为type属性指定的新值，有number、search、range，等等。</p>
<pre class="brush: js; ">

input type=&quot;number&quot;
input type=&quot;search&quot;
input type=&quot;range&quot;
input type=&quot;email&quot;
input type=&quot;date&quot;
input type=&quot;url&quot;
</pre>
<p>最关键的问题在于浏览器在看到这些新type值时会如何处理。现有的浏览器，不是将来的浏览器，现有的浏览器是无法理解这些新type值的。但在它们看到自己不理解的type值时，会将type的值解释为text。</p>
<p>无论你写的是<span style="font-family:'Palatino Linotype';">input type=&#8221;foo&#8221;</span>还是<span style="font-family:'Palatino Linotype';">input type=&#8221;bar&#8221;</bar>，现有的任何浏览器都会说：“嗯，也许作者的意思是text。”因而，你从现在开始就可以使用这些新值，而且你也可以放心，那些不理解它们的浏览器会把新值看成<span style="font-family:'Palatino Linotype';">type=&#8221;text&#8221;</span>，而这真是一个浏览器实践平稳退化原理的好例子。</p>
<p>比如说，你现在输入了<span style="font-family:'Palatino Linotype';">type=&#8221;number&#8221;</span>。假设你需要一个输入数值的文本框。那么你可以把这个input的type属性设置为number，然后理解它的浏览器就会呈现一个可爱的小控件，像带小箭头图标的微调控件之类的。对吧？而在不理解它的浏览器中，你会看到一个文本框，一个你再熟悉不过的文本框。既然如此，为什么不能说输入<span style="font-family:'Palatino Linotype';">type=&#8221;number&#8221;</span>就会得到一个带小箭头图标的微调控件呢？</p>
<p>当然，你还可以设置最小和最大值属性，它们同样可以平稳退化。这是问题的关键。</p>
<p>再看<span style="font-family:'Palatino Linotype';">input type=&#8221;search&#8221;</span>。你也可以考虑一下这种输入框，因为这种输入框在Safari中会被呈现为一个系统级的搜索控件，右边还有一个点击即可清除搜索关键词的X。而在其他浏览器中，你得到的则是一个文本框，就像你写的是<span style="font-family:'Palatino Linotype';">input type=&#8221;text&#8221;</span>一样，也就是你已经非常熟悉的文本框。那为什么还不使用<span style="font-family:'Palatino Linotype';">input type=&#8221;search&#8221;</span>呢？它不会有什么副作用，没有，对不对？</p>
<p>HTML5还为输入元素增加了新的属性，比如placeholder（占位符）。有人不知道这个属性的用处吗，没有吧？没错，就是用于在文本框中预先放一些文本。不对，不是标签（label）——占位符和标签完全不是一回事。占位符就是文本框可以接受的示例内容，一般颜色是灰色的。只要你一点击文本框，它就消失了。如果你把已经输入的内容全部删除，然后单击了文本框外部，它又会出现。</p>
<p>使用JavaScript编写一些代码当然也可以实现这个功能，但HTML5只用一个placeholder属性就帮我们解决了问题。</p>
<p>当然，对于不支持这个属性的浏览器，你还是可以使用JavaScript来实现占位符功能。通过JavaScript来测试浏览器支不支持该属性也非常简单。如果支持，后退一步，把路让开，乐享其成即可。如果不支持，可以再让你的JavaScript来模拟这个功能。</p>
<p>现在，我不得不提到另一个话题了：HTML5对Flash。也许你早听说过了，或者在哪里看到了这方面的讨论。说实话，我一点也不明白。我搞不懂人们怎么会仅仅凭自己的推测来展开争论。</p>
<p>首先，他们所说的HTML5对Flash，并不是指的HTML5，也不是指的Flash。而是指HTML5的一个子集和Flash的一个子集。具体来说，他们指的是视频。因此，不管你在哪里听到别人说“HTML5对Flash”，那很可能说的只是HTML5视频对Flash视频。</p>
<p>其次，一说HTML5对Flash，就好像你必须得作出选择一样：你站在哪一边？实际上不是这样的。HTML5规范的设计能够让你做到鱼和熊掌兼得。</p>
<p>好，下面就来看看这个新的video元素；真是非常贴心的一个元素，而且设计又简单，又实用。一个开始的video元素，加一个结束的video元素，中间可以放后备内容。注意，是后备内容，不是保证可访问性的内容，是后备内容。下面就是针对不支持video元素的浏览器写的代码：</p>
<pre class="brush: js; ">

&lt;video src=&quot;movie.mp4&quot;&gt;
&lt;!-- 后备内容 --&gt;
&lt;/video&gt;
</pre>
<p>那么，在后备内容里面放些什么东西呢？好，你可以放Flash影片。这样，HTML5的视频与Flash的视频就可以协同起来了。你不用作出选择。</p>
<pre class="brush: js; ">

&lt;video src=&quot;movie.mp4&quot;&gt;
&lt;object data=&quot;movie.swf&quot;&gt;
&lt;!-- 后备内容 --&gt;
&lt;/object&gt;
&lt;/video&gt;
</pre>
<p>当然，你的代码实际上并没有这么简单。因为这里我使用了H264，部分浏览器支持这种视频格式。但有的浏览器不支持。</p>
<p>对不起，请不要跟我谈视频格式，我一听就心烦。不是因为技术。技术倒无所谓，关键是会牵扯到一大堆专利还有律师、知识产权等等，这些都是Web的天敌，对我建网站一点好处都没有。</p>
<p>可你实际上要做的，仅仅就是把后备内容放在那而已，后备内容可以包含多种视频格式。如果愿意的话，可以使用source元素而非src属性来指定不同的视频格式。</p>
<pre class="brush: js; ">

&lt;video&gt;
&lt;source src=&quot;movie.mp4&quot;&gt;
&lt;source src=&quot;movie.ogv&quot;&gt;
&lt;object data=&quot;movie.swf&quot;&gt;
&lt;a href=&quot;movie.mp4&quot;&gt;download&lt;/a&gt;
&lt;/object&gt;
&lt;/video&gt;
</pre>
<p>上面的代码中包含了4个不同的层次。<br />
1、如果浏览器支持video元素，也支持H264，没什么好说的，用第一个视频。<br />
2、如果浏览器支持video元素，支持Ogg，那么用第二个视频。<br />
3、如果浏览器不支持video元素，那么就要试试Flash影片了。<br />
4、如果浏览器不支持video元素，也不支持Flash，我还给出了下载链接。</p>
<p>不错，一开始就能考虑这么周到很难得啊。有了这几个层次，已经够完善了。</p>
<p>总之，我是建议你各种技术要兼顾，无论是HTML5，还是Flash，一个也不能少。如果只使用video元素提供视频，难免搬起石头砸自己的脚，我个人认为。而如果只提供Flash影片，情况也好不到哪去，性质是一样的。所以还是应该两者兼顾。</p>
<p>为什么要兼顾这两种技术呢？假设你需要面向某些不支持Flash的手持设备——只是举个例子——提供视频，你当然希望手持设备的用户能够看到视频了，不是吗？</p>
<p>至于为什么要使用不同的格式，为什么Flash视频和音频如此成功，我想可以归结为另一个设计原理，即梅特卡夫定律(Metcalfe&#8217;s Law)：</p>
<p style="padding:2em;background:#eee;">
网络价值同网络用户数量的平方成正比。
</p>
<p>梅特卡夫的这个定律虽然是针对电话网提出来的，但在很多领域里也是适用的。使用网络的用户越多，网络的价值也就越大。人人都上Facebook，还不是因为人人都上Facebook嘛。虽然Facebook真正的价值不在于此，但只有人人都上才会让它的变得如此有价值。</p>
<p>梅特卡夫定律也适用于传真机。如果只有一个人购买了传真机，当然没有什么用处。但如果其他人也陆续购买了传真机，那么他的投资会就得到回报。</p>
<p>当然，面对竞争性的视频格式和不同的编码方式，你感觉不到梅特卡夫定律的作用，我也很讨厌以不同的方式来编码视频，但只向浏览器发送用一种方式编码的视频是行不通的。而这也正是Flash在视频/音频领域如此成功的原因。你只要把Flash影片发送给浏览器就好了，然后安装了插件的浏览器都能正常播放。本质上讲，Flash利用了梅特卡夫定律。</p>
<h2>最终用户优先</h2>
<p>今天我要讲的最后一个设计原理，也是我个人最推崇的一个，但没有要展示的代码示例。这个原理更有哲学的味道，即最终用户优先。</p>
<p>这个设计原理本质上是一种解决冲突的机制。换句话说，当你面临一个要解决的问题时，如果W3C给出了一种解决方案，而WHATWG给出了另一种解决方案，一个人这么想，另一个人那么想……这时候，有人站出来说：“对这个问题我们这样来解决。”</p>
<p style="padding:2em;background:#eee;">
一旦遇到冲突，最终用户优先，其次是作者，其次是实现者，其次标准制定者，最后才是理论上的完满。
</p>
<p>理论上的完满，大致是指尽可能创建出最完美的格式。标准制定者，指的是工作组、W3C，等等。实现者，指的是浏览器厂商。作者，就是我们这些开发人员，对吧？看看我们在这个链条里面的位置多靠上啊！我们的地位仅次于最终用户——事情本来就该这个样子。用户是第一位的。而我们的声音在标准制定过程中也同样非常非常重要。</p>
<p>Hixie（即Ian Hickson， Acid2、Acid3的作者及维护者，HTML5、CSS 2.1规范的制定者）经常说，在有人建议了某个特性，而HTML5工作组为此争论不下时，如果有浏览器厂商说“我们不会支持这个特性，不会在我们的浏览器中实现这个特性”，那么这个特性就不会写进规范。因为即使是把特性写进规范，如果没有厂商实现，规范不过是一纸空文，对不对？实现者可以拒绝实现规范。</p>
<p>而根据最终用户优先的原理，我们在链条中的位置高于实现者，假如我们发现了规范中的某些地方有问题，我们想“这样规定我们不能同意，我们不支持实现这个特性”，那么就等于把相应的特性给否定了，规范里就得删除，因为我们的声音具有更高的权重。我觉得这样挺好！本质上是我们拥有了更大的发言权，对吧？我认为开发人员就应该拥有更多的发言权。</p>
<p>我觉得这应该是最重要的一条设计原理了，因为它承认了你的权利，无论是设计一种格式，还是设计软件，这条原理保证了你的发言权。而这条原理也正道出了事物运行的本质。难道还不够明显吗？用户的权利大于作者，作者的权利大于实现者，实现者的权利大于标准制定者。然而，反观其他规范，比如XHTML2，你就会发现完全相反的做法。把追求理论的完满放在第一位，而把用户——需要忍受严格错误处理带来的各种麻烦的用户——放在了链条的最底端。我并没有说这种做法就是错误的，但我认为这是一种完全不同的思维方式。</p>
<p>因此，我认为无论你做什么，不管是构建像HTML5这样的格式，还是构建一个网站，亦或一个内容管理系统，明确你的设计原理都至关重要。</p>
<p style="padding:2em;background:#eee;">
软件，就像所有技术一样，具有天然的政治性。代码必然会反映作者的选择、偏见和期望。
</p>
<p>下面我们讲一个例子。Drupal社区曾联系马克·博尔顿（Mark Boulton）和丽莎·雷贺特（Leisa Reichilt）设计Drupal的界面。他们计划遵循一些设计原理。为此，他们并没有纸上谈兵，而是经过了一段时间的思考和酝酿，提出指导将来工作的4个设计原理：</p>
<p style="padding:2em;background:#eee;">
简化最常见的任务，让不常见的任务不至于太麻烦。<br />
只为80%设计。<br />
给内容创建者最大的权利。<br />
默认设置智能化。
</p>
<p>实际上，我在跟马克谈到这个问题时，马克说主要还是那两个，即“只为80%设计。给内容创建者最大的权利。”这就很不错了，至少它表明了立场，“我们认为内容创建者比这个项目中的任何人都重要。”在制定设计原理时，很多人花了很多时间都抓不住重点，因为他们想取悦所有人。关键在于我们不是要取悦所有人，而是要明确哪些人最重要。他们认为内容创建者是最重要的。</p>
<p>另一条设计原理，只为80%设计，其实是一条常见的设计原理，也是一种通用模式，即帕累托原理（Pareto principle）。</p>
<p>帕累托是意大利经济学家，他提出这个比例，80/20，说的是世界上20%的人口拥有80%的财富。这个比例又暗合了自然界各个领域的幂律分布现象。总之，无论你是编写软件，还是制造什么东西，都是一样的，即20%的努力可以触及80%的用例。最后20%的用例则需要付出80%甚至更多的努力。因此，有时候据此确定只为80%设计是很合理的，因为我们知道为此只要付出20%的努力即可。</p>
<p>再比如，微格式同样也利用了帕累托原理，只处理常见用例，而没有考虑少数情形。他们知道自己不会让所有人都满意；而他们的目标也不是让所有人都满意。他们遵循的设计原理很多，也都非常有价值，但最吸引人的莫过于下面这条了：</p>
<p style="padding:2em;background:#eee;">
首先为人类设计，其次为机器设计。
</p>
<p>同样，你我都会觉得这是一条再明显不过的道理，但现实中仍然有不少例子违反了这条原理：容易让机器理解（解析）比容易让用户理解更重要。</p>
<p>所以，我认为平常多看一看别人推崇的设计原理，有助于做好自己手头的工作。你可以把自己认为有道理的设计原理贴在墙上。当然，你可以维护一个URL，把自己认为有价值的设计原理分享出来，就像Mozilla基金会那样，对不对，以下是Mozilla的设计原理：</p>
<p style="padding:2em;background:#eee;">
Internet作为一种公共资源，其运作效率取决于互通性（协议、数据格式、内容）、变革及全球范围内的协作。<br />
基于透明社区的流程有助于增进协作、义务和信任。
</p>
<p>我觉得像这样的设计原理都非常好。而有了设计原理，我认为才更有希望设计出真正有价值的产品。设计原理是Web发展背后的驱动力，也是通过HTML5反映出来的某种思维方式。我想，下面这条原理你绝对不会陌生：</p>
<p style="padding:2em;background:#eee;">
<a name="html5_1"></a>大多数人的意见和运行的代码。<a href="#html5_1_note">[1]</a>
</p>
<p>对不对？这句话经常在我脑际回响，它囊括了Web的真谛，触及了HTML5的灵魂。</p>
<p>也许我该把这条原理打印出来贴到办公室的墙上，让它时刻提醒我，这就是Web的设计原理：大多数人的意见和运行的代码。</p>
<p>我想，今天的演讲就到这里了。如果大家有什么想法可以在twitter上通过@adactio找到我。有时候我也会在自己的博客，adactio.com上写写有关这个主题的文章。最后，可能还要顺便给我自己做个广告，我刚出了一本书，希望大家关注。</p>
<p>非常感谢大家。</p>
<p>[全文完]</p>
<p><img class="colorbox-2151"  src="http://ss5.sinaimg.cn/orignal/61baa48dx93226ab35934&#038;690" alt="Fronteers 2010" /></p>
<p>————————————<br />
<a name="html5_1_note"></a><a href="#html5_1">[1]</a> 1992年，大卫·克拉克（David Clark）教授在IETF会议上总结了这样一句话“We reject: kings, presidents, and voting. We believe in: rough consensus and running code”（我们拒绝国王、总统和投票，我们相信大多数人的意见和运行的代码）。这就是广为流传的“互联网哲学”（Internet Philosophy）。——译者注</p>
<p>最后编辑于：<br />
2010/11/07 @ 14:29</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cn-cuckoo.com/2010/10/21/the-design-of-html5-2151.html/feed</wfw:commentRss>
		<slash:comments>158</slash:comments>
		</item>
		<item>
		<title>从HTML 2.0到HTML5</title>
		<link>http://www.cn-cuckoo.com/2010/09/22/a-brief-history-of-markup-2079.html</link>
		<comments>http://www.cn-cuckoo.com/2010/09/22/a-brief-history-of-markup-2079.html#comments</comments>
		<pubDate>Tue, 21 Sep 2010 17:53:01 +0000</pubDate>
		<dc:creator>为之漫笔</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[好书]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://www.cn-cuckoo.com/?p=2079</guid>
		<description><![CDATA[原文链接：A Brief History of Markup 2010年9月23日校毕 HTML是World Wide Web上统一的语言。使用它所提供的标签，人类已经创建了令人惊奇、姿态万千的超链接的文档网络。看看Amazon、eBay和Wikipedia，再看看个人博客和专为猫咪建立的站点，无一不是HTML的杰作。 HTML5是这门通用语言的最新版。虽然这次升级的变化之大史无前例，但HTML更新换代已经不是第一次了。这门语言从诞生之日起一直在发展。 在发明Web的同时，Tim Berners-Lee先生创造了HTML（HyperText Markup Language，超文本标记语言）。1991年，他写了一篇名为“HTML Tags”的文档（另见更早的www-talk上的记录），其中建议人们使用20来个元素编写网页。 说到用尖括号包围文本的标签，并不是Tim先生的首创。更早的SGML（Standard Generalized Markup Language，标准通用标记语言）中就开始使用这种标签了。Tim先生当时并没有发明新语言，而是着眼于利用已经存在的技术——在HTML5的发展过程中，这个倾向依然得到了体现。 从IETF到W3C：HTML 4诞生记 HTML 1？这个版本实际上是不存在的。最早的HTML官方规范，是由IETF（Internet Engineering Task Force，因特网工程任务组）发布的HTML 2.0。这一规范中的许多特性，都是在已有实现的基础上归纳总结出来的。比如说，1994年居于市场领导地位的Mosaic浏览器提供了一个&#60;img&#62;标签，作者可以通过它在自己的文档中嵌入图像。后来，img元素就出现在了HTML 2.0中。 W3C（World Wide Web Consortium，万维网联盟）继IETF之后成为HTML后续标准的制定者，其官方网站是http://www.w3.org。20世纪90年代中期以后，W3C对HTML进行了几次升级，直至1999年发布HTML 4.01。 此时，HTML的发展走到了一个十字路口上。 XHTML 1：符合XML标准的HTML HMLT 4.01之后的一个修订版变成了XHTML 1.0。其中，X表示“eXtreme”（极端）。当时的Web开发人员在提到这个字母的时候，必须双臂交叉，作出一个X的形状来。 谁说的？纯属瞎掰。那个X表示的是“eXtensible”（可扩展），而且也没人要求你必须双臂交叉。 XHTML 1.0规范的内容与HTML 4.01完全相同，没有添加任何新元素或新属性。这两个规范唯一的差别就是对HTML的语法作出了不同的规定。HTML给予了作者最大的自由度，他们可以按照自己的意愿去写元素和属性，但XHTML要求作者遵从XML规则；XML是W3C大多数技术规范的基础，是一种更为严格的标记语言。 语法规则变得更严格了，这本身没有什么坏处。新规范的目的就是让作者按照统一的风格来编写标签。此前的标签和属性可以是大写、小写，或者任意大小写字母的组合，而有效的XHTML 1.0文档则要求所有标签和属性必须一律小写。 XHTML 1.0发布的时候恰逢浏览器普遍开始支持CSS。开发人员意识到了Web标准的出现，特别是在Web标准项目（The Web Standards Project）的倡导下，XHTML规定的这种更严格的语法被看成是写标记的“最佳实践”。 然后，W3C发布了XHTML 1.1。 虽然XHTML 1.0只不过是用XML来重新表示的HTML，但XHTML 1.1却是真正的、纯粹的XML。这意味着不能以text/html这样的MIME类型来提供XHTML [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: right;">原文链接：<a href="http://www.alistapart.com/articles/a-brief-history-of-markup/" target="_blank">A Brief History of Markup</a><br />
2010年9月23日校毕</p>
<p><div class="wp-caption alignleft" style="width: 405px"><a href="http://books.alistapart.com/products/html5-for-web-designers"><img class="colorbox-2079"  title="HTML5 for Web Designers" src="http://bkaprt.com/i/buy-html5-for-web-designers.png" alt="" width="395" height="554" /></a><p class="wp-caption-text">A Book Apart 的第一本书，由Jeremy Keith执笔；本文是该书第1章。</p></div> HTML是World Wide Web上统一的语言。使用它所提供的标签，人类已经创建了令人惊奇、姿态万千的超链接的文档网络。看看<a href="http://www.amazon.com/">Amazon</a>、<a href="http://www.ebay.com/">eBay</a>和<a href="http://en.wikipedia.org/wiki/Main_Page">Wikipedia</a>，再看看个人博客和专为猫咪建立的站点，无一不是HTML的杰作。</p>
<p>HTML5是这门通用语言的最新版。虽然这次升级的变化之大史无前例，但HTML更新换代已经不是第一次了。这门语言从诞生之日起一直在发展。</p>
<p>在发明Web的同时，Tim Berners-Lee先生创造了HTML（HyperText Markup Language，超文本标记语言）。1991年，他写了一篇<a href="http://www.w3.org/History/19921103-hypertext/hypertext/WWW/MarkUp/Tags.html">名为“HTML Tags”的文档</a>（<a href="http://lists.w3.org/Archives/Public/www-talk/1991SepOct/0003.html">另见更早的www-talk上的记录</a>），其中建议人们使用20来个元素编写网页。</p>
<p>说到用尖括号包围文本的标签，并不是Tim先生的首创。更早的<a href="http://www.iso.org/iso/catalogue_detail.htm?csnumber=16387">SGML（Standard Generalized Markup Language，标准通用标记语言）</a>中就开始使用这种标签了。Tim先生当时并没有发明新语言，而是着眼于利用已经存在的技术——在HTML5的发展过程中，这个倾向依然得到了体现。</p>
<h2>从IETF到W3C：HTML 4诞生记</h2>
<p>HTML 1？这个版本实际上是不存在的。最早的HTML官方规范，是<a href="http://www.ietf.org/">由IETF（Internet Engineering Task Force，因特网工程任务组）</a>发布的<a href="http://tools.ietf.org/html/rfc1866">HTML 2.0</a>。这一规范中的许多特性，都是在已有实现的基础上归纳总结出来的。比如说，1994年居于市场领导地位的<a href="http://en.wikipedia.org/wiki/Mosaic_(web_browser)">Mosaic浏览器</a>提供了一个&lt;img&gt;标签，作者可以通过它在自己的文档中嵌入图像。后来，img元素就出现在了HTML 2.0中。</p>
<p>W3C（World Wide Web Consortium，万维网联盟）继IETF之后成为HTML后续标准的制定者，其官方网站是<a href="http://www.w3.org">http://www.w3.org</a>。20世纪90年代中期以后，W3C对HTML进行了几次升级，直至1999年发布<a href="http://www.w3.org/TR/html401/">HTML 4.01</a>。</p>
<p>此时，HTML的发展走到了一个十字路口上。<br />
<span id="more-2079"></span></p>
<h2>XHTML 1：符合XML标准的HTML</h2>
<p>HMLT 4.01之后的一个修订版变成了<a href="http://www.w3.org/TR/xhtml1/">XHTML 1.0</a>。其中，X表示“eXtreme”（极端）。当时的Web开发人员在提到这个字母的时候，必须双臂交叉，作出一个X的形状来。</p>
<p>谁说的？纯属瞎掰。那个X表示的是“eXtensible”（可扩展），而且也没人要求你必须双臂交叉。</p>
<p>XHTML 1.0规范的内容与HTML 4.01完全相同，没有添加任何新元素或新属性。这两个规范唯一的差别就是对HTML的语法作出了不同的规定。HTML给予了作者最大的自由度，他们可以按照自己的意愿去写元素和属性，但XHTML要求作者遵从XML规则；XML是W3C大多数技术规范的基础，是一种更为严格的标记语言。</p>
<p>语法规则变得更严格了，这本身没有什么坏处。新规范的目的就是让作者按照统一的风格来编写标签。此前的标签和属性可以是大写、小写，或者任意大小写字母的组合，而有效的XHTML 1.0文档则要求所有标签和属性必须一律小写。</p>
<p>XHTML 1.0发布的时候恰逢浏览器普遍开始支持CSS。开发人员意识到了Web标准的出现，特别是在<a href="http://www.webstandards.org/">Web标准项目（The Web Standards Project）</a>的倡导下，XHTML规定的这种更严格的语法被看成是写标记的“最佳实践”。</p>
<p>然后，W3C发布了<a href="http://www.w3.org/TR/xhtml11/">XHTML 1.1</a>。</p>
<p>虽然XHTML 1.0只不过是用XML来重新表示的HTML，但XHTML 1.1却是真正的、纯粹的XML。这意味着不能以text/html这样的<a href="http://en.wikipedia.org/wiki/MIME">MIME类型</a>来提供XHTML 1.1文档。可是，如果有作者以XML的MIMI类型（application/xhtml+xml）来发布文档，那么当时世界上最流行的Web浏览器——Internet Explorer，又无法呈现该文档。</p>
<p>看起来W3C好像已经开始与日常的Web发布脱节了。</p>
<h2>XHTML 2：我们不接受！</h2>
<p>如果达斯汀·霍夫曼（Dustin Hoffman）在电影《毕业生》（<em>The Graduate</em>）中的角色是一名Web设计师，那么W3C只会对他说一句话，就一句话：XML。<a name="footref1"></a><a href="#footnotes1">[1]</a></p>
<p>W3C在接管HTML的时候，HTML的版本已经到了4。现在，他们又着手开发<a href="http://www.w3.org/TR/xhtml2/">XHTML 2</a>，旨在把Web引向建立在XML之上的无比光明的美好未来。</p>
<p>虽然XHTML 2的名字听起来与XHTML 1非常类似，但它们的差别却非常之大。与XHTML 1不一样，XHTML 2与既有的Web内容都不兼容，甚至就连以前版本的HTML都不兼容。说白了，XHTML 2就是要成为一门纯粹的语言，与以前规范的邋遢历史没有任何干系。</p>
<p>没想到竟是一场灾难。</p>
<h2>分裂：WHATWG TF？</h2>
<p>一股反抗势力在W3C内部逐步壮大。W3C热衷于从理论角度构建纯净的标准，却无视Web设计人员的需求。来自<a href="http://www.opera.com/">Opera</a>、<a href="http://www.apple.com/">Apple</a>和<a href="http://www.mozilla.org/">Mozilla</a>的代表对这种倾向非常反感。他们希望那些支持创建Web应用的特性能够得到更多的关注。</p>
<p>2004年的一次工作组会议成了矛盾激化的导火索。<a href="http://ian.hixie.ch/">伊恩·希克森（Ian Hickson）</a>——当时还在Opera Software效力——建议以支持创建Web应用为目标来扩展HTML。这个建议被驳回了。</p>
<p>心怀不满的反抗者建立了自己的组织：<a href="http://www.whatwg.org/">Web Hypertext Application Technology Working Group</a>（Web超文本应用技术工作组），简称WHATWG。</p>
<h2>从Web Apps 1.0到HTML5</h2>
<p>从一开始，WHATWG的工作方式就与W3C截然不同。W3C采取基于表决的方式：提出议题、讨论议题，然后投票表决。而在WHATWG，同样会提出和讨论议题，但哪些特性可以写入规范的最终决定权在编辑手中。这个编辑就是伊恩·希克森。</p>
<p>表面上看，W3C的流程更民主也更公平。但实际上，政治博弈加上内部争论，经常会导致流程停滞不前。而在WHATWG，任何人都可以自由地发表意见，但负责拍板的则只有编辑一个人，因此工作效率明显高很多。其实编辑也并非拥有绝对的权力：一个仅由受邀人员组成的指导委员会可以质疑编辑的偏执做法。</p>
<p>最初，WHATWG的大部分工作被分为两个规范：<a href="http://www.whatwg.org/specs/web-forms/current-work/">Web Form 2.0</a>和<a href="http://www.whatwg.org/specs/web-apps/2005-09-01/">Web Apps 1.0</a>。这两个规范都是在HTML的基础上扩展而来的。后来，这两个规范又被合并到一起，简单地称作<a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/">HTML5</a>。</p>
<h2>再次联手</h2>
<p>在WHATWG开发HTML5期间，W3C继续制定XHTML 2规范。如果说XHTML 2规范的制定速度很快那是忽悠人的。实际上，别提有多慢了。</p>
<p>2006年10月，Tim Berners-Lee先生发表了一篇博客，承认将Web从HTML迁移到XML是行不通的。几个月后，W3C签发了新委任状，成立了一个HTML工作组。这个工作组并没有从头开始，而是明智地决定在WHATWG工作成果的基础上开发下一个HTML版本。</p>
<p>一套起步停车的动作做下来以后，局面反倒让人不理解了。<a href="http://www.w3.org/MarkUp/Activity">W3C同时有两个工作组，分别负责制定不同的、互不兼容的标记语言</a>：<a href="http://www.w3.org/2007/03/XHTML2-WG-charter">XHTML 2</a>和<a href="http://www.w3.org/2007/03/HTML-WG-charter.html">HTML 5</a>（注意数字5前面有一个空格）。与此同时，还有一个独立的组织——WHATWG，正在开发HTML5（没有空格）规范，而该规范还将成为上述W3C中一个规范的基础！</p>
<p>每个想稿清楚上述状况的Web设计人员都会发现，还是破解电影《记忆碎片》（<em>Memento</em>）、《雷管》（<em>Primer</em>）中扑朔迷离的故事情节更容易一些，甚至就连摸清大卫·林奇（David Lynch）这样善用颠倒错乱、诡异多变的形象来迷惑人的导演的套路都没有那么复杂。</p>
<h2>XHTML已死，XHTML语法长生</h2>
<p>种种迷团终于在2009年烟消云散。W3C宣布不再续颁<a href="http://www.w3.org/2007/03/XHTML2-WG-charter">XHTML 2工作组的委任状</a>。XHTML 2作为一种格式实际上已经死了好几年了；这次的宣布差不多可以看成是为它补发了一张死亡证明。</p>
<p>奇怪的是，XHTML 2并没有平静地逝去，不少兴灾乐祸的小人跳出来大放厥词。XML反对者趁机奚落使用XHTML 1的人——连XHTML 1和XHTML 2几乎没有共同点这个事实都视而不见。</p>
<p>这时候，那些遵照XHTML 1较为严格规则的作者又担心起来，生怕HTML5又回到支持邋遢标记的老路上去。</p>
<p>其实，这个担心是多余的。HTML5允许邋邋遢遢的标记，也支持严格的标记，到底邋遢还是严格就要看编写标记的人了。</p>
<h2>HTML5的时间线</h2>
<p>HTML5目前的状态已经不似先前那么含含糊糊了，但仍然还是不甚明了。</p>
<p>有两个工作组在围绕HTML5工作。WHATWG正在使用它的“提交后评审”流程创建HTML5规范。而HTML Working Group则把这个规范作为输入，并将其纳入到了自己的“评审后提交”的流程当中。不难想见，这个联盟并不和谐。最后，仍然还需要就类似“要空格还是不要空格？”这样讨厌的问题达成共识才行。</p>
<p>对于刚刚涉足HTML5的Web开发人员来说，最令他们困惑的一个问题莫过于“这个规范什么时候能够完工啊？”</p>
<p>在一次采访中，伊恩·希克森提到HTML5估计要等到2022年才能成为推荐标准。有些Web设计者听他这么一说，立刻就激动起来。他们并不理解所谓的“推荐标准”意味着什么，但他们知道从现在开始数到2022，自己的10个手指头根本就不够用的。</p>
<p>这种激动完全是没有来由的。想一想吧，成为“推荐标准”，意味必须要有两个HTML5的完整实现。考虑到这个规范涵盖的范围之广，这个时间点恐怕都有点仓促了。历史表明，没有哪款浏览器在实现既有标准方面是做得出色的。仅仅支持一个小小的abbr元素，Internet Explorer就用了10多年的时间。</p>
<p>与HTML5真正有关系的日期应该是2012年。这是它预计将会成为“候选标准”的时间。成为“候选标准”，就意味着标准的制定工作结束了。</p>
<p>不过，即便是这个时间对Web开发人员来说也不是特别重要。真正重要的问题是浏览器从什么时候开始支持HTML5的特性。从浏览器一支持<a href="http://www.w3.org/TR/CSS2/">CSS 2.1</a>的部分特性，我们就开始使用那些特性了。要是等到所有浏览器都完全支持CSS 2.1我们才去使用它，那么恐怕现如今我们在痴痴地等呢。</p>
<p>HTML5不也一样嘛。没有人规定这个时间点，说不到这个时间你就不能使用HTML5。只要浏览器支持，我们就先使用那些它们支持的特性就不完了吗。</p>
<p>切记，HTML5并不是一门凭空造出来的新语言。它的标记变化都是革新性的，不是革命性的。无论你现在使用哪个版本的HTML创建网站，你都可以说自己已经在使用HTML5了。</p>
<hr size="1" /><a name="footnotes1"></a> <a href="#footref1">[1]</a> 男主角本杰明是一位以优异成绩毕业的大学生，其父亲的好友麦奎尔先生对他未来职业规划的建议只有一句话：塑料。——译者注</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cn-cuckoo.com/2010/09/22/a-brief-history-of-markup-2079.html/feed</wfw:commentRss>
		<slash:comments>20</slash:comments>
		</item>
		<item>
		<title>在Windows平台的Apache中配置Python</title>
		<link>http://www.cn-cuckoo.com/2010/08/19/run-python-in-apache-by-use-mod_python-1960.html</link>
		<comments>http://www.cn-cuckoo.com/2010/08/19/run-python-in-apache-by-use-mod_python-1960.html#comments</comments>
		<pubDate>Thu, 19 Aug 2010 11:25:35 +0000</pubDate>
		<dc:creator>为之漫笔</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[编程技术]]></category>

		<guid isPermaLink="false">http://www.cn-cuckoo.com/?p=1960</guid>
		<description><![CDATA[要在Windows平台的Apache中使用Python，当然必须得先安装Apache和Python。Apache我使用的是XAMPP，而Python则随便一搜，就可以找到下载链接。由于这个解决方案要通过安装Apache模块mod_python来实现，而mod_python的当前版本3.3.1只支持Apache 2.2和Python 2.5，所以不得不先缷载已经装好的Python 3.0，重新下载安装了Python 2.5。mod_python是一个Apache模块，它可以将Python解释器嵌入到Apache服务器中（详情可以看这里）。 让Apache支持Python的过程很简单，只要3步。 下载mod_python模块安装程序（注意文件名后面Python和Apache的版本号要与自己已经安装的版本一致；文件名前面的版本号则是mod_python的，文件名示例：mod_python-3.3.1.win32-py2.5-Apache2.2.exe），然后安装，安装向导会自动找到Python路径，但可能需要我们手工指定Apache路径，安装到最后，向导还会提示你如何修改Apache配置文件（参见下一步）并给出了后续步骤的英文说明。 让Apache加载mod_python模块。在Apache安装目录下找到其配置文件apache\conf\httpd.conf，打开，搜“LoadModule”，找到加载模块的地方，然后添加一条语句：LoadModule python_module modules/mod_python.so，重新启动Apache。 在htdocs目录下新建一个目录，如：“py”。进入py目录，新建一个文本文件，并命名为“.htaccess”，加入下列3条指令： AddHandler mod_python .py PythonHandler mptest PythonDebug On 这里第一条指令是将所有URL末尾为.py的请求转发给mod_python处理程序，mod_python接收到请求之后再寻找适当的PythonHandler处理程序。第二条指令只定义了一个mptest处理程序。最后一条是启用Python代码调试功能，以便在代码运行出错时输出Python解释器返回的错误。 完成以上3步之后，就可以编写Python文件并进行测试了。在py目录下新建 mptest.py 文件，打开后添加如下代码： from mod_python import apache def handler(req): req.content_type = &#039;text/plain&#039; req.write(&#34;Hello World!&#34;) return apache.OK 保存。打开浏览器，输入http://localhost/py/mptest.py，回车。看到“Hello World！”了吗？ 实际上，由于前面只明确将mptest设置为处理程序，所以无论浏览器URL中的.py文件名是什么（如：login.py、default.py），都将被转发给mptest.py文件来处理，都会返回“Hello World！”。怎么办呢？长话短说，可以将上面第3步中的代码替换成如下所示： AddHandler mod_python .py PythonHandler mod_python.publisher PythonDebug On 更多内容，参见Mod_python Manual和Introducing mod_python。]]></description>
			<content:encoded><![CDATA[<p>要在Windows平台的Apache中使用Python，当然必须得先安装Apache和Python。Apache我使用的是<a title="下载XAMPP" href="http://www.apachefriends.org/zh_cn/xampp.html" target="_blank">XAMPP</a>，而Python则随便一搜，就可以找到下载链接。由于这个解决方案要通过安装Apache模块mod_python来实现，而mod_python的当前版本3.3.1只支持Apache 2.2和Python 2.5，所以不得不先缷载已经装好的Python 3.0，重新下载安装了Python 2.5。mod_python是一个Apache模块，它可以将Python解释器嵌入到Apache服务器中（<a title="http://www.modpython.org/" href="http://www.modpython.org/" target="_blank">详情可以看这里</a>）。</p>
<p>让Apache支持Python的过程很简单，只要3步。</p>
<ol>
<li><a title="下载mod_python安装文件" href="http://www.apache.org/dist/httpd/modpython/win/" target="_blank">下载mod_python模块安装程序</a>（注意文件名后面Python和Apache的版本号要与自己已经安装的版本一致；文件名前面的版本号则是mod_python的，文件名示例：<strong>mod_python-3.3.1</strong>.win32-<strong>py2.5</strong>-<strong>Apache2.2</strong>.exe），然后安装，安装向导会自动找到Python路径，但可能需要我们手工指定Apache路径，安装到最后，向导还会提示你如何修改Apache配置文件（参见下一步）并给出了<a title="修改完Apache配置文件（httpd.conf）后，看这个链接。" href="http://www.modpython.org/live/current/doc-html/inst-testing.html" target="_blank">后续步骤的英文说明</a>。</li>
<li>让Apache加载mod_python模块。在Apache安装目录下找到其配置文件apache\conf\httpd.conf，打开，搜“LoadModule”，找到加载模块的地方，然后添加一条语句：<strong>LoadModule python_module modules/mod_python.so</strong>，重新启动Apache。</li>
<li>在htdocs目录下新建一个目录，如：“py”。进入py目录，新建一个文本文件，并命名为“.htaccess”，加入下列3条指令：
<pre class="brush: py; ">

AddHandler mod_python .py
PythonHandler mptest
PythonDebug On
</pre>
<p>这里第一条指令是将所有URL末尾为.py的请求转发给mod_python处理程序，mod_python接收到请求之后再寻找适当的PythonHandler处理程序。第二条指令只定义了一个mptest处理程序。最后一条是启用Python代码调试功能，以便在代码运行出错时输出Python解释器返回的错误。</li>
</ol>
<p>完成以上3步之后，就可以编写Python文件并进行测试了。在py目录下新建 mptest.py 文件，打开后添加如下代码：</p>
<pre class="brush: py; ">

from mod_python import apache

def handler(req):
	req.content_type = &#039;text/plain&#039;
	req.write(&quot;Hello World!&quot;)
	return apache.OK
</pre>
<p>保存。打开浏览器，输入http://localhost/py/mptest.py，回车。看到“Hello World！”了吗？</p>
<p>实际上，由于前面只明确将mptest设置为处理程序，所以无论浏览器URL中的.py文件名是什么（如：login.py、default.py），都将被转发给mptest.py文件来处理，都会返回“Hello World！”。怎么办呢？长话短说，可以将上面第3步中的代码替换成如下所示：</p>
<pre class="brush: py; ">

AddHandler mod_python .py
PythonHandler mod_python.publisher
PythonDebug On
</pre>
<p>更多内容，参见<a href="http://www.modpython.org/live/current/doc-html/modpython.html"><em>Mod_python Manual</em></a>和<a href="http://onlamp.com/pub/a/python/2003/10/02/mod_python.html"><em>Introducing mod_python</em></a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cn-cuckoo.com/2010/08/19/run-python-in-apache-by-use-mod_python-1960.html/feed</wfw:commentRss>
		<slash:comments>36</slash:comments>
		</item>
		<item>
		<title>《JavaScript高级程序设计（第2版）》快出版了</title>
		<link>http://www.cn-cuckoo.com/2010/06/24/professional-javascript-for-web-developers-2nd-will-soon-be-published-1706.html</link>
		<comments>http://www.cn-cuckoo.com/2010/06/24/professional-javascript-for-web-developers-2nd-will-soon-be-published-1706.html#comments</comments>
		<pubDate>Thu, 24 Jun 2010 06:30:54 +0000</pubDate>
		<dc:creator>为之漫笔</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[好书]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://www.cn-cuckoo.com/?p=1706</guid>
		<description><![CDATA[]]></description>
			<content:encoded><![CDATA[<p style="text-align: center;"><a title="互动网本书页面" href="http://www.china-pub.com/196857" target="_blank"><img class="colorbox-1706"  src="http://images.china-pub.com/ebook195001-200000/196857/shupi.jpg" alt="《JavaScript高级程序设计（第2版）》" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.cn-cuckoo.com/2010/06/24/professional-javascript-for-web-developers-2nd-will-soon-be-published-1706.html/feed</wfw:commentRss>
		<slash:comments>36</slash:comments>
		</item>
		<item>
		<title>《JavaScript高级程序设计（第2版）》译者序</title>
		<link>http://www.cn-cuckoo.com/2010/05/24/the-translators-foreword-for-professional-javascript-1644.html</link>
		<comments>http://www.cn-cuckoo.com/2010/05/24/the-translators-foreword-for-professional-javascript-1644.html#comments</comments>
		<pubDate>Mon, 24 May 2010 07:57:47 +0000</pubDate>
		<dc:creator>为之漫笔</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[好书]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://www.cn-cuckoo.com/?p=1644</guid>
		<description><![CDATA[寻人启示 lyongde 同学，请尽快将你的名字发到我的邮箱里面（lsf.email[at]gmail.com），以便在第二次印刷时加到译者序中以表感谢。 儒家经典《大学》将“格物致知”奉为做学问、养身性的最高境界。 尼古拉斯•扎卡斯重新修订的这个最新版本，为各层次的JavaScript爱好者和Web前端开发人员提供了一条“格物致知”的捷径。 新版本的原书不仅篇幅由原来的600多页增加到800页，而且几乎全部更新、重写了上一版的内容，删除了上一版中与今天的职业需求无关的主题，新增了大量比上一版更有价值、更能反映JavaScript最新发展成果的内容。从颇具深度的JavaScript语言基础到作用域（链），从JavaScript引用类型到面向对象编程，从极其灵活的匿名函数到闭包的内部机制，从浏览器对象模型（BOM）到客户端检测，从文档对象模型（DOM）到基于事件的Web脚本编程，从错误处理到前端调试，从XML（E4X）到Ajax及JSON，从高级前端开发技术到前沿的客户端存储，从最佳编程实践到展望即将成为现实的API，直至JavaScript未来的发展。全书基本上囊括了JavaScript技术的各个方面，几乎涉及到了Web前端开发的所有热门话题。值得一提的是，本书还涵盖了当前最受开发人员关注的HTML5和移动设备（如iPhone）开发的内容。可以预见，本书一定会成为Web前端开发人员不可多得的经典之作。 需要提请读者注意的是，本书第22章讲到了JavaScript未来的变化，里面大部分讲的是ECMAScript 4/JavaScript 2，而ECMAScript 4已经被放弃了，新标准是ECMAScript 5。请读者参考http://www.ecmascript.org/。感谢周涛（Snandy）指出此问题。 本书文前和第1章至第17章由李松峰翻译，第18章至第22章及附录由曹力翻译。武卫东老师审读斧正了序的翻译，责任编辑朱巍为本书早日出版多方协调，执行编辑毛倩倩发现了译稿中多处错译和漏译，排校负责人董秋霞、谢凌老师严把三道排校质量关、谢廷晟全面审校了第1章至第17章，吴玺喆（George Wing）、吴生辉（千年一梦）、周裕波、梁超（LC）、张树恒(shuzai)、罗永德（lyongde）也审校了前17章的部分内容，为确保本书翻译质量起到了重要作用，在此对上述老师和同学致以深深的谢意。 译者 2010年5月]]></description>
			<content:encoded><![CDATA[<div style="background:#eee;padding:0 1em 1em 1em;margin-bottom:1em;text-decoration:line-through;">
<p style="font-size:1.5em;color:red;text-align:center;">寻人启示</p>
<p>lyongde 同学，请尽快将你的名字发到我的邮箱里面（lsf.email[at]gmail.com），以便在第二次印刷时加到译者序中以表感谢。</p></div>
<p>儒家经典《大学》将“格物致知”奉为做学问、养身性的最高境界。</p>
<p>尼古拉斯•扎卡斯重新修订的这个最新版本，为各层次的JavaScript爱好者和Web前端开发人员提供了一条“格物致知”的捷径。</p>
<p>新版本的原书不仅篇幅由原来的600多页增加到800页，而且几乎全部更新、重写了上一版的内容，删除了上一版中与今天的职业需求无关的主题，新增了大量比上一版更有价值、更能反映JavaScript最新发展成果的内容。从颇具深度的JavaScript语言基础到作用域（链），从JavaScript引用类型到面向对象编程，从极其灵活的匿名函数到闭包的内部机制，从浏览器对象模型（BOM）到客户端检测，从文档对象模型（DOM）到基于事件的Web脚本编程，从错误处理到前端调试，从XML（E4X）到Ajax及JSON，从高级前端开发技术到前沿的客户端存储，从最佳编程实践到展望即将成为现实的API，直至JavaScript未来的发展。全书基本上囊括了JavaScript技术的各个方面，几乎涉及到了Web前端开发的所有热门话题。值得一提的是，本书还涵盖了当前最受开发人员关注的HTML5和移动设备（如iPhone）开发的内容。可以预见，本书一定会成为Web前端开发人员不可多得的经典之作。</p>
<p>需要提请读者注意的是，本书第22章讲到了JavaScript未来的变化，里面大部分讲的是ECMAScript 4/JavaScript 2，而ECMAScript 4已经被放弃了，新标准是ECMAScript 5。请读者参考http://www.ecmascript.org/。感谢周涛（Snandy）指出此问题。</p>
<p>本书文前和第1章至第17章由李松峰翻译，第18章至第22章及附录由曹力翻译。武卫东老师审读斧正了序的翻译，责任编辑朱巍为本书早日出版多方协调，执行编辑毛倩倩发现了译稿中多处错译和漏译，排校负责人董秋霞、谢凌老师严把三道排校质量关、谢廷晟全面审校了第1章至第17章，吴玺喆（George Wing）、吴生辉（千年一梦）、周裕波、梁超（LC）、张树恒(shuzai)、罗永德（lyongde）也审校了前17章的部分内容，为确保本书翻译质量起到了重要作用，在此对上述老师和同学致以深深的谢意。</p>
<p style="text-align: right;">译者<br />
2010年5月</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cn-cuckoo.com/2010/05/24/the-translators-foreword-for-professional-javascript-1644.html/feed</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>关于《JavaScript高级程序设计（第2版）》中的一句话</title>
		<link>http://www.cn-cuckoo.com/2010/05/08/about-one-sentence-of-pro-js-2nd-1626.html</link>
		<comments>http://www.cn-cuckoo.com/2010/05/08/about-one-sentence-of-pro-js-2nd-1626.html#comments</comments>
		<pubDate>Sat, 08 May 2010 05:56:05 +0000</pubDate>
		<dc:creator>为之漫笔</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://www.cn-cuckoo.com/?p=1626</guid>
		<description><![CDATA[说明：《JavaScript高级程序设计（第2版）》（预计2010年7月份上市）的审校者谢廷晟针对书中一句关键的表述，给出了如下分析说明。虽然译者也同样意识到将this关键字与函数执行时所处的作用域简单地等同起来不恰当，但在书中其他章节里，还有多处类似表述。本着不擅自修改原文的原则，谨以此说明帮助读者慎思明辨（书中也通过译者注形式给出了此文的链接）。感谢廷晟的认真审校。 第5章中有这样一句话：“this是函数在执行时所处的作用域”（《JavaScript高级程序设计（第2版）》第5章5.5.4节正文倒数第3段中）。我觉得作者的这种说法大有问题。对JavaScript不熟悉的读者会越看越糊涂。这里首先需要明确两个概念：函数执行时所处的作用域、在哪个作用域中调用函数函数调用发生的作用域，否则讨论就无法继续深入。把后一概念明确为“函数调用语句所处的那个作用域”应该没有问题。而前一个概念，实际上就是函数的定义所处的那个作用域。以下面的代码为例： function a() { // ... } function b() { /// ... return function c() { // ... }; } var d = b(); a(); d(); 在这里，函数a、b和d（实际上就是c）都是在全局作用域中调用的。a和b执行时所处的作用域都是全局作用域。但是d执行时所处的作用域并不是全局作用域，而是函数b的局部作用域。说到这里，就可以看到“this是函数在执行时所处的作用域”这一说法的不妥了。假如函数c中引用到了this（在本例中，d是直接调用的，所以this指向的是全局对象），那么按作者的说法，c 岂不是直接运行在全局作用域中而不是b的局部作用域中了？再看下述例子： var greeting = &#039;Hello from global scope!&#039;; function e() { alert(greeting); alert(this.greeting); } var tom = { greeting:&#039;Hello from Tom!&#039; }; tom.f = e; tom.f(); 这个例子中的this指向的是什么？显然是tom。那么f（即e）执行时所处的作用域是什么？显然是全局作用域。假如f执行时所处的作用域如作者所说为this所指对象的话，那就意味着在本例中f执行时所处的作用域为tom，也就是说在f执行过程中，与其作用域链相对应的那个变量对象链的最前端那个对象是tom，而这就意味着在此时函数体内对名称greeting进行解析时首先遇到的是tom中定义的greeting，于是两条输出语句的结果都应该是“Hello [...]]]></description>
			<content:encoded><![CDATA[<div style="background:#eee;padding:10px;">说明：《JavaScript高级程序设计（第2版）》（预计2010年7月份上市）的审校者谢廷晟针对书中一句关键的表述，给出了如下分析说明。虽然译者也同样意识到将<strong>this关键字</strong>与<strong>函数执行时所处的作用域</strong>简单地等同起来不恰当，但在书中其他章节里，还有多处类似表述。本着不擅自修改原文的原则，谨以此说明帮助读者慎思明辨（书中也通过译者注形式给出了此文的链接）。感谢廷晟的认真审校。</div>
<p>第5章中有这样一句话：“<strong>this是函数在执行时所处的作用域</strong>”（《JavaScript高级程序设计（第2版）》第5章5.5.4节正文倒数第3段中）。我觉得作者的这种说法大有问题。对JavaScript不熟悉的读者会越看越糊涂。这里首先需要明确两个概念：函数执行时所处的作用域、<del datetime="2010-05-09T11:55:45+00:00">在哪个作用域中调用函数</del>函数调用发生的作用域，否则讨论就无法继续深入。把后一概念明确为“函数调用语句所处的那个作用域”应该没有问题。而前一个概念，实际上就是函数的定义所处的那个作用域。以下面的代码为例：</p>
<pre class="brush: js; ">

function a() {
 // ...
}

function b() {
 /// ...

 return function c() {
  // ...
 };
}

var d = b();
a();
d();
</pre>
<p>在这里，函数a、b和d（实际上就是c）都是在全局作用域中调用的。a和b执行时所处的作用域都是全局作用域。但是d执行时所处的作用域并不是全局作用域，而是函数b的局部作用域。说到这里，就可以看到“this是函数在执行时所处的作用域”这一说法的不妥了。假如函数c中引用到了this（在本例中，d是直接调用的，所以this指向的是全局对象），那么按作者的说法，c 岂不是直接运行在全局作用域中而不是b的局部作用域中了？再看下述例子：</p>
<pre class="brush: js; ">

var greeting = &#039;Hello from global scope!&#039;;

function e() {
 alert(greeting);
 alert(this.greeting);
}

var tom = {
 greeting:&#039;Hello from Tom!&#039;
};
tom.f = e;
tom.f();
</pre>
<p>这个例子中的this指向的是什么？显然是tom。那么f（即e）执行时所处的作用域是什么？显然是全局作用域。假如f执行时所处的作用域如作者所说为this所指对象的话，那就意味着在本例中f执行时所处的作用域为tom，也就是说在f执行过程中，与其作用域链相对应的那个变量对象链的最前端那个对象是tom，而这就意味着在此时函数体内对名称greeting进行解析时首先遇到的是tom中定义的greeting，于是两条输出语句的结果都应该是“Hello from Tom!”，这不符合事实，所以按作者的说法所做的那个假设是错误的。</p>
<p>对于this这个关键字，我认为不应该扯什么作用域的事儿，只要向读者说明以下几项<del datetime="2010-05-09T11:50:53+00:00">这样一句话</del>就够了：<del datetime="2010-05-09T11:44:46+00:00">函数作为哪个对象的方法调用，函数体内的this（不包括嵌套定义在其中的函数中的this）指向的就是那个对象。直接调用一个函数，相当于把它当作全局对象的方法调用。JavaScript 中没有类作用域的概念，因此方法内部要访问据以调用此方法的那个对象的属性，必须使用this关键字，按‘this.属性名’的语法来访问</del></p>
<ol>
<li>函数作为哪个对象的方法调用，函数体内的this（不包括嵌套定义在其中的函数中的this）指向的就是那个对象。</li>
<li>结合new运算符调用一个构造函数时，系统会先自动生成一个对象，然后在该对象上调用构造函数。此时在构造函数体内，this指向的就是这个对象。</li>
<li>直接调用一个函数，相当于把它当作全局对象的方法调用。</li>
<li>JavaScript中没有类作用域的概念，因此方法内部要访问据以调用此方法的那个对象的属性，必须使用this关键字，按“this.属性名”的语法来访问。</li>
</ol>
<p>与这个问题相关的还有一个函数体内的名称解析的问题。我看过的JavaScript教材上都说得不太全面。实际上，那种直接引用的名称，其名称解析是在作用域链上进行的；而那种按“obj.属性名”方式引用的名称，其名称解析是在obj的原型对象链上进行的（首先检查obj是否直接定义了同名属性，如果没有，则在其原型对象链上逐层查找）。理解了这一点，就更能搞清前面的this与作用域的瓜葛。</p>
<div style="background:#eee;padding:10px;">谢廷晟，《<a href="http://www.china-pub.com/508886">JavaScript设计模式</a>》和《<a href="http://www.china-pub.com/39715">深入浅出HTML</a>》的译者。<br/><br />
<a href="http://www.china-pub.com/508886"><img class="colorbox-1626"  src="http://images.china-pub.com/ebook505001-510000/508886/zcover.jpg" alt="《JavaScript设计模式》" /></a>&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://www.china-pub.com/39715"><img class="colorbox-1626"  src="http://images.china-pub.com/ebook35001-40000/39715/zcover.jpg" alt="《深入浅出HTML》" /></a>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.cn-cuckoo.com/2010/05/08/about-one-sentence-of-pro-js-2nd-1626.html/feed</wfw:commentRss>
		<slash:comments>79</slash:comments>
		</item>
		<item>
		<title>John Resig谈改进Web应用的高级JavaScript技术[待续]</title>
		<link>http://www.cn-cuckoo.com/2010/04/09/john-resig-on-advanced-javascript-to-improve-your-web-app-1493.html</link>
		<comments>http://www.cn-cuckoo.com/2010/04/09/john-resig-on-advanced-javascript-to-improve-your-web-app-1493.html#comments</comments>
		<pubDate>Fri, 09 Apr 2010 13:08:50 +0000</pubDate>
		<dc:creator>为之漫笔</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[翻译]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[John Resig]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://www.cn-cuckoo.com/?p=1493</guid>
		<description><![CDATA[原文链接：http://carsonified.com/blog/dev/john-resig-on-advanced-javascript-to-improve-your-web-app/ 录音整理：http://carsonified.com/blog/author/keir-whitaker/ 在线演示：http://ejohn.org/apps/workshop/adv-talk/index2.html 背景 2010年2月，JavaScript框架jQuery的创建者及核心开发人员John Resig，在今年迈阿密举行的Future of Web Apps大会上作了演讲。在短短25分钟的演讲中，John为与会者概述了jQuery 1.4背后的新特性和新理念。以下是根据他的演讲录音整理的文字稿。 谢谢。感谢邀请我来这里的所有人。真的非常感谢。今天，我想谈两个话题，基本上是围绕jQuery展开的，但我会尽量照顾到那些没有使用jQuery的朋友，希望这两个话题对你们开发Web应用也会有所帮助。 在座的所有朋友在开发Web应用时，可能都要用到几种技术。我们总想提升JavaScript代码的性能，总想增强易访问性，让代码更简单一点。最后，我们还想让设计过程再容易一些。 说到性能，在JavaScript中有很多技术可以运用，其中有三个比较容易，而通过jQuery来实现则会更容易。一个就是事件委托。事件委托是一种绕过传统方法的事件绑定技术。我的意思是说，通常在为某个元素添加单击处理程序时，你都是为每个需要绑定单击事件的元素分别绑定单击处理程序。这样做真的很浪费。如果有一个包含上千个单元格的表格，那么你就要添加大量的单击处理程序。 事件委托，就是在你添加处理程序时，要添加到DOM树上层的某个父元素上。比如，添加到表格上，而不是添加到每个单元格上。这样就可以利用浏览器原生的事件冒泡机制。也就是说，用户在单击某个单元格时，事件会沿DOM树向上冒泡，冒泡到表格，而你可以在这个时候再处理它。这就是事件委托。 这样一来，你只要为文档添加一个事件就行，根本用不着添加几千个。而且速度又快，灵活性又高。为此，jQuery提供了两个方法；一个是“dotlive”（.live()）。另一个则是我们前几天刚刚添加的方法，即“delegate”（.delegate()）。关于委托，除了它的速度快之外，我认为真正有价值的地方在于，它对所有当前乃至未来的元素都有效。即便现在文档中只有一千个单元格，而你又添加了一千个，它照样还是有效。你不用为处理新增的单元格而添加新处理程序。 委托方法（.delegate()）是这几天我们刚刚加进来的。这个方法的本质就是将委托的概念具体化了。下面我想讲一个实际的例子。假如你想为某个核心元素，例如表格，添加单击事件。然后你还要监视（这个表格中）任意单元格上的悬停事件。那么，只要编写短短几行代码，很快就可以实现你的意图。 $(&#8220;table&#8221;).delegate(&#8220;td&#8221;, &#8220;hover&#8221;, function(){ $(this).toggleClass(&#8220;active&#8221;); }); 实时事件（.live()）则是另外一种编写和实现委托的方式，但关键是它能起作用，并且看上去与事件绑定的效果还完全一样。你可以使用相同的语法，可以使用选择符，然后可以直接给它添加事件，或者至少看起来是直接的。而在后台，jQuery会帮你周旋并确保一切都各就各位。 举个例子，我们这里在鼠标悬停时会显示一些菜单，子菜单在消失时带一个小动画。有意思的是，如果我们又添加了新菜单，这个新添加的菜单也会带有相同的动画。这时候，动画效果的添加就是实时的。而且，不管是对页面中当前还是将来的元素，也都会持续有效。（点击这里查看交互演示。） $(&#8220;a.menu&#8221;).live(&#8220;hover&#8221;, function(){ $(this).next().toggle(200); return false; }); [未完待续……]]]></description>
			<content:encoded><![CDATA[<p><span id="more-1493"></span></p>
<p style="text-align: right;">原文链接：<a href="http://carsonified.com/blog/dev/john-resig-on-advanced-javascript-to-improve-your-web-app/">http://carsonified.com/blog/dev/john-resig-on-advanced-javascript-to-improve-your-web-app/</a><br />
录音整理：<a title="http://carsonified.com/blog/author/keir-whitaker/" href="http://carsonified.com/blog/author/keir-whitaker/" target="_blank">http://carsonified.com/blog/author/keir-whitaker/</a><br />
在线演示：<a title="http://ejohn.org/apps/workshop/adv-talk/index2.html" href="http://ejohn.org/apps/workshop/adv-talk/index2.html" target="_blank">http://ejohn.org/apps/workshop/adv-talk/index2.html</a></p>
<fieldset>
<legend>背景</legend>
<p>2010年2月，<a title="http://jquery.com/" href="http://jquery.com/" target="_blank">JavaScript框架jQuery</a>的创建者及核心开发人员<a title="http://ejohn.org/" href="http://ejohn.org/" target="_blank">John Resig</a>，在今年迈阿密举行的<a title="http://futureofwebapps.com/" href="http://futureofwebapps.com/" target="_blank">Future of Web Apps大会</a>上作了演讲。在短短25分钟的演讲中，John为与会者概述了jQuery 1.4背后的新特性和新理念。以下是根据他的演讲录音整理的文字稿。</fieldset>
<p>谢谢。感谢邀请我来这里的所有人。真的非常感谢。今天，我想谈两个话题，基本上是围绕jQuery展开的，但我会尽量照顾到那些没有使用jQuery的朋友，希望这两个话题对你们开发Web应用也会有所帮助。</p>
<p>在座的所有朋友在开发Web应用时，可能都要用到几种技术。我们总想<strong>提升JavaScript代码的性能</strong>，总想<strong>增强易访问性</strong>，让<strong>代码更简单</strong>一点。最后，我们还想让<strong>设计过程再容易</strong>一些。</p>
<p>说到性能，在JavaScript中有很多技术可以运用，其中有三个比较容易，而通过jQuery来实现则会更容易。一个就是<strong>事件委托</strong>。事件委托是一种绕过传统方法的事件绑定技术。我的意思是说，通常在为某个元素添加单击处理程序时，你都是为每个需要绑定单击事件的元素分别绑定单击处理程序。这样做真的很浪费。如果有一个包含上千个单元格的表格，那么你就要添加大量的单击处理程序。</p>
<p>事件委托，就是在你添加处理程序时，要添加到DOM树上层的某个父元素上。比如，添加到表格上，而不是添加到每个单元格上。这样就可以利用浏览器原生的事件冒泡机制。也就是说，用户在单击某个单元格时，事件会沿DOM树向上冒泡，冒泡到表格，而你可以在这个时候再处理它。这就是事件委托。</p>
<p>这样一来，你只要为文档添加一个事件就行，根本用不着添加几千个。而且速度又快，灵活性又高。为此，jQuery提供了两个方法；一个是“dotlive”（.live()）。另一个则是我们前几天刚刚添加的方法，即“delegate”（.delegate()）。关于委托，除了它的速度快之外，我认为真正有价值的地方在于，它对所有当前乃至未来的元素都有效。即便现在文档中只有一千个单元格，而你又添加了一千个，它照样还是有效。你不用为处理新增的单元格而添加新处理程序。</p>
<p>委托方法（.delegate()）是这几天我们刚刚加进来的。这个方法的本质就是将委托的概念具体化了。下面我想讲一个实际的例子。假如你想为某个核心元素，例如表格，添加单击事件。然后你还要监视（这个表格中）任意单元格上的悬停事件。那么，只要编写短短几行代码，很快就可以实现你的意图。</p>
<p>$(&#8220;table&#8221;).delegate(&#8220;td&#8221;, &#8220;hover&#8221;, function(){<br />
$(this).toggleClass(&#8220;active&#8221;);<br />
});</p>
<p>实时事件（.live()）则是另外一种编写和实现委托的方式，但关键是它能起作用，并且看上去与事件绑定的效果还完全一样。你可以使用相同的语法，可以使用选择符，然后可以直接给它添加事件，或者至少看起来是直接的。而在后台，jQuery会帮你周旋并确保一切都各就各位。</p>
<p>举个例子，我们这里在鼠标悬停时会显示一些菜单，子菜单在消失时带一个小动画。有意思的是，如果我们又添加了新菜单，这个新添加的菜单也会带有相同的动画。这时候，动画效果的添加就是实时的。而且，不管是对页面中当前还是将来的元素，也都会持续有效。（<a href="http://ejohn.org/apps/workshop/adv-talk/index2.html#5" target="_blank">点击这里查看交互演示</a>。）<br />
$(&#8220;a.menu&#8221;).live(&#8220;hover&#8221;, function(){<br />
$(this).next().toggle(200);<br />
return false;<br />
});</p>
<p style="text-align: right;">[未完待续……]</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cn-cuckoo.com/2010/04/09/john-resig-on-advanced-javascript-to-improve-your-web-app-1493.html/feed</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>经典名著，精选样章</title>
		<link>http://www.cn-cuckoo.com/2010/02/06/professional-javascript-developers-wrox-programmer-sample-chapter-1411.html</link>
		<comments>http://www.cn-cuckoo.com/2010/02/06/professional-javascript-developers-wrox-programmer-sample-chapter-1411.html#comments</comments>
		<pubDate>Sat, 06 Feb 2010 14:16:27 +0000</pubDate>
		<dc:creator>为之漫笔</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[好书]]></category>
		<category><![CDATA[译作支持]]></category>

		<guid isPermaLink="false">http://www.cn-cuckoo.com/?p=1411</guid>
		<description><![CDATA[在一年一度的新春佳节即将到来之际，应热心读者的要求，为满足大家先睹为快的愿望，也为了答谢朋友们对本博客长期以来的支持，即日起到春节前夕，本站将发布尚未出版的《JavaScript高级程序设计（第2版）》一书的样章（暂定为3章，约115页）。 申请办法 1、发邮件到：lisf@turingbook.com。 2、邮件主题：《JavaScript高级程序设计（第2版）》样章；邮件内容：您的Email地址。 3、24小时内收到样章，先睹为快！ 备注：样章格式为PDF，托管在“Google文件”，可以在线查看（无须登录），也可以下载和打印。希望在线查看PDF的朋友，请在邮件正文中注明“希望接收Google文件”字样，即可收到样章的链接（也可以下载）；否则，将收到PDF文件（*请确保有5M以上的空余邮箱空间）。 样章列表（详细目录） 第3章 基本概念 第4章 变量、作用域及内存问题 第5章 引用类型 《JavaScript高级程序设计（第2版）》简介 本书是人民邮电出版社图灵公司引进出版的大畅销书、JavaScript权威著作《JavaScript高级程序设计》的最新升级版。《JavaScript高级程序设计》自2006年11月出版以来，已经累计销售逾30000册，而且至今仍然十分畅销。这一点可以通过北京新华文化发展有限公司（新华书店）近期的店面销售数据看出来（大家可以自行比较一下其他畅销书的销量）。应该说，在Web 2.0革命爆发的同时，人民邮电出版社图灵公司引进出版的本书成就了计算机图书市场上难得一见的奇迹。 本书作者尼古拉斯·扎卡斯（Nicholas C. Zakas）现为Yahoo!公司首席前端工程师，世界顶级Web技术专家。原书第1版曾被选为Yahoo!公司YUI（Yahoo! User Interface Library，Yahoo!用户界面库）团队的内部培训教材。 2009年初，本书第2版面世（《Professional JavaScript for Web developers, 2nd Edition》）。新版本不仅篇幅由原来的600多页增加到800页，而且几乎全部更新、重写了上一版的内容，删除了上一版中与今天的职业需求无关的主题，新增了大量比上一版更有价值、更能反映JavaScript最新发展成果的内容。从颇具深度的JavaScript语言基础到作用域（链），从JavaScript引用类型到面向对象编程的最佳实践，从极其灵活的匿名函数到闭包的内部机制，从浏览器对象模型（BOM）到客户端检测，从文档对象模型（DOM）到基于事件的Web脚本编程，从错误处理到前端调试，从XML（E4X）到Ajax及JSON，从高级前端开发技术到前沿的客户端存储，从最佳编程实践到展望即将成为现实的API，直至JavaScript未来的发展。全书彻底涵盖了JavaScript技术的各个方面，几乎涉及到了Web前端开发的每一处细节。可以预见，这部著作一定会成为Web前端开发人员不可多得的又一部经典。 目前，《JavaScript高级程序设计（第2版）》的翻译工作已经进入后期阶段（全书22章，所剩不到5章）。而且，为确保新版及时上市与读者见面，出版社采取了与译者同步翻译、同步编辑审校的特别措施。新版本预计2010年上半年可以上市；当然，在确保出版品质的前提下一定会尽量往前赶！ 样章详细目录 第3章 基本概念 1 3.1 语法 1 3.1.1 区分大小写 1 3.1.2 标识符 1 3.1.3 注释 2 3.1.4 语句 2 3.2 关键字和保留字 3 3.3 变量 4 [...]]]></description>
			<content:encoded><![CDATA[<p>在一年一度的新春佳节即将到来之际，应热心读者的要求，为满足大家先睹为快的愿望，也为了答谢朋友们对本博客长期以来的支持，即日起到春节前夕，本站将发布尚未出版的《JavaScript高级程序设计（第2版）》一书的样章（暂定为3章，约115页）。</p>
<div style="background: #eee; padding: .3em; font-size: 1.5em;">申请办法</div>
<p>1、发邮件到：lisf@turingbook.com。<br />
2、邮件主题：《JavaScript高级程序设计（第2版）》样章；邮件内容：您的Email地址。<br />
3、24小时内收到样章，先睹为快！</p>
<div style="border: 1px dashed #333; color: #555; padding: .5em;">备注：样章格式为PDF，托管在“Google文件”，可以在线查看（无须登录），也可以下载和打印。<span style="text-decoration: line-through;">希望在线查看PDF的朋友，请在邮件正文中注明“希望接收Google文件”字样，即可收到样章的链接（也可以下载）；否则，将收到PDF文件（*请确保有5M以上的空余邮箱空间）</span>。</div>
<div style="background: #eee; padding: .3em; font-size: 1.5em; margin-top: .5em;">样章列表（<a href="#contents">详细目录</a>）</div>
<p>第3章 基本概念<br />
第4章 变量、作用域及内存问题<br />
第5章 引用类型</p>
<div style="background: #eee; padding: .3em; font-size: 1.5em;">《JavaScript高级程序设计（第2版）》简介</div>
<p>本书是<a title="人民邮电出版社图灵公司" href="http://www.turingbook.com" target="_blank">人民邮电出版社图灵公司</a>引进出版的大畅销书、JavaScript权威著作《<a title="互动网：JavaScript高级程序设计(AJAX程序员必备)" href="http://www.china-pub.com/31282" target="_blank">JavaScript高级程序设计</a>》的最新升级版。《JavaScript高级程序设计》自2006年11月出版以来，已经累计销售逾30000册，而且至今仍然十分畅销。这一点可以通过<a title="北京新华书店店面销售数据：近期销售走势" href="http://www.xhsd.com.cn/books/views.asp?PLUCODE=711515209" target="_blank">北京新华文化发展有限公司（新华书店）近期的店面销售数据</a>看出来（大家可以自行比较一下其他畅销书的销量）。应该说，在Web 2.0革命爆发的同时，人民邮电出版社图灵公司引进出版的本书成就了计算机图书市场上难得一见的奇迹。</p>
<p>本书作者<a title="http://www.nczonline.net/" href="http://www.nczonline.net/" target="_blank">尼古拉斯·扎卡斯（Nicholas C. Zakas）</a>现为Yahoo!公司首席前端工程师，世界顶级Web技术专家。原书第1版曾被选为Yahoo!公司<a title="YUI" href="http://developer.yahoo.com/yui/" target="_blank">YUI（Yahoo! User Interface Library，Yahoo!用户界面库）</a>团队的内部培训教材。</p>
<p>2009年初，本书第2版面世（<a title="Professional JavaScript for Web developers, 2nd Edition" href="http://www.amazon.com/Professional-JavaScript-Developers-Wrox-Programmer/dp/047022780X/" target="_blank">《Professional JavaScript for Web developers, 2nd Edition》</a>）。新版本不仅篇幅由原来的600多页增加到800页，而且几乎全部更新、重写了上一版的内容，删除了上一版中与今天的职业需求无关的主题，新增了大量比上一版更有价值、更能反映JavaScript最新发展成果的内容。从颇具深度的JavaScript语言基础到作用域（链），从JavaScript引用类型到面向对象编程的最佳实践，从极其灵活的匿名函数到闭包的内部机制，从浏览器对象模型（BOM）到客户端检测，从文档对象模型（DOM）到基于事件的Web脚本编程，从错误处理到前端调试，从XML（E4X）到Ajax及JSON，从高级前端开发技术到前沿的客户端存储，从最佳编程实践到展望即将成为现实的API，直至JavaScript未来的发展。全书彻底涵盖了JavaScript技术的各个方面，几乎涉及到了Web前端开发的每一处细节。可以预见，这部著作一定会成为Web前端开发人员不可多得的又一部经典。</p>
<p>目前，《JavaScript高级程序设计（第2版）》的翻译工作已经进入后期阶段（全书22章，所剩不到5章）。而且，为确保新版及时上市与读者见面，出版社采取了与译者同步翻译、同步编辑审校的特别措施。新版本预计2010年上半年可以上市；当然，在确保出版品质的前提下一定会尽量往前赶！</p>
<p><a name="contents"></a></p>
<div style="background: #eee; padding: .3em; font-size: 1.5em;">样章详细目录</div>
<p>第3章	基本概念	1<br />
3.1	语法	1<br />
3.1.1	区分大小写	1<br />
3.1.2	标识符	1<br />
3.1.3	注释	2<br />
3.1.4	语句	2<br />
3.2	关键字和保留字	3<br />
3.3	变量	4<br />
3.4	数据类型	5<br />
3.4.1	typeof操作符	5<br />
3.4.2	Undefined类型	6<br />
3.4.3	Null类型	7<br />
3.4.4	Boolean类型	7<br />
3.4.5	Number类型	8<br />
3.4.6	String类型	14<br />
3.4.7	Object类型	16<br />
3.5	操作符	17<br />
3.5.1	一元操作符	17<br />
3.5.2	位操作符	20<br />
3.5.3	布尔操作符	26<br />
3.5.4	乘性操作符	29<br />
3.5.5	加性操作符	30<br />
3.5.6	关系操作符	32<br />
3.5.7	相等操作符	34<br />
3.5.8	条件操作符	35<br />
3.5.9	赋值操作符	36<br />
3.5.10	逗号操作符	36<br />
3.6	语句	37<br />
3.6.1	if语句	37<br />
3.6.2	do-while语句	38<br />
3.6.3	while语句	38<br />
3.6.4	for语句	38<br />
3.6.5	for-in语句	40<br />
3.6.6	label语句	40<br />
3.6.7	break和continue语句	41<br />
3.6.8	with语句	42<br />
3.6.9	switch语句	43<br />
3.7	函数	45<br />
3.7.1	理解参数	47<br />
3.7.2	没有重载	48<br />
3.8	小结	49</p>
<p>第4章	变量、作用域和内存问题	1<br />
4.1	基本类型和引用类型的值	1<br />
4.1.1	动态属性	2<br />
4.1.2	复制变量值	3<br />
4.1.3	传递参数	4<br />
4.1.4	检测类型	6<br />
4.2	执行环境及作用域	6<br />
4.2.1	延长作用域链	9<br />
4.2.2	没有块级作用域	10<br />
4.2.3	声明变量	10<br />
4.2.4	查询标识符	11<br />
4.3	垃圾收集	12<br />
4.3.1	标记清除	12<br />
4.3.2	引用计数	13<br />
4.3.3	性能问题	14<br />
4.3.4	管理内存	15<br />
4.4	小结	15</p>
<p>第5章	引用类型	1<br />
5.1	Object类型	1<br />
5.2	Array类型	3<br />
5.2.1	转换方法	6<br />
5.2.2	栈方法	7<br />
5.2.3	队列方法	8<br />
5.2.4	重排序方法	9<br />
5.2.5	操作方法	11<br />
5.3	Date类型	12<br />
5.3.1	继承的方法	14<br />
5.3.2	日期格式化方法	15<br />
5.3.3	日期/时间组件方法	15<br />
5.4	RegExp类型	17<br />
5.4.1	RegExp实例属性	19<br />
5.4.2	RegExp实例方法	19<br />
5.4.3	RegExp构造函数属性	21<br />
5.4.4	模式的局限性	23<br />
5.5	Function类型	23<br />
5.5.1	没有重载（深入理解）	25<br />
5.5.2	函数声明与函数表达式	25<br />
5.5.3	作为值的函数	26<br />
5.5.4	函数内部属性	27<br />
5.5.5	函数属性和方法	29<br />
5.6	基本包装类型	31<br />
5.6.1	Boolean类型	32<br />
5.6.2	Number类型	33<br />
5.6.3	String类型	35<br />
5.7	内置对象	42<br />
5.7.1	Global对象	43<br />
5.7.2	Math对象	46<br />
5.8	小结	49</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cn-cuckoo.com/2010/02/06/professional-javascript-developers-wrox-programmer-sample-chapter-1411.html/feed</wfw:commentRss>
		<slash:comments>44</slash:comments>
		</item>
		<item>
		<title>评判浏览器API好坏的标准是什么</title>
		<link>http://www.cn-cuckoo.com/2010/01/22/what-makes-a-good-browser-api-1391.html</link>
		<comments>http://www.cn-cuckoo.com/2010/01/22/what-makes-a-good-browser-api-1391.html#comments</comments>
		<pubDate>Fri, 22 Jan 2010 05:17:00 +0000</pubDate>
		<dc:creator>为之漫笔</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://www.cn-cuckoo.com/?p=1391</guid>
		<description><![CDATA[Original Post：What makes a good browser API? Nicholas C. Zakas，2009年11月24日 翻译完成：2010年1月22日，最后更新：2010年1月22日 上个月，我又参加了Mozilla公司组织的一次研讨会，这一次讨论的是Web数据库。虽然研讨会的议题很有意思，但我觉得会议期间大家对另一个问题的争论似乎更值得关注。争论中，与会者针对浏览器到底应该为JavaScript提供什么样的API分成两派。一派坚持认为原生的JavaScript API应该尽量保持低级化，然后由库开发者在低级API基础上再去构建更好用的接口。另外一派，也是我所在的阵营，则认为中级API才是大势所趋。没有人认为浏览器应该向开发人员提供高级API。所谓低级、中级、高级到底都是什么意思呢？ 低级API 低级API仅为提供基本功能而设计。由于只要能实现相应功能即可，因此这种API不需要很直观或者很好理解。有时候，低级API确实会给初级甚至中级开发人员造成理解上的困难。这样一来，借由人们频繁使用来发现相应API问题的机会就大为减少了。大家都会指望库开发者在这些低级API基础上实现直观、好用的API，以便于普通开发人员使用。doument.cookie就是说明低级API最好的一个例子。 作为JavaScript开发人员操作cookie的唯一接口，document.cookie可谓有史以来最难使用的一个API。关于cookie，我专门写过一篇文章，还探讨过它的安全性问题，其中都涉及到如何在JavaScript中使用它们；因此，这里只能算是一个简单的介绍了。要设置cookie，必须以正确的cookie格式来设置document.cookie属性，例如： document.cookie = &#8220;name=Nicholas; domain=nczonline.net; path=/; expires=Sat, 02 May 2009 23:38:25 GMT 要取得cookie，则需要读取document.cookie，返回的字符串是如下列所示的名值对格式： name1=value1; name2=value2; name3=value3; name4=value4 而为了得到想要的值，必须先从这个字符串中查找相应的名字，然后再解析出相应的值。 之所以把这种API归类为低级API，是因为其实现要求你必须先了解cookie的内部格式，然后才能使用它。实际上，document.cookie属性只是在简单地模仿Set-Cookie和Cookie这两个对开发人员不可见的HTTP首部。为了写cookie，必须要理解字符串的确切格式，这涉及到其中的名和值必须采用URI编码形式，而其他片段之间必须以一个分号和一个空格来分隔，此外还必须知道设置过期日期的正确日期格式。反过来也一样，在读cookie时，你同样需要知道返回的字符串是什么格式，然后才能从中解析出想要的数据。这就是所谓的“遇繁不简，遇简也不简”。一句话，这种API对于不了解cookie的人根本没有用。 如果大多数开发人员都不会直接使用某个API，你就可以说它是低级API。不用，是因为使用它们所需的知识储备（Cognitive Overhead）太多了。绝大多数开发人员在使用JavaScript读写cookie时，最终都会求诸于一个JavaScript库例如YUI中的Cookie工具（YUI2和YUI3），这些工具把那些令人讨厌的实现细节都隐藏起来了。 这正是那些低级API的支持者所愿意看到的：浏览器应该只提供基本功能，而基于这些功能开发易用API的任务应该交给开发人员社区。这些人支持低级API有一个主要的理由，即围绕基本功能可以实现任何层次的抽象，开发人员也会因此获得更多选择，从而更好地利用基本功能。 低级API的问题在于浪费时间。如果你创建了低级API，那结果就是潜在用户的数量会很少。至于什么时候能够出现好用的抽象工具，只能指望某一天这些用户中有（一个或几个）人会意识到确实有必要去做这件事，以便其他社区人员更好地利用该API。如果你想让新API尽快地被别人使用，你就会明白应该怎样去改进它，低级API根本不合适。 提示：大多数服务器端语言（如 ASP.NET、JSP、PHP）都提供了读写cookie的原生抽象，但JavaScript始终都没有。 高级API 这一争论的另一个极端是高级API。高级API设计出来就是为了让开发人员直接使用的，并且一般都非常直观。这种API不仅要考虑提供某种功能，而且还要提供使用相应功能的友好、易用的接口。高级API设计首先考虑的是开发人员的方便，因而通常需要对开发人员使用API的方式从理论上作出归纳。显然，这又是一个问题：谁能确切地知道某个人希望怎么去使用一个API呢？因此，在浏览器中提供原生的高级API几乎就是一个不可能完成的任务。 各式各样的JavaScript库就是高级API的典型例子。这些库都面向相同的浏览器，但为实现相同功能而提供的接口却差别很大。使用jQuery的方式与使用YUI截然不同；这是件好事，因为开发人员可以选择。可是，如果你告诉YUI开发人员必须使用jQuery语法写代码——因为只能使用一种语法；或者相反，会怎么样呢？相信对此提出抗议的开发人员一定会成群结队。强迫人们必须以某种方式开发是不幸之源。只有抽象，或者说只有随时都可以提高和降低抽象级别，才会让开发充满乐趣，也才能激励开发人员不断地创新。 高级API要求的知识储备非常低，因此开发人员无需了解太多就可以直接使用。但值得高兴的是，没有人认为浏览器应该提供高级AIP。大家都希望有所选择，都希望不同程度的抽象。 中级API 折衷方案是中级API。以我的观点来看，中级API是浏览器所应该研究和实现的。顾名思义，中级API处于低级和高级之间，兼具二者之长。所谓中级API，（我的定义）就是针对最常见的应用提供简单的接口，同时能够通过扩展实现更强大的操作和对不常见应用的支持。第一部分，常用的接口，是非常简单、无需抽象即可直接使用的。而不常用接口可以更复杂一些，甚至可以“让人摸不着头脑”，因为很少会有人用。 XMLHttpRequest是不错的中级API中最出色的例子。使用它最常见的情形就是发送一次GET请求，然后取得XML数据。实现这个过程的代码不多： var xhr = new XMLHttpRequest(); xhr.open(&#8220;get&#8221;, &#8220;/somexml&#8221;, true); [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: right;">Original Post：<a title="What makes a good browser API?" href="http://www.nczonline.net/blog/2009/11/24/what-makes-a-good-browser-api/" target="_blank">What makes a good browser API?</a><br />
<a title="NCZOnline" href="http://www.nczonline.net/" target="_blank">Nicholas C. Zakas</a>，2009年11月24日<br />
翻译完成：2010年1月22日，最后更新：2010年1月22日</p>
<p>上个月，我又参加了Mozilla公司组织的一次研讨会，这一次讨论的是Web数据库。虽然研讨会的议题很有意思，但我觉得会议期间大家对另一个问题的争论似乎更值得关注。争论中，与会者针对浏览器到底应该为JavaScript提供什么样的API分成两派。一派坚持认为原生的JavaScript API应该尽量保持低级化，然后由库开发者在低级API基础上再去构建更好用的接口。另外一派，也是我所在的阵营，则认为中级API才是大势所趋。没有人认为浏览器应该向开发人员提供高级API。所谓低级、中级、高级到底都是什么意思呢？</p>
<h2>低级API</h2>
<p>低级API仅为提供基本功能而设计。由于只要能实现相应功能即可，因此这种API不需要很直观或者很好理解。有时候，低级API确实会给初级甚至中级开发人员造成理解上的困难。这样一来，借由人们频繁使用来发现相应API问题的机会就大为减少了。大家都会指望库开发者在这些低级API基础上实现直观、好用的API，以便于普通开发人员使用。doument.cookie就是说明低级API最好的一个例子。</p>
<p>作为JavaScript开发人员操作cookie的唯一接口，document.cookie可谓有史以来最难使用的一个API。关于cookie，我专门写过<a title="HTTP cookies explained（HTTP Cookie详解）" href="http://www.nczonline.net/blog/2009/05/05/http-cookies-explained/" target="_blank">一篇文章</a>，还探讨过它的<a title="Cookies and security（Cookie与安全）" href="http://www.nczonline.net/blog/2009/05/12/cookies-and-security/" target="_blank">安全性问题</a>，其中都涉及到如何在JavaScript中使用它们；因此，这里只能算是一个简单的介绍了。要设置cookie，必须以正确的cookie格式来设置document.cookie属性，例如：<br />
<coolcode lang="javascript" linenum="off"><br />
document.cookie = &#8220;name=Nicholas; domain=nczonline.net; path=/; expires=Sat, 02 May 2009 23:38:25 GMT<br />
</coolcode><br />
要取得cookie，则需要读取document.cookie，返回的字符串是如下列所示的名值对格式：<br />
<coolcode lang="javascript" linenum="off"><br />
name1=value1; name2=value2; name3=value3; name4=value4<br />
</coolcode><br />
而为了得到想要的值，必须先从这个字符串中查找相应的名字，然后再解析出相应的值。</p>
<p>之所以把这种API归类为低级API，是因为其实现要求你必须先了解cookie的内部格式，然后才能使用它。实际上，document.cookie属性只是在简单地模仿Set-Cookie和Cookie这两个对开发人员不可见的HTTP首部。为了写cookie，必须要理解字符串的确切格式，这涉及到其中的名和值必须采用URI编码形式，而其他片段之间必须以一个分号和一个空格来分隔，此外还必须知道设置过期日期的正确日期格式。反过来也一样，在读cookie时，你同样需要知道返回的字符串是什么格式，然后才能从中解析出想要的数据。这就是所谓的“遇繁不简，遇简也不简”。一句话，这种API对于不了解cookie的人根本没有用。</p>
<p>如果大多数开发人员都不会直接使用某个API，你就可以说它是低级API。不用，是因为使用它们所需的知识储备（<a title="Cognitive Overhead" href="http://elab.eserver.org/hfl0098.html" target="_blank">Cognitive Overhead</a>）太多了。绝大多数开发人员在使用JavaScript读写cookie时，最终都会求诸于一个JavaScript库例如YUI中的Cookie工具（<a title="YUI2的Cookie工具" href="http://developer.yahoo.com/yui/2/cookie" target="_blank">YUI2</a>和<a title="YUI3的Cookie工具" href="http://developer.yahoo.com/yui/3/cookie" target="_blank">YUI3</a>），这些工具把那些令人讨厌的实现细节都隐藏起来了。</p>
<p>这正是那些低级API的支持者所愿意看到的：浏览器应该只提供基本功能，而基于这些功能开发易用API的任务应该交给开发人员社区。这些人支持低级API有一个主要的理由，即围绕基本功能可以实现任何层次的抽象，开发人员也会因此获得更多选择，从而更好地利用基本功能。</p>
<p>低级API的问题在于浪费时间。如果你创建了低级API，那结果就是潜在用户的数量会很少。至于什么时候能够出现好用的抽象工具，只能指望某一天这些用户中有（一个或几个）人会意识到确实有必要去做这件事，以便其他社区人员更好地利用该API。如果你想让新API尽快地被别人使用，你就会明白应该怎样去改进它，低级API根本不合适。</p>
<p><strong>提示</strong>：大多数服务器端语言（如 <a title="ASP.NET对Cookie的支持" href="http://www.codetoad.com/ASP.NET/cookies.asp" target="_blank">ASP.NET</a>、<a title="JSP对Cookie的支持" href="http://www.roseindia.net/jsp/jspcookies.shtml" target="_blank">JSP</a>、<a title="PHP对Cookie的支持" href="http://www.w3schools.com/PHP/php_cookies.asp" target="_blank">PHP</a>）都提供了读写cookie的原生抽象，但JavaScript始终都没有。</p>
<h2>高级API</h2>
<p>这一争论的另一个极端是高级API。高级API设计出来就是为了让开发人员直接使用的，并且一般都非常直观。这种API不仅要考虑提供某种功能，而且还要提供使用相应功能的友好、易用的接口。高级API设计首先考虑的是开发人员的方便，因而通常需要对开发人员使用API的方式从理论上作出归纳。显然，这又是一个问题：谁能确切地知道某个人希望怎么去使用一个API呢？因此，在浏览器中提供原生的高级API几乎就是一个不可能完成的任务。</p>
<p>各式各样的JavaScript库就是高级API的典型例子。这些库都面向相同的浏览器，但为实现相同功能而提供的接口却差别很大。使用jQuery的方式与使用YUI截然不同；这是件好事，因为开发人员可以选择。可是，如果你告诉YUI开发人员必须使用jQuery语法写代码——因为只能使用一种语法；或者相反，会怎么样呢？相信对此提出抗议的开发人员一定会成群结队。强迫人们必须以某种方式开发是不幸之源。只有抽象，或者说只有随时都可以提高和降低抽象级别，才会让开发充满乐趣，也才能激励开发人员不断地创新。</p>
<p>高级API要求的知识储备非常低，因此开发人员无需了解太多就可以直接使用。但值得高兴的是，没有人认为浏览器应该提供高级AIP。大家都希望有所选择，都希望不同程度的抽象。<span id="more-1391"></span></p>
<h2>中级API</h2>
<p>折衷方案是中级API。以我的观点来看，中级API是浏览器所应该研究和实现的。顾名思义，中级API处于低级和高级之间，兼具二者之长。所谓中级API，（我的定义）就是针对最常见的应用提供简单的接口，同时能够通过扩展实现更强大的操作和对不常见应用的支持。第一部分，常用的接口，是非常简单、无需抽象即可直接使用的。而不常用接口可以更复杂一些，甚至可以“让人摸不着头脑”，因为很少会有人用。</p>
<p>XMLHttpRequest是不错的中级API中最出色的例子。使用它最常见的情形就是发送一次GET请求，然后取得XML数据。实现这个过程的代码不多：<br />
<coolcode lang="javascript" linenum="off"><br />
var xhr = new XMLHttpRequest();<br />
xhr.open(&#8220;get&#8221;, &#8220;/somexml&#8221;, true);<br />
xhr.onreadystatechange = function(){<br />
    if (xhr.readyState == 4){<br />
        if (xhr.status == 200){<br />
            process(xhr.responseXML.getElementsByTagName(&#8220;item&#8221;));<br />
        }<br />
    }<br />
};<br />
xhr.send(null);<br />
</coolcode><br />
虽然有人会说onreadystatechange这个事件处理程序看起来有点麻烦，但实际上，你要做的不过是检查一点信息，以确定是否接收到了正确的数据。可是，所有必需的信息都已经各就各位了，而且也已经转换成了方便访问的格式：HTTP状态就在那摆着，而XML也已经转换成了DOM格式。为了给你提供这些数据，API已经做了不少的工作了。</p>
<p>另一种不太常见的用法就是在URL中包含提交的表单数据。虽然代码难看点，但仍然可以接受：<br />
<coolcode lang="javascript" linenum="off"><br />
var xhr = new XMLHttpRequest();<br />
xhr.open(&#8220;post&#8221;, &#8220;/add&#8221;, true);<br />
xhr.setRequestHeader(&#8220;Content-type&#8221;, &#8220;application/x-www-form-urlencoded&#8221;);<br />
xhr.onreadystatechange = function(){<br />
    if (xhr.readyState == 4){<br />
        if (xhr.status == 200){<br />
            signalComplete();<br />
        }<br />
    }<br />
};<br />
xhr.send(encodeURIComponent(name) + &#8220;=&#8221; + encodeURIComponent(value));<br />
</coolcode><br />
除此之外，你当然还可以把XMLHttpRequest对象用于更复杂的处理中，例如Comet。问题的关键在于，它在常用情形下很简单，而且还能轻易地支持更复杂、更不常见的用例。这样一来，JavaScript库也容易在后台构建一个比较好用的接口，帮我们处理那些复杂应用下的琐碎细节。尽管每个JavaScript库在如何发起Ajax通信方面各有各的方式，但XMLHttpRequest接口的设计能够很好地适应所有方式。</p>
<p><strong>注意</strong>：有些人认为XMLHttpRequest也属于低级API。我承认它不是最清晰的API，但在常见用例中它确实非常简便易行。不要忘了，最初在设计这个对象的时候，常见用例就是从服务器上取得XML数据。从那个时候到现在，常见用例已经变了，但人们照样还在使用同一个API。在我看来，这恰恰表明了它是一个不可多得的中级API。</p>
<h2>总结</h2>
<p>我主张浏览器应该原生提供中级API，这样才能自如地应对常见用例，同时还可以为不常见的用例留下扩展的空间。API的抽象程度太低，不利于广泛流传，更不容易引起开发社区的重视；API的抽象程度太高，由于限制的用例太专，人们要么能用，要么根本就用不了。目前来看，较新的API似乎有低级化的倾向，如此一来，开发人员在实际使用它们之前，往往需要有第三方来实现一些必要的抽象。我希望能够阻止这种趋势，好让常见用例实现起来更简单，以便人们能够立即使用它们，同时还可以对它们加以扩展。而中级API能够同时满足这两个条件。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cn-cuckoo.com/2010/01/22/what-makes-a-good-browser-api-1391.html/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>《JavaScript高级程序设计（第2版）》序</title>
		<link>http://www.cn-cuckoo.com/2010/01/17/professional-javascript-for-web-developers-2nd-edition-foreword-1373.html</link>
		<comments>http://www.cn-cuckoo.com/2010/01/17/professional-javascript-for-web-developers-2nd-edition-foreword-1373.html#comments</comments>
		<pubDate>Sun, 17 Jan 2010 06:14:54 +0000</pubDate>
		<dc:creator>为之漫笔</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[好书]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://www.cn-cuckoo.com/?p=1373</guid>
		<description><![CDATA[从诞生至今的大部分时间里，焦虑、抨击、蔑视和误解一直与JavaScript如影随形。JavaScript刚刚问世那几年，很多“严肃的程序员”都认为它不够严肃。 相比之下，.COM泡沫时期加入Web开发行列的许多文科生，则普遍觉得JavaScript深不可测、晦涩难懂。就算那些耐力和韧性俱佳者能够把JavaScript琢磨得很透，但仍然摆脱不掉竞争性浏览器提供的不同实现给他们带来的麻烦。凡此种种，最终导致粗制滥造的脚本越来越多。另一方面，拜Web前端代码的无比开放性所赐，各种坏习惯不断从一个站点被粘贴进另一个站点的源代码中。那些实现活该臭名昭著，可是，JavaScript这门语言也因此被严重拖累，背上了不该有的坏名声了。 2001年前后（随着Internet Explorer 6的发布），浏览器实现已经大为改进，Web开发实践也开始得到改善，呈现出了二者水乳交融的局面。作为Ajax核心的XMLHttpRequest对象正慢慢地为人们所发现，一种新的桌面风格的用户交互模式出现在浏览器中。允许JavaScript操作Web文档结构和内容的DOM API已经定型。而CSS，不管人们如何曲解或者无视它，也无论浏览器开发商怎样丧心病狂地实现它，都已经成长得足够茁壮，它的美妙和反应敏捷令它能够与新的Web交互能力配合无间。最终，JavaScript一扫颓势，变得令人惊诧、让人兴奋、使人敬畏。想想2004年第一次使用Google Maps时的情景吧，那种感觉你或许还记忆犹新。 Google Maps是新兴应用程序的典型代表。这类浏览器编程与后端编程并重的应用程序，不禁令人对Web浏览器窗口中那块“画布”的未来浮想联翩。（除Google Maps之外，早在2003年就基于网页邮件客户端提供类似Outlook功能的Oddpost，也是这类应用程序的一个了不起的先驱。）随着这类应用程序如雨后春笋般大量涌现，以及支持它们的浏览器的市场份额不断攀升，一个Web应用全面复兴的时代真的到来了。“Web 2.0”诞生了，Ajax也成了“IT”技术。Web似乎在一夜之间脱胎换骨，重新激发起了人们的兴趣。而JavaScript作为唯一的Web编程语言，也变得更有意思了。 有意思，但用好它却不简单。JavaScript以及在DOM和BOM中为其定义的API不一致的实现，给跨浏览器编程造成了比原本大得多的困难。前端设计行业还远未成熟。大学教学计划并没有（至今仍没有）做出相应的调整，以满足相关的培训要求。 到2004年底，JavaScript无疑已经成为最重要的编程语言。但从学术角度看，它依然不具备进入一类学科的资格。Web虽然已经翻开了新的一页，但在培养足够的知识全面、训练有素的人才方面，我们依然面临着严峻的挑战。 为此，很多技术作者挺身而出，撰写了不少有关JavaScript的图书。几年来，这类书虽然也出了不下几十本，但总体来说仍然不尽如人意。其中有的在推销与落伍的浏览器有关的技术，有的则在卖弄容易剪贴但却不好扩展和维护的技术。让人想不通的是，许多JavaScript图书让人觉得作者好象并不真正喜欢JavaScript，或者他们不认为读者应该喜欢它，再或者他们根本不相信读者能够完全理解JavaScript。 2005年，Nicholas C. Zakas这本书的第一版面世，为前端工程领域奉献了一本真正的好书。当时，我和雅虎的同事们正在创建YUI（Yahoo! User Interface Library，Yahoo!用户界面库），打算将其作为公司前端工程的基础，同时也借以推广我们这门新学问的最佳实践。每到周五，我们就聚到一间教室里讨论前端工程，也向大家讲解JavaScript、CSS以及在浏览器中创建Web应用程序的知识。我们从已出版的高级JavaScript及DOM脚本编程方面的图书中认真挑选了几本，想让新工程师通过它们掌握如何构建耐用、基于标准且容易维护的Web应用程序。Zakas的书一出版，马上就被选为我们的JavaScript内部培训课本。 从那时起我们就一直使用他的书。我们一致认为这本书太有用了，于是就跟Zakas商量，让他加入雅虎帮我们建立公司的前端工程社区。 Zakas在书中传达的理念与众不同——JavaScript既需要严肃认真地对待，但也是完全可以理解和掌握的。如果你是个程序员，这本书会告诉你JavaScript与各种编程语言的关系，以及如何运用你已经习以为常的各种编程模式。你可以理解JavaScript的继承机制及其固有的动态特性（虽不合传统，但却十分自由十分强大），可以从Zakas这位尊重和理解JavaScript的同道那里学会欣赏JavaScript这门语言。 如果你曾经是一名文科生，在网络泡沫时期步入了这个行业，至今也没有转行，而且想要弥补自己在JavaScript方面的不足，你会发现Zakas是一位难得的良师益友。他可以帮你实现从“会做”到“做好”的转变。他能让你认真地理解这门严肃的学问。最重要的是，他不会让你先入为主地产生对这门语言应该理解多深的想法。相反，通过他严肃、耐心、通俗易懂的讲解，你自然而然地会对这门语言有同样深刻的认识。 本书是经过扩展、更新和改进后的第二版，删除了上一版中与今天的职业需求无关的主题，并用我们在2005年至2008年学习的新知识更新了剩余的内容。这几年是JavaScript发展的重要时期，Zakas则始终位于最前沿孜孜不倦地学习这些新知识。他这些年一直在致力于建造新一代最流行的Web个人门户（My Yahoo!），以及开发Web上最受欢迎的站点（Yahoo!主页）的新版本。Zakas以他作为老师和作者的独特视角，筛选出由这些超复杂、超大型应用程序磨砺出的经验，并将这些经验融入到了本书的字里行间。 他给出的解决方案远远超出了一本好书的范畴，只有每天都与代码同呼吸共命运的人，才有可能与读者分享如此具有实用价值的知识。 说实话，本书新版的面世对我和各位读者而言真是个莫大的喜讯。因为它的内容比上一版更有价值、更能反映JavaScript最新的发展成果，因此也更加令人不可错过。 埃里克·米拉利亚（Eric Miraglia） YUI高级技术经理 哲学博士 于加利福尼亚州森尼维耳市 Nicholas C. Zakas，Yahoo!主页首席前端工程师，个人网站www.nczonline.net。《Professional JavaScript for Web developers, 2nd Edition》作者。最新专著《High Performance JavaScript》（O&#8217;Reilly Media; 1 edition,March 15, 2010）。 本站相关译文 Nicholas C. Zakas如何面试前端工程师 如何通过Nicholas C. Zakas的面试 [...]]]></description>
			<content:encoded><![CDATA[<h1><img class="alignleft colorbox-1373" style="margin: 0 1em 1em 0;" src="http://yuiblog.com/assets//miraglia-20081125-141210.jpg" alt="埃里克·米拉利亚（Eric Miraglia）" width="191" height="262" /></h1>
<p>从诞生至今的大部分时间里，焦虑、抨击、蔑视和误解一直与JavaScript如影随形。JavaScript刚刚问世那几年，很多“严肃的程序员”都认为它不够严肃。</p>
<p>相比之下，.COM泡沫时期加入Web开发行列的许多文科生，则普遍觉得JavaScript深不可测、晦涩难懂。就算那些耐力和韧性俱佳者能够把JavaScript琢磨得很透，但仍然摆脱不掉竞争性浏览器提供的不同实现给他们带来的麻烦。凡此种种，最终导致粗制滥造的脚本越来越多。另一方面，拜Web前端代码的无比开放性所赐，各种坏习惯不断从一个站点被粘贴进另一个站点的源代码中。那些实现活该臭名昭著，可是，JavaScript这门语言也因此被严重拖累，背上了不该有的坏名声了。</p>
<p>2001年前后（随着Internet Explorer 6的发布），浏览器实现已经大为改进，Web开发实践也开始得到改善，呈现出了二者水乳交融的局面。作为Ajax核心的XMLHttpRequest对象正慢慢地为人们所发现，一种新的桌面风格的用户交互模式出现在浏览器中。允许JavaScript操作Web文档结构和内容的DOM API已经定型。而CSS，不管人们如何曲解或者无视它，也无论浏览器开发商怎样丧心病狂地实现它，都已经成长得足够茁壮，它的美妙和反应敏捷令它能够与新的Web交互能力配合无间。最终，JavaScript一扫颓势，变得令人惊诧、让人兴奋、使人敬畏。想想2004年第一次使用Google Maps时的情景吧，那种感觉你或许还记忆犹新。</p>
<p>Google Maps是新兴应用程序的典型代表。这类浏览器编程与后端编程并重的应用程序，不禁令人对Web浏览器窗口中那块“画布”的未来浮想联翩。（除Google Maps之外，早在2003年就基于网页邮件客户端提供类似Outlook功能的Oddpost，也是这类应用程序的一个了不起的先驱。）随着这类应用程序如雨后春笋般大量涌现，以及支持它们的浏览器的市场份额不断攀升，一个Web应用全面复兴的时代真的到来了。“Web 2.0”诞生了，Ajax也成了“IT”技术。Web似乎在一夜之间脱胎换骨，重新激发起了人们的兴趣。而JavaScript作为唯一的Web编程语言，也变得更有意思了。</p>
<p>有意思，但用好它却不简单。JavaScript以及在DOM和BOM中为其定义的API不一致的实现，给跨浏览器编程造成了比原本大得多的困难。前端设计行业还远未成熟。大学教学计划并没有（至今仍没有）做出相应的调整，以满足相关的培训要求。</p>
<p>到2004年底，JavaScript无疑已经成为最重要的编程语言。但从学术角度看，它依然不具备进入一类学科的资格。Web虽然已经翻开了新的一页，但在培养足够的知识全面、训练有素的人才方面，我们依然面临着严峻的挑战。</p>
<p>为此，很多技术作者挺身而出，撰写了不少有关JavaScript的图书。几年来，这类书虽然也出了不下几十本，但总体来说仍然不尽如人意。其中有的在推销与落伍的浏览器有关的技术，有的则在卖弄容易剪贴但却不好扩展和维护的技术。让人想不通的是，许多JavaScript图书让人觉得作者好象并不真正喜欢JavaScript，或者他们不认为读者应该喜欢它，再或者他们根本不相信读者能够完全理解JavaScript。</p>
<p>2005年，Nicholas C. Zakas这本书的第一版面世，为前端工程领域奉献了一本真正的好书。当时，我和雅虎的同事们正在创建YUI（Yahoo! User Interface Library，Yahoo!用户界面库），打算将其作为公司前端工程的基础，同时也借以推广我们这门新学问的最佳实践。每到周五，我们就聚到一间教室里讨论前端工程，也向大家讲解JavaScript、CSS以及在浏览器中创建Web应用程序的知识。我们从已出版的高级JavaScript及DOM脚本编程方面的图书中认真挑选了几本，想让新工程师通过它们掌握如何构建耐用、基于标准且容易维护的Web应用程序。Zakas的书一出版，马上就被选为我们的JavaScript内部培训课本。</p>
<p>从那时起我们就一直使用他的书。我们一致认为这本书太有用了，于是就跟Zakas商量，让他加入雅虎帮我们建立公司的前端工程社区。</p>
<p>Zakas在书中传达的理念与众不同——JavaScript既需要严肃认真地对待，但也是完全可以理解和掌握的。如果你是个程序员，这本书会告诉你JavaScript与各种编程语言的关系，以及如何运用你已经习以为常的各种编程模式。你可以理解JavaScript的继承机制及其固有的动态特性（虽不合传统，但却十分自由十分强大），可以从Zakas这位尊重和理解JavaScript的同道那里学会欣赏JavaScript这门语言。</p>
<p>如果你曾经是一名文科生，在网络泡沫时期步入了这个行业，至今也没有转行，而且想要弥补自己在JavaScript方面的不足，你会发现Zakas是一位难得的良师益友。他可以帮你实现从“会做”到“做好”的转变。他能让你认真地理解这门严肃的学问。最重要的是，他不会让你先入为主地产生对这门语言应该理解多深的想法。相反，通过他严肃、耐心、通俗易懂的讲解，你自然而然地会对这门语言有同样深刻的认识。</p>
<p>本书是经过扩展、更新和改进后的第二版，删除了上一版中与今天的职业需求无关的主题，并用我们在2005年至2008年学习的新知识更新了剩余的内容。这几年是JavaScript发展的重要时期，Zakas则始终位于最前沿孜孜不倦地学习这些新知识。他这些年一直在致力于建造新一代最流行的Web个人门户（My Yahoo!），以及开发Web上最受欢迎的站点（Yahoo!主页）的新版本。Zakas以他作为老师和作者的独特视角，筛选出由这些超复杂、超大型应用程序磨砺出的经验，并将这些经验融入到了本书的字里行间。</p>
<p>他给出的解决方案远远超出了一本好书的范畴，只有每天都与代码同呼吸共命运的人，才有可能与读者分享如此具有实用价值的知识。</p>
<p>说实话，本书新版的面世对我和各位读者而言真是个莫大的喜讯。因为它的内容比上一版更有价值、更能反映JavaScript最新的发展成果，因此也更加令人不可错过。</p>
<p style="text-align: right;">埃里克·米拉利亚（Eric Miraglia）<br />
YUI高级技术经理 哲学博士<br />
于加利福尼亚州森尼维耳市</p>
<div style="padding: 1px 10px; background: #eee;">
<p><img class="alignleft colorbox-1373" style="margin: 0 1em 1em 0;" src="http://www.therichwebexperience.com/s/images/bio/1692_Zakas_medium.jpg" alt="Nicholas C. Zakas，Yahoo!主页首席前端工程师" width="129" height="170" />Nicholas C. Zakas，Yahoo!主页首席前端工程师，个人网站<a title="Nicholas C. Zakas，Yahoo!主页首席前端工程师，个人网站www.nczonline.net。" href="http://www.nczonline.net">www.nczonline.net</a>。《<a title="http://www.amazon.com/Professional-JavaScript-Developers-Wrox-Programmer/dp/047022780X/" href="http://www.amazon.com/Professional-JavaScript-Developers-Wrox-Programmer/dp/047022780X/" target="_blank">Professional JavaScript for Web developers, 2nd Edition</a>》作者。最新专著《<a title="http://www.amazon.com/High-Performance-JavaScript-Zakas-Nicholas/dp/059680279" href="http://www.amazon.com/High-Performance-JavaScript-Zakas-Nicholas/dp/059680279" target="_blank">High Performance JavaScript</a>》（O&#8217;Reilly Media; 1 edition,March 15, 2010）。</p>
<div style="text-align: right;">
<h4>本站相关译文</h4>
<ul>
<li><a title="Nicholas C. Zakas如何面试前端工程师" href="http://www.cn-cuckoo.com/2010/01/08/how-nicholas-c-zakas-interviewing-the-front-end-engineer-1332.html" target="_blank">Nicholas C. Zakas如何面试前端工程师</a></li>
<li><a title="如何通过Nicholas C. Zakas的面试" href="http://www.cn-cuckoo.com/2010/01/09/surviving-an-interview-with-nicholas-c-zakas-1346.html" target="_blank">如何通过Nicholas C. Zakas的面试</a></li>
<li><a title="Nicholas C. Zakas谈怎样才能成为优秀的前端工程师" href="http://www.cn-cuckoo.com/2010/01/10/nicholas-c-zakas-talk-about-what-makes-a-good-front-end-engineer-1356.html" target="_blank">Nicholas C. Zakas谈怎样才能成为优秀的前端工程师</a></li>
</ul>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.cn-cuckoo.com/2010/01/17/professional-javascript-for-web-developers-2nd-edition-foreword-1373.html/feed</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
		<item>
		<title>Nicholas C. Zakas谈怎样才能成为优秀的前端工程师</title>
		<link>http://www.cn-cuckoo.com/2010/01/10/nicholas-c-zakas-talk-about-what-makes-a-good-front-end-engineer-1356.html</link>
		<comments>http://www.cn-cuckoo.com/2010/01/10/nicholas-c-zakas-talk-about-what-makes-a-good-front-end-engineer-1356.html#comments</comments>
		<pubDate>Sun, 10 Jan 2010 03:01:06 +0000</pubDate>
		<dc:creator>为之漫笔</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://www.cn-cuckoo.com/?p=1356</guid>
		<description><![CDATA[Original Post：What makes a good front end engineer? Nicholas C. Zakas，2007年8月15日 翻译完成：2010年1月10日，最后更新：2010年1月10日 昨天，我负责了Yahoo!公司组织的一次面试活动，感触颇深的是其中的应聘者提问环节。我得说自己对应聘者们提出的大多数问题都相当失望。我希望听到一些对在Yahoo！工作充满激情的问题。在昨天的应聘者中，只有一个人的问题是我认为最好的，那个人问我：“你觉得怎么才能成为优秀的前端工程师？”我觉得很有必要把这个问题从面试房间里拿出来讨论一下。 首先，前端工程师必须得掌握HTML、CSS和JavaScript。只懂其中一个或两个还不行，你必须对这三门语言都很熟悉。也不是说必须对这三门语言都非常精通，但你至少要能够运用它们完成大多数任务，而无需频繁地寻求别人的帮助。 优秀的前端工程师应该具备快速学习能力。推动Web发展的技术并不是静止不动的，没错吧？我甚至可以说这些技术几乎每天都在变化，如果没有快速学习能力，你就跟不上Web发展的步伐。你必须不断提升自己，不断学习新技术、新模式；仅仅依靠今天的知识无法适应未来。Web的明天与今天必将有天壤之别，而你的工作就是要搞清楚如何通过自己的Web应用程序来体现这种翻天覆地的变化。 计算机科学这个大门类下面的许多分支在人们眼中实际上都不外乎科学。但是，我们所说的前端不是什么科学，而是艺术。艺术家不仅要掌握谋生的技术，还要懂得如何运用。对同一个问题的解决方案在这种情况适用，在另一种情况下可能就不适用。对Web应用程序的前端而言，解决同一问题的方案经常会有很多。没有哪个方案是错的，但其中确实有一些是更合适的。优秀的前端工程师应该知道在什么情况下使用哪种方案更合适，而在什么情况下应该重新选择。 优秀的前端工程师需要具备良好的沟通能力，因为你的工作与很多人的工作息息相关。在任何情况下，前端工程师至少都要满足下列四类客户的需求。 产品经理——这些是负责策划应用程序的一群人。他们能够想象出怎样通过应用程序来满足用户需求，以及怎样通过他们设计的模式赚到钱（但愿如此）。一般来说，这些人追求的是丰富的功能。 UI设计师——这些人负责应用程序的视觉设计和交互模拟。他们关心的是用户对什么敏感、交互的一贯性以及整体的好用性。他们热衷于流畅靓丽但并不容易实现的用户界面。 项目经理——这些人负责实际地运行和维护应用程序。项目管理的主要关注点，无外乎正常运行时间（uptime）——应用程序始终正常可用的时间、性能和截止日期。项目经理追求的目标往往是尽量保持事情的简单化，以及不在升级更新时引入新问题。 最终用户——当然是应用程序的主要消费者。尽管我们不会经常与最终用户打交道，但他们的反馈意见至关重要；没人想用的应用程序毫无价值。最终用户要求最多的就是对个人有用的功能，以及竞争性产品所具备的功能。 那么，前端工程师应该最关注哪些人的意见呢？答案是所有这四类人。优秀的前端工程师必须知道如何平衡这四类人的需求和预期，然后在此基础上拿出最佳解决方案。由于前端工程师处于与这四类人沟通的交汇点上，因此其沟通能力的重要性不言而喻。如果一个非常酷的新功能因为会影响前端性能，必须删繁就简，你怎么跟产品经理解释？再比如，假设某个设计如果不改回原方案可能会给应用程序造成负面影响，你怎么才能说服UI设计师？作为前端工程师，你必须了解每一类人的想法从何而来，必须能拿出所有各方都能接受的解决方案。从某种意义上说，优秀的前端工程师就像是一位大使，需要时刻抱着外交官的心态来应对每一天的工作。 我告诫新来的前端工程师最多的一句话，就是不要在没有作出评估之前就随便接受某项任务。你必须始终记住，一定先搞清楚别人到底想让你干什么，不能简单地接受“这个功能有问题”之类的大概其的说法。而且，你还要确切地知道这个功能或设计的真正意图何在。“加一个按钮”之类的任务并不总意味着你最后会加一个按钮。还可能意味着你会找产品经理，问一问这个按钮有什么用处，然后再找UI设计师一块探讨按钮是不是最佳的交互手段。要成为优秀的前端工程师，这种沟通至关重要。 无论从哪个方面讲，我都觉得前端工程师是计算机科学职业领域中最复杂的一个工种。绝大多数传统的编程思想已经不适用了，为了在多种平台中使用，多种技术都借鉴了大量软科学的知识和理念。成为优秀前端工程师所要具备的专业技术，涉及到广阔而复杂的领域，这些领域又会因为你最终必须服务的各方的介入而变得更加复杂。专业技术可能会引领你进入成为前端工程师的大门，但只有运用该技术创造的应用程序以及你跟他人并肩协同的能力，才会真正让你变得优秀。 延伸阅读 Nicholas C. Zakas如何面试前端工程师 如何通过Nicholas C. Zakas的面试 Nicholas C. Zakas的书]]></description>
			<content:encoded><![CDATA[<p style="text-align: right;">Original Post：<a title="What makes a good front end engineer?" href="http://www.nczonline.net/blog/2007/08/15/what-makes-a-good-front-end-engineer/" target="_blank">What makes a good front end engineer?<br />
</a><a title="NCZOnline" href="http://www.nczonline.net/" target="_blank">Nicholas C. Zakas</a>，2007年8月15日<br />
翻译完成：2010年1月10日，最后更新：2010年1月10日</p>
<p>昨天，我负责了Yahoo!公司组织的一次面试活动，感触颇深的是其中的应聘者提问环节。我得说自己对应聘者们提出的大多数问题都相当失望。我希望听到一些对在Yahoo！工作充满激情的问题。在昨天的应聘者中，只有一个人的问题是我认为最好的，那个人问我：“你觉得怎么才能成为优秀的前端工程师？”我觉得很有必要把这个问题从面试房间里拿出来讨论一下。</p>
<p>首先，前端工程师必须得掌握HTML、CSS和JavaScript。只懂其中一个或两个还不行，你必须对这三门语言都很熟悉。也不是说必须对这三门语言都非常精通，但你至少要能够运用它们完成大多数任务，而无需频繁地寻求别人的帮助。</p>
<p>优秀的前端工程师应该具备快速学习能力。推动Web发展的技术并不是静止不动的，没错吧？我甚至可以说这些技术几乎每天都在变化，如果没有快速学习能力，你就跟不上Web发展的步伐。你必须不断提升自己，不断学习新技术、新模式；仅仅依靠今天的知识无法适应未来。Web的明天与今天必将有天壤之别，而你的工作就是要搞清楚如何通过自己的Web应用程序来体现这种翻天覆地的变化。</p>
<p>计算机科学这个大门类下面的许多分支在人们眼中实际上都不外乎科学。但是，我们所说的前端不是什么科学，而是艺术。艺术家不仅要掌握谋生的技术，还要懂得如何运用。对同一个问题的解决方案在这种情况适用，在另一种情况下可能就不适用。对Web应用程序的前端而言，解决同一问题的方案经常会有很多。没有哪个方案是错的，但其中确实有一些是更合适的。优秀的前端工程师应该知道在什么情况下使用哪种方案更合适，而在什么情况下应该重新选择。</p>
<p>优秀的前端工程师需要具备良好的沟通能力，因为你的工作与很多人的工作息息相关。在任何情况下，前端工程师至少都要满足下列四类客户的需求。</p>
<ol>
<li><strong>产品经理</strong>——这些是负责策划应用程序的一群人。他们能够想象出怎样通过应用程序来满足用户需求，以及怎样通过他们设计的模式赚到钱（但愿如此）。一般来说，这些人追求的是丰富的功能。</li>
<li><strong>UI设计师</strong>——这些人负责应用程序的视觉设计和交互模拟。他们关心的是用户对什么敏感、交互的一贯性以及整体的好用性。他们热衷于流畅靓丽但并不容易实现的用户界面。</li>
<li><strong>项目经理</strong>——这些人负责实际地运行和维护应用程序。项目管理的主要关注点，无外乎正常运行时间（uptime）——应用程序始终正常可用的时间、性能和截止日期。项目经理追求的目标往往是尽量保持事情的简单化，以及不在升级更新时引入新问题。</li>
<li><strong>最终用户</strong>——当然是应用程序的主要消费者。尽管我们不会经常与最终用户打交道，但他们的反馈意见至关重要；没人想用的应用程序毫无价值。最终用户要求最多的就是对个人有用的功能，以及竞争性产品所具备的功能。</li>
</ol>
<p>那么，前端工程师应该最关注哪些人的意见呢？答案是所有这四类人。优秀的前端工程师必须知道如何平衡这四类人的需求和预期，然后在此基础上拿出最佳解决方案。由于前端工程师处于与这四类人沟通的交汇点上，因此其沟通能力的重要性不言而喻。如果一个非常酷的新功能因为会影响前端性能，必须删繁就简，你怎么跟产品经理解释？再比如，假设某个设计如果不改回原方案可能会给应用程序造成负面影响，你怎么才能说服UI设计师？作为前端工程师，你必须了解每一类人的想法从何而来，必须能拿出所有各方都能接受的解决方案。从某种意义上说，优秀的前端工程师就像是一位大使，需要时刻抱着外交官的心态来应对每一天的工作。</p>
<p>我告诫新来的前端工程师最多的一句话，就是不要在没有作出评估之前就随便接受某项任务。你必须始终记住，一定先搞清楚别人到底想让你干什么，不能简单地接受“这个功能有问题”之类的大概其的说法。而且，你还要确切地知道这个功能或设计的真正意图何在。“加一个按钮”之类的任务并不总意味着你最后会加一个按钮。还可能意味着你会找产品经理，问一问这个按钮有什么用处，然后再找UI设计师一块探讨按钮是不是最佳的交互手段。要成为优秀的前端工程师，这种沟通至关重要。</p>
<p>无论从哪个方面讲，我都觉得前端工程师是计算机科学职业领域中最复杂的一个工种。绝大多数传统的编程思想已经不适用了，为了在多种平台中使用，多种技术都借鉴了大量软科学的知识和理念。成为优秀前端工程师所要具备的专业技术，涉及到广阔而复杂的领域，这些领域又会因为你最终必须服务的各方的介入而变得更加复杂。专业技术可能会引领你进入成为前端工程师的大门，但只有运用该技术创造的应用程序以及你跟他人并肩协同的能力，才会真正让你变得优秀。</p>
<p><strong>延伸阅读</strong></p>
<ul>
<li><a title="Nicholas C. Zakas如何面试前端工程师" href="http://www.cn-cuckoo.com/2010/01/08/how-nicholas-c-zakas-interviewing-the-front-end-engineer-1332.html" target="_blank">Nicholas C. Zakas如何面试前端工程师</a></li>
<li><a title="如何通过Nicholas C. Zakas的面试" href="http://www.cn-cuckoo.com/2010/01/09/surviving-an-interview-with-nicholas-c-zakas-1346.html" target="_blank">如何通过Nicholas C. Zakas的面试</a></li>
</ul>
<div style="margin-top: 1em;">
<p><strong>Nicholas C. Zakas的书</strong></p>
<table style="margin: 0; padding: 0; border: 0;">
<tbody>
<tr>
<td><a href="http://www.amazon.com/gp/product/059680279X?ie=UTF8&amp;tag=nczonline-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=059680279X"><img class="colorbox-1356"  src="http://i764.photobucket.com/albums/xx289/nzakas/nczonline/hpjs.png" alt="" width="100" height="126" /></a></td>
<td><a href="http://www.amazon.com/gp/product/047022780X?ie=UTF8&amp;tag=nczonline-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=047022780X"><img class="colorbox-1356"  src="http://i764.photobucket.com/albums/xx289/nzakas/nczonline/pro_js_2e.png" alt="Professional JavaScript for Web Developers, 2nd Edition" width="100" height="126" /></a></td>
<td><a href="http://www.amazon.com/gp/product/0470109491?ie=UTF8&amp;tag=nczonline-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0470109491"><img class="colorbox-1356"  src="http://i764.photobucket.com/albums/xx289/nzakas/nczonline/pro_ajax_2e.png" alt="Professional Ajax, 2nd Edition" width="100" height="126" /></a></td>
<td><a href="http://www.amazon.com/gp/product/0596522304?ie=UTF8&amp;tag=nczonline-20&amp;link_code=as3&amp;camp=211189&amp;creative=373489&amp;creativeASIN=0596522304"><img class="colorbox-1356"  src="http://i764.photobucket.com/albums/xx289/nzakas/nczonline/even_faster.png" alt="Even Faster Web Sites" width="100" height="126" /></a></td>
</tr>
</tbody>
</table>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.cn-cuckoo.com/2010/01/10/nicholas-c-zakas-talk-about-what-makes-a-good-front-end-engineer-1356.html/feed</wfw:commentRss>
		<slash:comments>42</slash:comments>
		</item>
		<item>
		<title>如何通过Nicholas C. Zakas的面试</title>
		<link>http://www.cn-cuckoo.com/2010/01/09/surviving-an-interview-with-nicholas-c-zakas-1346.html</link>
		<comments>http://www.cn-cuckoo.com/2010/01/09/surviving-an-interview-with-nicholas-c-zakas-1346.html#comments</comments>
		<pubDate>Sat, 09 Jan 2010 09:38:33 +0000</pubDate>
		<dc:creator>为之漫笔</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://www.cn-cuckoo.com/?p=1346</guid>
		<description><![CDATA[Original Post：Surviving an interview with me Nicholas C. Zakas，2007年3月27日 翻译完成：2010年1月9日，最后更新：2010年1月10日 早就打算写这篇文章了，但时至今日才决定动笔。如果你投了简历，那么应该会在面试你的人名单里找到我的名字。你现在就有点紧张了，（好啦，别不好意思）面试总会让人感觉有点不舒服。作为面试官，我其实并不算难对付，但如果你想在我们谈话之后让我放你过关，你确实得做一些必要的准备。 回答问题。我问你一个问题，你必须要回答它。我遇到应聘者在回答我问题时顾左右而言他的情况太多了。我知道你会有些紧张，说几句不着边际的话可能有助于缓解，但请你不要喋喋不休，要赶快回到正题上来。我不想知道你的宠物猫最近又出了什么新状况，我只想听到你的回答。假如你没有听明白我问的是什么，可以要求我再解释一下，重复几遍问题或者换一种问法，对我而言没有什么。 告诉我你不知道什么。如果我问到了你不知道的问题，一定要告诉我。我不认为你的大脑里可以装得下百科全书。在知道了你不知道什么以后，我对你的评估才会更加公平。问题仍然要回答，但我会给你一些提示，同时也可以考察一下你解决问题的能力。 不要放弃。在我面试你的过程中，不要总想着放弃。如果你被我前面的话不幸言中，那么你可能会面对一个让你不知所措的问题，而且你也告诉我你答不上来了。此时此刻，千万不要打退堂鼓！我会尽力提醒你，让你找到正确答案；因此不要随随便便打断我说：“我真的不知道。”在我们这个行业，你经常会遇到没有现成解决方案的挑战，到时候你会轻易放弃吗？我必须知道你具备解决问题的能力，而不是遇到一点挫折就轻言放弃。 不用担心怪问题。有些公司的确有吓唬应聘者的传统，他们会让你回答一些类似脑筋急转弯似的稀奇古怪的问题。对那种面试方式，我不敢苟同。我提的所有问题都有答案，而且绝大多数还不止有一个正确答案；我保证一个怪问题也不会问你。因为这样既会让你难堪，又对我毫无意义。你大可放心，我的每个问题都至少会有一个正确答案。 自圆其说。如果你提到了某个解决方案或者强调自己掌握了某方面知识，请做好进一步讨论它的准备。假设我问了一个问题，你在回答这个问题时提到：“对，因为IE不支持CSS3……”然后，你最好能够跟我讨论一下要是IE支持CSS3你会怎么办。 不要说自己是专家。大多数面试中可能都需要注意这一条，但我对这一条尤其敏感。我从来不会把应聘者划分为三六九等，因此你也不必告诉我你属于哪个等级。一旦你声明自己已经跻身“专家”的行列，我怕有些问题会让你下不来台。我确实见过自称专家而又确实是专家的人。但是，我认为真正的专家不会自己说出来，而是会做给你看。 不要靠卖弄赚取我的好印象。如果我想知道什么，我会问。我知道在面试时需要了解哪些信息，只要一听到有人说“想不想看一个绝妙的技巧？”或者其他类似的话，我都有一种立即中断面试的冲动。所以，请尽力回答好我的问题即可。 充满激情。如果你想得到跟我一起工作的机会，请给我一个愿意跟你共事的理由。最好的理由就是要有激情，把你主动、积极学习的热情展示出来。希望你能谈一谈产品、公司，以及为什么想得到这份工作。尤其要注意最后一点，我不想听你说你当前的工作如何如何讨厌。当然，可以解释一下为什么现在或者过去没有从事你喜欢的工作，但你一定要告诉我你对自己今后的成长有何打算，还有为什么你应聘的这个职位能够有助于你的成长。 没错，我确实希望将来有可能被我面试的所有人都看到这篇文章。我希望你能在我面试你时表现得非常好，真的，确实如此。说来也简单，只要你留意上述这些常见的问题，并且原原本本地展示你自己就足够了。说不定哪一天，你就会跟我坐到同一间办公室里了。 注意，My Yahoo!团队正在招聘呢。如果你是一位有才华的软件工程师，又对创造价值和Yahoo!公司充满激情，请跟我联系，咱们谈谈。 延伸阅读 Nicholas C. Zakas如何面试前端工程师 Nicholas C. Zakas谈怎样才能成为优秀的前端工程师 Nicholas C. Zakas的书]]></description>
			<content:encoded><![CDATA[<p style="text-align: right;">Original Post：<a title="Surviving an interview with me" href="http://www.nczonline.net/blog/2007/03/27/surviving-an-interview-with-me/" target="_blank">Surviving an interview with me</a><br />
<a title="NCZOnline" href="http://www.nczonline.net/" target="_blank">Nicholas C. Zakas</a>，2007年3月27日<br />
翻译完成：2010年1月9日，最后更新：2010年1月10日</p>
<p>早就打算写这篇文章了，但时至今日才决定动笔。如果你投了简历，那么应该会在面试你的人名单里找到我的名字。你现在就有点紧张了，（好啦，别不好意思）面试总会让人感觉有点不舒服。作为面试官，我其实并不算难对付，但如果你想在我们谈话之后让我放你过关，你确实得做一些必要的准备。</p>
<ul>
<li><strong>回答问题</strong>。我问你一个问题，你必须要回答它。我遇到应聘者在回答我问题时顾左右而言他的情况太多了。我知道你会有些紧张，说几句不着边际的话可能有助于缓解，但请你不要喋喋不休，要赶快回到正题上来。我不想知道你的宠物猫最近又出了什么新状况，我只想听到你的回答。假如你没有听明白我问的是什么，可以要求我再解释一下，重复几遍问题或者换一种问法，对我而言没有什么。</li>
</ul>
<ul>
<li><strong>告诉我你不知道什么</strong>。如果我问到了你不知道的问题，一定要告诉我。我不认为你的大脑里可以装得下百科全书。在知道了你不知道什么以后，我对你的评估才会更加公平。问题仍然要回答，但我会给你一些提示，同时也可以考察一下你解决问题的能力。</li>
</ul>
<ul>
<li><strong>不要放弃</strong>。在我面试你的过程中，不要总想着放弃。如果你被我前面的话不幸言中，那么你可能会面对一个让你不知所措的问题，而且你也告诉我你答不上来了。此时此刻，千万不要打退堂鼓！我会尽力提醒你，让你找到正确答案；因此不要随随便便打断我说：“我真的不知道。”在我们这个行业，你经常会遇到没有现成解决方案的挑战，到时候你会轻易放弃吗？我必须知道你具备解决问题的能力，而不是遇到一点挫折就轻言放弃。</li>
</ul>
<ul>
<li><strong>不用担心怪问题</strong>。有些公司的确有吓唬应聘者的传统，他们会让你回答一些类似脑筋急转弯似的稀奇古怪的问题。对那种面试方式，我不敢苟同。我提的所有问题都有答案，而且绝大多数还不止有一个正确答案；我保证一个怪问题也不会问你。因为这样既会让你难堪，又对我毫无意义。你大可放心，我的每个问题都至少会有一个正确答案。</li>
</ul>
<ul>
<li><strong>自圆其说</strong>。如果你提到了某个解决方案或者强调自己掌握了某方面知识，请做好进一步讨论它的准备。假设我问了一个问题，你在回答这个问题时提到：“对，因为IE不支持CSS3……”然后，你最好能够跟我讨论一下要是IE支持CSS3你会怎么办。</li>
</ul>
<ul>
<li><strong>不要说自己是专家</strong>。大多数面试中可能都需要注意这一条，但我对这一条尤其敏感。我从来不会把应聘者划分为三六九等，因此你也不必告诉我你属于哪个等级。一旦你声明自己已经跻身“专家”的行列，我怕有些问题会让你下不来台。我确实见过自称专家而又确实是专家的人。但是，我认为真正的专家不会自己说出来，而是会做给你看。</li>
</ul>
<ul>
<li><strong>不要靠卖弄赚取我的好印象</strong>。如果我想知道什么，我会问。我知道在面试时需要了解哪些信息，只要一听到有人说“想不想看一个绝妙的技巧？”或者其他类似的话，我都有一种立即中断面试的冲动。所以，请尽力回答好我的问题即可。</li>
</ul>
<ul>
<li> <strong>充满激情</strong>。如果你想得到跟我一起工作的机会，请给我一个愿意跟你共事的理由。最好的理由就是要有激情，把你主动、积极学习的热情展示出来。希望你能谈一谈产品、公司，以及为什么想得到这份工作。尤其要注意最后一点，我不想听你说你当前的工作如何如何讨厌。当然，可以解释一下为什么现在或者过去没有从事你喜欢的工作，但你一定要告诉我你对自己今后的成长有何打算，还有为什么你应聘的这个职位能够有助于你的成长。</li>
</ul>
<p>没错，我确实希望将来有可能被我面试的所有人都看到这篇文章。我希望你能在我面试你时表现得非常好，真的，确实如此。说来也简单，只要你留意上述这些常见的问题，并且原原本本地展示你自己就足够了。说不定哪一天，你就会跟我坐到同一间办公室里了。</p>
<p>注意，My Yahoo!团队正在招聘呢。如果你是一位有才华的软件工程师，又对创造价值和Yahoo!公司充满激情，请跟我联系，咱们谈谈。</p>
<p><strong>延伸阅读</strong></p>
<ul>
<li><a title="Nicholas C. Zakas如何面试前端工程师" href="http://www.cn-cuckoo.com/2010/01/08/how-nicholas-c-zakas-interviewing-the-front-end-engineer-1332.html" target="_blank">Nicholas C. Zakas如何面试前端工程师</a></li>
<li><a title="Nicholas C. Zakas谈怎样才能成为优秀的前端工程师" href="http://www.cn-cuckoo.com/2010/01/10/nicholas-c-zakas-talk-about-what-makes-a-good-front-end-engineer-1356.html" target="_blank">Nicholas C. Zakas谈怎样才能成为优秀的前端工程师</a></li>
</ul>
<div style="margin-top: 1em;">
<p><strong>Nicholas C. Zakas的书</strong></p>
<table style="margin: 0; padding: 0; border: 0;">
<tbody>
<tr>
<td><a href="http://www.amazon.com/gp/product/059680279X?ie=UTF8&amp;tag=nczonline-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=059680279X"><img class="colorbox-1346"  src="http://i764.photobucket.com/albums/xx289/nzakas/nczonline/hpjs.png" alt="" width="100" height="126" /></a></td>
<td><a href="http://www.amazon.com/gp/product/047022780X?ie=UTF8&amp;tag=nczonline-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=047022780X"><img class="colorbox-1346"  src="http://i764.photobucket.com/albums/xx289/nzakas/nczonline/pro_js_2e.png" alt="Professional JavaScript for Web Developers, 2nd Edition" width="100" height="126" /></a></td>
<td><a href="http://www.amazon.com/gp/product/0470109491?ie=UTF8&amp;tag=nczonline-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0470109491"><img class="colorbox-1346"  src="http://i764.photobucket.com/albums/xx289/nzakas/nczonline/pro_ajax_2e.png" alt="Professional Ajax, 2nd Edition" width="100" height="126" /></a></td>
<td><a href="http://www.amazon.com/gp/product/0596522304?ie=UTF8&amp;tag=nczonline-20&amp;link_code=as3&amp;camp=211189&amp;creative=373489&amp;creativeASIN=0596522304"><img class="colorbox-1346"  src="http://i764.photobucket.com/albums/xx289/nzakas/nczonline/even_faster.png" alt="Even Faster Web Sites" width="100" height="126" /></a></td>
</tr>
</tbody>
</table>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.cn-cuckoo.com/2010/01/09/surviving-an-interview-with-nicholas-c-zakas-1346.html/feed</wfw:commentRss>
		<slash:comments>28</slash:comments>
		</item>
		<item>
		<title>Nicholas C. Zakas如何面试前端工程师</title>
		<link>http://www.cn-cuckoo.com/2010/01/08/how-nicholas-c-zakas-interviewing-the-front-end-engineer-1332.html</link>
		<comments>http://www.cn-cuckoo.com/2010/01/08/how-nicholas-c-zakas-interviewing-the-front-end-engineer-1332.html#comments</comments>
		<pubDate>Thu, 07 Jan 2010 23:30:49 +0000</pubDate>
		<dc:creator>为之漫笔</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://www.cn-cuckoo.com/?p=1332</guid>
		<description><![CDATA[Original Post：Interviewing the front-end engineer Nicholas C. Zakas，2010年1月5日 翻译完成：2010年1月7日，最后更新：2010年1月10日 面试前端工程师对我来说是一件非常有意思的事，因为面试过程很大程度上也是自我提升的过程。无论大公司还是小公司，之所以在如何招聘到真正有能力的前端工程师方面会遇到同样的问题，就是因为负责招聘的那些人不知道自己公司需要什么样的人，结果问问题时也问不到点子上。经过这几年在行业里的摸索，我总结出了自己的一套很有效的面试前端工程的方法。 有的应聘者说我不好对付，但留给他们这样的印象也并非我所愿。我觉得之所以他们说我不好对付，主要是因为我问他们问题时问得太细了。以前我曾专门写过一些东西，告诉应聘者怎么才能通过我的面试以及怎样才能成为优秀的前端工程师应该具备什么样的素质，而我的面试可以说完全是按照那两篇文章的标准进行的。我不会问一些特别偏门的问题，也不认为出几道逻辑题就能考出人的真实水平。我唯一的想法就是确定你能否胜任我们要招的这个职位。为此，我需要简单地考察如下几个方面。 基本知识 我们生活在互联网时代，你想知道的任何事情几乎都能在15分钟内找到相关信息。可是，能找到信息并不等于你会使用它。我认为所有前端工程师至少都应该掌握某些基本的知识，才能有效地完成自己的工作。如果一遇到问题，就停下工作上网四处搜索解决方案，怎么可能保证按期完成工作呢？听听，还有谁在说“我不知道，但我可以上网搜到。”请这些同学把手举起来，让大家认识一下（immediately raises a flag for me.）。下面我列出一些基本的知识点，这些都是我认为一名前端工程师（无论工作年头长短）在没有任何外来帮助的情况下就应该知道的。 DOM结构——两个节点之间可能存在哪些关系以及如何在节点之间任意移动。 DOM操作——怎样添加、移除、移动、复制、创建和查找节点。 事件——怎样使用事件以及IE和DOM事件模型之间存在哪些主要差别。 XMLHttpRequest——这是什么、怎样完整地执行一次GET请求、怎样检测错误。 严格模式与混杂模式——如何触发这两种模式，区分它们有何意义。 盒模型——外边距、内边距和边框之间的关系，IE &#60; 8中的盒模型有什么不同。 块级元素与行内元素——怎么用CSS控制它们、它们怎样影响周围的元素以及你觉得应该如何定义它们的样式。 浮动元素——怎么使用它们、它们有什么问题以及怎么解决这些问题。 HTML与XHTML——二者有什么区别，你觉得应该使用哪一个并说出理由。 JSON——它是什么、为什么应该使用它、到底该怎么使用它，说出实现细节来。 重申一下，上述这些知识点都应该是你“想都不用想”就知道的东西。我一开始问的所有问题都是想摸清你对所有这些领域知识的掌握程度。虽然上面列出的这些知识点并没有面面俱到，但我觉得你至少应该掌握这些，才有可能跟我坐到一间办公室里来。 少量提问 我非常赞同面试者问的问题越少越好。反复问应聘者各种问题既不公平，也很无聊。我在任何一次面试中，通常只问三个大问题，但每个问题又会涉及我所能想到的多个方面。回答每个大问题一般要经过几个步骤，这样我就可以在每个步骤中穿插着问一些小问题。比如说： 现在有一个正显示着Yahoo!股票价格的页面。页面上有一个按钮，你可以单击它来刷新价格，但不会重新加载页面。请你描述一下实现这个功能的过程，假设服务器会负责准备好正确的股票价格数据。 这个问题牵扯到一组我想要考察的基本知识点：DOM结构、DOM操作、事件处理、XHR和JSON。如果我要求你换一种处理股票价格的方式，或者让你在页面中显示其他信息，就可以把更多的知识点包括进来。对于经验比较丰富的应聘者，我也可以自如地扩展要考察的知识范围，最简单像JOSN与XML的区别、安全问题、容量问题，等等。 我还希望应聘者给出的任何解决方案中都不要使用库。我想看到最原生态的代码，你就当页面中没有包含任何库。你说你对哪个库了解多少多少，但我不能把关于库的知识作为评判能力的因素，因为库是会随时间变化的。我需要的是真正理解库背后的机制，特别是能够徒手写出一个自己的库的人。 解决问题 做为一名前端工程师，最值得高兴的事莫过于解决同一个问题会有很多种不同的方法，而你要做的就是找出最合适的方法来。我在提问的时候，经常会在应聘者解释完一种方法后问他们还有没有第二种方法。此时我会跟他们说，假设你的这个方法由于种种原因被否决了，那么你还能不能给出另一种方法。这样做可以达到两个目的。 首先，可以测试出他们是否在毫无意义地复述书本中的东西。不能不承认，某些人确实有过目不忘的天赋，听他们在那里滔滔不绝地讲，你会觉得他们什么都明白。可是，只要一跟这些人谈到怎么查找方案无效的原因，以及能否拿出一个新方案来，他们往往就傻眼了。这时候，如果我听到“我不明白这个方案为什么不够好”之类的反问，心里立刻就明白我的问题已经超出了他们的能力范围，而他们只是想拿自己死记硬背的结论来蒙混过关。 其次，可以测试出他们已经掌握的（还是那句话，“想都不用想”就知道的）浏览器技术知识。如果他们对浏览器平台的核心知识有较好的理解，想出解决同一问题的不同方案根本没有那么难。 对一名前端工程师来说，这绝对是最重要的能力。前端工程师在工作中遇到本该如此却并未如此的难题（说你啦，IE6），应该说是一件很平常的事。一个方案无效就无计可施的人，做不了前端工程师。 考核应聘者解决问题能力的另一层原因，与我的个人喜好有关。在搞清楚应聘者知道什么不知道什么之后，我就会想着问一个他们知识领域之外的问题。这样做的目的，就是想看看他们怎样运用已有的知识解决新问题。在解决问题的每一步，我也准备了一些提示，以防有人会卡壳打艮（在我面前15分钟一言不发，对我评价这个人毫无帮助）。我真正感兴趣的，是他们能够从上一步前进到下一步。我希望看到一个人就在我眼前学到新知识。 注意：所有问题都与浏览器技术相关。我不相信出几道抽象的逻辑题，就能够考出某人解决Web技术问题的能力。在我看来，这无异于让素描大师画肖像（或者让刘翔跟博尔特同场竞技），没有意义，也得不到任何有价值的信息。 有激情 要成为一名优秀的前端工程师，最重要的莫过于对自己做的事要有激情。我们的技能都不是从学校中或者研讨会上学来的，因此前端工程师必须具备自学能力。浏览器技术的变化可谓日新月异，所以也只有不断提升自己的技能才做得到与时俱进。我虽然不能强迫谁必须多看博客、不断学习，但想应聘前端工程师的人恐怕还是必须得这么做。 你怎么知道谁对这种工作有没有激情？实际上非常简单。我只问一个简单的问题：“目前你对什么Web技术最感兴趣？”这个问题永远不会过期，而且也几乎不可能出错……除非你答不上来。就眼下来说，我希望你对这个问题给出的技术中包括WebSocket、HTML、WebGL、客户端数据库，等等。只有对Web开发充满激情的人，才会坚持不懈地学习新知识、掌握新技能；这些人才是我真正想要的。当然，我会让他们详细解释自己提到的技术，以保证他们不是随口念叨了几个时髦的新词汇。 最后一点 计算机科学或者Web设计方面的知识当然也有用，但那都是基本知识之外的东西。只要基本知识在那儿了，一切就都有了基础，想扩充知识面也不难。可是，如果等到正式上班以后，还得从头学习基本技能，那种难度是不可同日而语的。另外，高级前端工程师与一般工程师相比，肯定需要掌握更多的技能。而面试几乎没有经验的大学毕业生，我也会有一套完全不同的程序。我在这篇文章里列出来的都是一些最基本的东西。 对于那些还没有多少面试经验的人，我总是喜欢告诉他们，面试完了只要问自己一个问题就行：你想以后跟这个人在一起共事吗？如果不管为什么，回答是不，那就是不。 免责声明：本文的任何观点与意见都只跟Nicholas C. Zakas有关，与Yahoo!公司、Wrox出版公司、O&#8217;Reilly出版公司乃至其他任何人无关。我在这里说的话，仅代表我自己，不代表上述公司。 你可以在这里留言，也可以在你自己的站点上发送一个引用通告。 延伸阅读 如何通过Nicholas [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: right;">Original Post：<a title="Interviewing the front-end engineer" href="http://www.nczonline.net/blog/2010/01/05/interviewing-the-front-end-engineer/" target="_blank">Interviewing the front-end engineer<br />
</a><a title="NCZOnline" href="http://www.nczonline.net/" target="_blank">Nicholas C. Zakas</a>，2010年1月5日<br />
翻译完成：2010年1月7日，最后更新：2010年1月10日</p>
<p>面试前端工程师对我来说是一件非常有意思的事，因为面试过程很大程度上也是自我提升的过程。无论大公司还是小公司，之所以在如何招聘到真正有能力的前端工程师方面会遇到同样的问题，就是因为负责招聘的那些人不知道自己公司需要什么样的人，结果问问题时也问不到点子上。经过这几年在行业里的摸索，我总结出了自己的一套很有效的面试前端工程的方法。</p>
<p>有的应聘者说我不好对付，但留给他们这样的印象也并非我所愿。我觉得之所以他们说我不好对付，主要是因为我问他们问题时问得太细了。以前我曾专门写过一些东西，告诉应聘者<a title="如何通过Nicholas C. Zakas的面试" href="http://www.cn-cuckoo.com/2010/01/09/surviving-an-interview-with-nicholas-c-zakas-1346.html" target="_blank">怎么才能通过我的面试</a>以及<a title="Nicholas C. Zakas谈怎样才能成为优秀的前端工程师" href="http://www.cn-cuckoo.com/2010/01/10/nicholas-c-zakas-talk-about-what-makes-a-good-front-end-engineer-1356.html" target="_blank">怎样才能成为优秀的前端工程师</a><span style="text-decoration: line-through;">应该具备什么样的素质</span>，而我的面试可以说完全是按照那两篇文章的标准进行的。我不会问一些特别偏门的问题，也不认为出几道逻辑题就能考出人的真实水平。我唯一的想法就是确定你能否胜任我们要招的这个职位。为此，我需要简单地考察如下几个方面。</p>
<h2>基本知识</h2>
<p>我们生活在互联网时代，你想知道的任何事情几乎都能在15分钟内找到相关信息。可是，能找到信息并不等于你会使用它。我认为所有前端工程师至少都应该掌握某些基本的知识，才能有效地完成自己的工作。如果一遇到问题，就停下工作上网四处搜索解决方案，怎么可能保证按期完成工作呢？听听，还有谁在说“我不知道，但我可以上网搜到。”请这些同学把手举起来，让大家认识一下（immediately raises a flag for me.）。下面我列出一些基本的知识点，这些都是我认为一名前端工程师（无论工作年头长短）在没有任何外来帮助的情况下就应该知道的。</p>
<ul>
<li><strong>DOM结构</strong>——两个节点之间可能存在哪些关系以及如何在节点之间任意移动。</li>
<li><strong>DOM操作</strong>——怎样添加、移除、移动、复制、创建和查找节点。</li>
<li><strong>事件</strong>——怎样使用事件以及IE和DOM事件模型之间存在哪些主要差别。</li>
<li><strong>XMLHttpRequest</strong>——这是什么、怎样完整地执行一次GET请求、怎样检测错误。</li>
<li><strong>严格模式与混杂模式</strong>——如何触发这两种模式，区分它们有何意义。</li>
<li><strong>盒模型</strong>——外边距、内边距和边框之间的关系，IE &lt; 8中的盒模型有什么不同。</li>
<li><strong>块级元素与行内元素</strong>——怎么用CSS控制它们、它们怎样影响周围的元素以及你觉得应该如何定义它们的样式。</li>
<li><strong>浮动元素</strong>——怎么使用它们、它们有什么问题以及怎么解决这些问题。</li>
<li><strong>HTML与XHTML</strong>——二者有什么区别，你觉得应该使用哪一个并说出理由。</li>
<li><strong>JSON</strong>——它是什么、为什么应该使用它、到底该怎么使用它，说出实现细节来。</li>
</ul>
<p>重申一下，上述这些知识点都应该是你“想都不用想”就知道的东西。我一开始问的所有问题都是想摸清你对所有这些领域知识的掌握程度。虽然上面列出的这些知识点并没有面面俱到，但我觉得你至少应该掌握这些，才有可能跟我坐到一间办公室里来。</p>
<h2>少量提问</h2>
<p>我非常赞同面试者问的问题越少越好。反复问应聘者各种问题既不公平，也很无聊。我在任何一次面试中，通常只问三个大问题，但每个问题又会涉及我所能想到的多个方面。回答每个大问题一般要经过几个步骤，这样我就可以在每个步骤中穿插着问一些小问题。比如说：<span id="more-1332"></span></p>
<div style="margin: 0 1em 0 1em; background: #eee; padding: 1em;">现在有一个正显示着Yahoo!股票价格的页面。页面上有一个按钮，你可以单击它来刷新价格，但不会重新加载页面。请你描述一下实现这个功能的过程，假设服务器会负责准备好正确的股票价格数据。</div>
<p>这个问题牵扯到一组我想要考察的基本知识点：DOM结构、DOM操作、事件处理、XHR和JSON。如果我要求你换一种处理股票价格的方式，或者让你在页面中显示其他信息，就可以把更多的知识点包括进来。对于经验比较丰富的应聘者，我也可以自如地扩展要考察的知识范围，最简单像JOSN与XML的区别、安全问题、容量问题，等等。</p>
<p>我还希望应聘者给出的任何解决方案中都<strong>不要</strong>使用库。我想看到最原生态的代码，你就当页面中没有包含任何库。你说你对哪个库了解多少多少，但我不能把关于库的知识作为评判能力的因素，因为库是会随时间变化的。我需要的是真正理解库背后的机制，特别是能够徒手写出一个自己的库的人。</p>
<h2>解决问题</h2>
<p>做为一名前端工程师，最值得高兴的事莫过于解决同一个问题会有很多种不同的方法，而你要做的就是找出最合适的方法来。我在提问的时候，经常会在应聘者解释完一种方法后问他们还有没有第二种方法。此时我会跟他们说，假设你的这个方法由于种种原因被否决了，那么你还能不能给出另一种方法。这样做可以达到两个目的。</p>
<p>首先，可以测试出他们是否在毫无意义地复述书本中的东西。不能不承认，某些人确实有过目不忘的天赋，听他们在那里滔滔不绝地讲，你会觉得他们什么都明白。可是，只要一跟这些人谈到怎么查找方案无效的原因，以及能否拿出一个新方案来，他们往往就傻眼了。这时候，如果我听到“我不明白这个方案为什么不够好”之类的反问，心里立刻就明白我的问题已经超出了他们的能力范围，而他们只是想拿自己死记硬背的结论来蒙混过关。</p>
<p>其次，可以测试出他们已经掌握的（还是那句话，“想都不用想”就知道的）浏览器技术知识。如果他们对浏览器平台的核心知识有较好的理解，想出解决同一问题的不同方案根本没有那么难。</p>
<p>对一名前端工程师来说，这绝对是最重要的能力。前端工程师在工作中遇到本该如此却并未如此的难题（说你啦，IE6），应该说是一件很平常的事。一个方案无效就无计可施的人，做不了前端工程师。</p>
<p>考核应聘者解决问题能力的另一层原因，与我的个人喜好有关。在搞清楚应聘者知道什么不知道什么之后，我就会想着问一个他们知识领域之外的问题。这样做的目的，就是想看看他们怎样运用已有的知识解决新问题。在解决问题的每一步，我也准备了一些提示，以防有人会卡壳打艮（在我面前15分钟一言不发，对我评价这个人毫无帮助）。我真正感兴趣的，是他们能够从上一步前进到下一步。我希望看到一个人就在我眼前学到新知识。</p>
<p>注意：所有问题都与浏览器技术相关。我不相信出几道抽象的逻辑题，就能够考出某人解决Web技术问题的能力。在我看来，这无异于让素描大师画肖像（或者让刘翔跟博尔特同场竞技），没有意义，也得不到任何有价值的信息。</p>
<h2>有激情</h2>
<p>要成为一名优秀的前端工程师，最重要的莫过于对自己做的事要有激情。我们的技能都不是从学校中或者研讨会上学来的，因此前端工程师必须具备自学能力。浏览器技术的变化可谓日新月异，所以也只有不断提升自己的技能才做得到与时俱进。我虽然不能强迫谁必须多看博客、不断学习，但想应聘前端工程师的人恐怕还是必须得这么做。</p>
<p>你怎么知道谁对这种工作有没有激情？实际上非常简单。我只问一个简单的问题：“目前你对什么Web技术最感兴趣？”这个问题永远不会过期，而且也几乎不可能出错……除非你答不上来。就眼下来说，我希望你对这个问题给出的技术中包括WebSocket、HTML、WebGL、客户端数据库，等等。只有对Web开发充满激情的人，才会坚持不懈地学习新知识、掌握新技能；这些人才是我真正想要的。当然，我会让他们详细解释自己提到的技术，以保证他们不是随口念叨了几个时髦的新词汇。</p>
<h2>最后一点</h2>
<p>计算机科学或者Web设计方面的知识当然也有用，但那都是基本知识之外的东西。只要基本知识在那儿了，一切就都有了基础，想扩充知识面也不难。可是，如果等到正式上班以后，还得从头学习基本技能，那种难度是不可同日而语的。另外，高级前端工程师与一般工程师相比，肯定需要掌握更多的技能。而面试几乎没有经验的大学毕业生，我也会有一套完全不同的程序。我在这篇文章里列出来的都是一些最基本的东西。</p>
<p>对于那些还没有多少面试经验的人，我总是喜欢告诉他们，面试完了只要问自己一个问题就行：你想以后跟这个人在一起共事吗？如果不管为什么，回答是不，那就是不。</p>
<div style="padding: 1em; border: 1px dashed #ddd;">免责声明：本文的任何观点与意见都只跟Nicholas C. Zakas有关，与Yahoo!公司、Wrox出版公司、O&#8217;Reilly出版公司乃至其他任何人无关。我在这里说的话，仅代表我自己，不代表上述公司。</p>
<p>你可以在这里留言，也可以在你自己的站点上发送一个引用通告。</p>
</div>
<p><strong>延伸阅读</strong></p>
<ul>
<li><a title="如何通过Nicholas C. Zakas的面试" href="http://www.cn-cuckoo.com/2010/01/09/surviving-an-interview-with-nicholas-c-zakas-1346.html" target="_blank">如何通过Nicholas C. Zakas的面试</a></li>
<li><a title="Nicholas C. Zakas谈怎样才能成为优秀的前端工程师" href="http://www.cn-cuckoo.com/2010/01/10/nicholas-c-zakas-talk-about-what-makes-a-good-front-end-engineer-1356.html" target="_blank">Nicholas C. Zakas谈怎样才能成为优秀的前端工程师</a></li>
</ul>
<div style="margin-top: 1em;">
<p><strong>Nicholas C. Zakas的书</strong></p>
<table style="margin: 0; padding: 0; border: 0;">
<tbody>
<tr>
<td><a href="http://www.amazon.com/gp/product/059680279X?ie=UTF8&amp;tag=nczonline-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=059680279X"><img class="colorbox-1332"  src="http://i764.photobucket.com/albums/xx289/nzakas/nczonline/hpjs.png" alt="" width="100" height="126" /></a></td>
<td><a href="http://www.amazon.com/gp/product/047022780X?ie=UTF8&amp;tag=nczonline-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=047022780X"><img class="colorbox-1332"  src="http://i764.photobucket.com/albums/xx289/nzakas/nczonline/pro_js_2e.png" alt="Professional JavaScript for Web Developers, 2nd Edition" width="100" height="126" /></a></td>
<td><a href="http://www.amazon.com/gp/product/0470109491?ie=UTF8&amp;tag=nczonline-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0470109491"><img class="colorbox-1332"  src="http://i764.photobucket.com/albums/xx289/nzakas/nczonline/pro_ajax_2e.png" alt="Professional Ajax, 2nd Edition" width="100" height="126" /></a></td>
<td><a href="http://www.amazon.com/gp/product/0596522304?ie=UTF8&amp;tag=nczonline-20&amp;link_code=as3&amp;camp=211189&amp;creative=373489&amp;creativeASIN=0596522304"><img class="colorbox-1332"  src="http://i764.photobucket.com/albums/xx289/nzakas/nczonline/even_faster.png" alt="Even Faster Web Sites" width="100" height="126" /></a></td>
</tr>
</tbody>
</table>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.cn-cuckoo.com/2010/01/08/how-nicholas-c-zakas-interviewing-the-front-end-engineer-1332.html/feed</wfw:commentRss>
		<slash:comments>35</slash:comments>
		</item>
		<item>
		<title>命名函数表达式探秘</title>
		<link>http://www.cn-cuckoo.com/2009/12/22/named-function-expressions-demystified-1320.html</link>
		<comments>http://www.cn-cuckoo.com/2009/12/22/named-function-expressions-demystified-1320.html#comments</comments>
		<pubDate>Tue, 22 Dec 2009 10:47:04 +0000</pubDate>
		<dc:creator>为之漫笔</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://www.cn-cuckoo.com/?p=1320</guid>
		<description><![CDATA[函数声明与函数表达式的有什么区别？ 命名函数表达式的语义及其适用场景有哪些？ JScript、WebKit在实现命名函数表达式时“创造”了哪些bug？ SpiderMonkey在实现命名函数表达式是如何对规范“言听计从”的？ 请看 命名函数表达式探秘 原文链接：http://yura.thinkweb2.com/named-function-expressions/ 本文链接：http://www.cn-cuckoo.com/2009/12/22/named-function-expressions-demystified-1320.html Table of Contents 前言 函数表达式与函数声明 函数语句 命名函数表达式 调试器中的函数名 JScript的bug JScript的内存管理 测试 Safari中存在的bug SpiderMonkey的怪癖 解决方案 替代方案 WebKit的displayName 对未来的思考 致谢]]></description>
			<content:encoded><![CDATA[<p>函数声明与函数表达式的有什么区别？<br />
命名函数表达式的语义及其适用场景有哪些？<br />
JScript、WebKit在实现命名函数表达式时“创造”了哪些bug？<br />
SpiderMonkey在实现命名函数表达式是如何对规范“言听计从”的？</p>
<p>请看<br />
<a style="font-size:48px;text-decoration:none;" href="http://www.cn-cuckoo.com/main/wp-content/uploads/2009/12/named-function-expressions-demystified.html">命名函数表达式探秘</a></p>
<p>原文链接：<a href="http://yura.thinkweb2.com/named-function-expressions/">http://yura.thinkweb2.com/named-function-expressions/</a><br />
本文链接：<a href="http://www.cn-cuckoo.com/2009/12/22/named-function-expressions-demystified-1320.html">http://www.cn-cuckoo.com/2009/12/22/named-function-expressions-demystified-1320.html</a></p>
<h1>Table of Contents</h1>
<ol>
<li><a href="http://www.cn-cuckoo.com/main/wp-content/uploads/2009/12/named-function-expressions-demystified.html#introduction">前言</a></li>
<li><a href="http://www.cn-cuckoo.com/main/wp-content/uploads/2009/12/named-function-expressions-demystified.html#expr-vs-decl">函数表达式与函数声明</a></li>
<li><a href="http://www.cn-cuckoo.com/main/wp-content/uploads/2009/12/named-function-expressions-demystified.html#function-statements">函数语句</a></li>
<li><a href="http://www.cn-cuckoo.com/main/wp-content/uploads/2009/12/named-function-expressions-demystified.html#named-expr">命名函数表达式</a></li>
<li><a href="http://www.cn-cuckoo.com/main/wp-content/uploads/2009/12/named-function-expressions-demystified.html#names-in-debuggers">调试器中的函数名</a></li>
<li><a href="http://www.cn-cuckoo.com/main/wp-content/uploads/2009/12/named-function-expressions-demystified.html#jscript-bugs">JScript的bug</a></li>
<li><a href="http://www.cn-cuckoo.com/main/wp-content/uploads/2009/12/named-function-expressions-demystified.html#jscript-memory-management">JScript的内存管理</a></li>
<li><a href="http://www.cn-cuckoo.com/main/wp-content/uploads/2009/12/named-function-expressions-demystified.html#tests">测试</a></li>
<li><a href="http://www.cn-cuckoo.com/main/wp-content/uploads/2009/12/named-function-expressions-demystified.html#safari-bug">Safari中存在的bug</a></li>
<li><a href="http://www.cn-cuckoo.com/main/wp-content/uploads/2009/12/named-function-expressions-demystified.html#spidermonkey-peculiarity">SpiderMonkey的怪癖</a></li>
<li><a href="http://www.cn-cuckoo.com/main/wp-content/uploads/2009/12/named-function-expressions-demystified.html#solution">解决方案</a></li>
<li><a href="http://www.cn-cuckoo.com/main/wp-content/uploads/2009/12/named-function-expressions-demystified.html#alt-solution">替代方案</a></li>
<li><a href="http://www.cn-cuckoo.com/main/wp-content/uploads/2009/12/named-function-expressions-demystified.html#webkit-displayName">WebKit的displayName</a></li>
<li><a href="http://www.cn-cuckoo.com/main/wp-content/uploads/2009/12/named-function-expressions-demystified.html#future-considerations">对未来的思考</a></li>
<li><a href="http://www.cn-cuckoo.com/main/wp-content/uploads/2009/12/named-function-expressions-demystified.html#credits">致谢</a></li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.cn-cuckoo.com/2009/12/22/named-function-expressions-demystified-1320.html/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>翻译CSS之父论文《层叠样式表》</title>
		<link>http://www.cn-cuckoo.com/2009/11/16/translating-thesis-of-hakon-wium-lie-1270.html</link>
		<comments>http://www.cn-cuckoo.com/2009/11/16/translating-thesis-of-hakon-wium-lie-1270.html#comments</comments>
		<pubDate>Mon, 16 Nov 2009 14:51:55 +0000</pubDate>
		<dc:creator>为之漫笔</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://www.cn-cuckoo.com/?p=1270</guid>
		<description><![CDATA[提示：由于目前正在抓紧时间翻译Professional JavaScript, 2nd，预计春节之前没有时间翻译这份论文了。对自己，也对大家，更对“CSS之父”说声抱歉吧！ 中文链接：www.cn-cuckoo.com/css/thesis-of-Hakon-Wium-Lie/ 原文链接：people.opera.com/howcome/2006/phd/ 翻译进度列表： 2009-1-7，“灵感” 2009-11-1，“第1章 导言” Håkon Wium Lie出生于1965年7月26日，是土生土长的挪威人。现为Opera Software的CTO（Chief Technology Officer，首席技术官）。他的个人页面、维基百科词条。 1994年，Håkon Wium Lie提出了层叠样式表的概念，并于当年10月提交了他的样式表建议——Cascading HTML style sheets。1996年12月，他亲自主持并以他的建议为基础创建的Cascading Style Sheets, level 1，正式成为W3C的推荐标准。后来，几乎所有主要浏览器都实现了CSS。CSS的普及，结束了长达数年之久的“表现性HTML”的历史，开创了标准Web开发中结构、表现、行为分离的新时代。 1995年， Håkon Wium Lie针对测试Web浏览器在呈现HTML标记、CSS2.1样式、PNG图像及数据URI方面的支持情况，提出了Acid2建议。该建议后来由Web标准组织开发并发布，成为判定新（版）浏览器对Web标准支持情况的一个重要依据。 另外，Håkon Wium Lie与另一位CSS标准的制定者Bert Bos合著的Cascading Style Sheets: Designing for the Web, 3rd Edition 2005年5月由Addison-Wesley Professional出版。也是学习CSS的一本优秀图书。这里还有一篇发表于A List Apart的他们合写的文章：Printing a Book with CSS: Boom! 总而言之，翻译这篇论文的想法由来已久了。原因很简单，这篇论文是Håkon Wium Lie在他提出CSS的建议10年后写就的，其中全面翔实地包含了大量与CSS及Web发展有关的珍贵资料，是研究和学习CSS不可多得的重要参考文献。翻译这篇论文的过程，也是学习和研究的过程。希望自己在翻译完这篇论文后，对CSS和Web的理解能上升到一个新的层次。]]></description>
			<content:encoded><![CDATA[<div style="background:orange;padding:1em;color:#fff;"><strong>提示：</strong>由于目前正在抓紧时间翻译<a style="color:#fff;" href="http://www.amazon.com/dp/047022780X/"><em>Professional JavaScript, 2nd</em></a>，预计春节之前没有时间翻译这份论文了。对自己，也对大家，更对“CSS之父”说声抱歉吧！</div>
<p>中文链接：<a title="http://www.cn-cuckoo.com/css/thesis-of-Hakon-Wium-Lie/" href="http://www.cn-cuckoo.com/css/thesis-of-Hakon-Wium-Lie/" target="_blank">www.cn-cuckoo.com/css/thesis-of-Hakon-Wium-Lie/</a></p>
<p>原文链接：<a style="color: #0000ee; background-image: initial; background-repeat: initial; background-attachment: initial; -webkit-background-clip: initial; -webkit-background-origin: initial; background-color: transparent; text-decoration: none; background-position: initial initial;" title="http://people.opera.com/howcome/2006/phd/" href="http://people.opera.com/howcome/2006/phd/" target="_blank">people.opera.com/howcome/2006/phd/</a></p>
<p><span id="more-1270"></span><img class="size-full wp-image-1273 alignleft colorbox-1270" title="cover" src="http://www.cn-cuckoo.com/wordpress/wp-content/uploads/2009/11/cover1.jpg" alt="cover" width="360" height="335" /></p>
<p>翻译进度列表：</p>
<ul>
<li>2009-1-7，“<a title="灵感" href="http://www.cn-cuckoo.com/css/thesis-of-Hakon-Wium-Lie/#inspiration" target="_blank">灵感</a>”</li>
<li>2009-11-1，“<a title="http://www.cn-cuckoo.com/css/thesis-of-Hakon-Wium-Lie/#ch-introduction" href="http://www.cn-cuckoo.com/css/thesis-of-Hakon-Wium-Lie/#ch-introduction" target="_blank">第1章 导言</a>”</li>
</ul>
<div style="clear:both"><a title="http://people.opera.com/howcome/" href="http://people.opera.com/howcome/" target="_blank"><img class="colorbox-1270"  style="float: right; width: 90px; height: 135px;" title="Håkon Wium Lie博士" src="http://people.opera.com/howcome/2005/img/hakon_wium_lie-s.jpg" alt="Håkon Wium Lie博士" hspace="10" vspace="20" width="90" height="135" /></a><br />
Håkon Wium Lie出生于1965年7月26日，是土生土长的挪威人。现为<a title="Opera Software" href="http://www.opera.com/" target="_blank">Opera Software</a>的CTO（Chief Technology Officer，首席技术官）。他的<a title="http://people.opera.com/howcome/" href="http://people.opera.com/howcome/" target="_blank">个人页面</a>、<a title="http://en.wikipedia.org/wiki/Håkon_Wium_Lie" href="http://en.wikipedia.org/wiki/Håkon_Wium_Lie" target="_blank">维基百科词条</a>。</p>
<p>1994年，Håkon Wium Lie提出了层叠样式表的概念，并于当年10月提交了他的样式表建议——<a title="http://www.w3.org/People/howcome/p/cascade.html" href="http://www.w3.org/People/howcome/p/cascade.html" target="_blank">Cascading HTML style sheets</a>。1996年12月，他亲自主持并以他的建议为基础创建的<a title="http://www.w3.org/TR/CSS1/" href="http://www.w3.org/TR/CSS1/" target="_blank">Cascading Style Sheets, level 1</a>，正式成为W3C的推荐标准。后来，几乎所有主要浏览器都实现了CSS。CSS的普及，结束了长达数年之久的“表现性HTML”的历史，开创了标准Web开发中结构、表现、行为分离的新时代。</p>
<p>1995年， Håkon Wium Lie针对测试Web浏览器在呈现HTML标记、CSS2.1样式、<a title="http://en.wikipedia.org/wiki/Portable_Network_Graphics" href="http://en.wikipedia.org/wiki/Portable_Network_Graphics" target="_blank">PNG图像</a>及<a title="http://en.wikipedia.org/wiki/Data_URI" href="http://en.wikipedia.org/wiki/Data_URI" target="_blank">数据URI</a>方面的支持情况，提出了Acid2建议。该建议后来由Web标准组织开发并发布，成为判定新（版）浏览器对Web标准支持情况的一个重要依据。</p>
<p><a title="http://www.amazon.com/Cascading-Style-Sheets-Designing-Web/dp/0321193121" href="http://www.amazon.com/Cascading-Style-Sheets-Designing-Web/dp/0321193121" target="_blank"><img class="colorbox-1270"  style="margin-bottom: 10px; width: 91px; height: 120px;" src="http://people.opera.com/howcome/2005/img/bk3/cover.jpg" alt="" hspace="10" vspace="0" width="91" height="120" align="left" /></a>另外，Håkon Wium Lie与另一位CSS标准的制定者<a title="http://www.w3.org/People/Bos/" href="http://www.w3.org/People/Bos/" target="_blank">Bert Bos</a>合著的<a title="http://www.amazon.com/Cascading-Style-Sheets-Designing-Web/dp/0321193121" href="http://www.amazon.com/Cascading-Style-Sheets-Designing-Web/dp/0321193121" target="_blank"><em>Cascading Style Sheets: Designing for the Web, 3rd Edition</em></a> 2005年5月由Addison-Wesley Professional出版。也是学习CSS的一本优秀图书。这里还有一篇发表于<a title="http://www.alistapart.com/" href="http://www.alistapart.com/" target="_blank">A List Apart</a>的他们合写的文章：<a title="http://www.alistapart.com/articles/boom" href="http://www.alistapart.com/articles/boom" target="_blank">Printing a Book with CSS: Boom!</a></p>
<p>总而言之，翻译这篇论文的想法由来已久了。原因很简单，这篇论文是Håkon Wium Lie在他提出CSS的建议10年后写就的，其中全面翔实地包含了大量与CSS及Web发展有关的珍贵资料，是研究和学习CSS不可多得的重要参考文献。翻译这篇论文的过程，也是学习和研究的过程。希望自己在翻译完这篇论文后，对CSS和Web的理解能上升到一个新的层次。</p></div>
]]></content:encoded>
			<wfw:commentRss>http://www.cn-cuckoo.com/2009/11/16/translating-thesis-of-hakon-wium-lie-1270.html/feed</wfw:commentRss>
		<slash:comments>35</slash:comments>
		</item>
		<item>
		<title>MySQL数据类型</title>
		<link>http://www.cn-cuckoo.com/2009/11/07/mysql-data-type-1230.html</link>
		<comments>http://www.cn-cuckoo.com/2009/11/07/mysql-data-type-1230.html#comments</comments>
		<pubDate>Sat, 07 Nov 2009 08:26:44 +0000</pubDate>
		<dc:creator>为之漫笔</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[原创]]></category>

		<guid isPermaLink="false">http://www.cn-cuckoo.com/?p=1230</guid>
		<description><![CDATA[MySQL跟其他主流数据库一样，能够存储任何类型的数据，比如字符、数值和日期。而且，大多数应用程序中只会用到这3种数据。 1. 字符数据 1.1 字符数据分为字符型和文本型。字符型又分为两种，一是固定长度字符型（char），存储空间为255字节，不足空间以空格填充；另一种是可变长度字符型（varchar），存储空间为65 535字节，不足空间不用空格填充。在为表列定义字符类型时，必须指定最大字符数（英文每个字母占一个字节，汉字每个字占两个字节），不能超过相应类型的字节上限，例如： char(40) /* 固定长度字符列，最多可以保存40个英文字母或20个汉字 */ char(280) /* 无效，超过了255字节 */ varchar(280) /* 可变长度字符列，最多可以保存280个英文字母或140个汉字 */ 1.2 另外，在为表列指定数据类型的同时，可以同时指定列的字符集，例如： varchar(20) character set utf8 /* UTF-8字符集，可以用于保存汉字等多字节字符 */ 甚至，在创建数据库时也可以直接指定默认的字符集，例如： create database myblog character set utf8; 1.3 对于要求存储空间大于64KB（64×1024=65 535字节）的列，就需要声明为文本型了。文本型又分为四种：短文本型（tinytext/255）、文本型（text/65 535）、中长文本型（mediumtext/16 777 215）和长文本型（longtext/4 294 967 295）。 由于MySQL提供了65 535字节长的可变长度字符型（varchar），因此短文本型（tinytext）和文本型（text）并不常用。 关于文本型数据，有以下说明： （1）如果实际文本超出相应类型指定的最大长度，则多余文本将被截掉； （2）如果实际文本不足相应类型指定的最大长度，则不会删除后面空格； 2. 数值数据 数值数据分为整数和浮点数（带小数点的数，有符号），而整数又分有符号数和无符号数（用于区分正负数）。MySQL中有5种整数数值类型： 较小整数（tinyint/-128~127或0~255）； 小整数（smallint/-32 768~32 767或0~65 535）； [...]]]></description>
			<content:encoded><![CDATA[<div class="wp-caption alignleft" style="width: 124px"><a title="http://www.mysql.com/" href="http://www.mysql.com/" target="_blank"><img class="  colorbox-1230" style="margin:0 1em 1em 0" src="http://www.mysql.com/common/logos/logo_mysql_sun_a.gif" alt="MySQL" width="114" height="68" /></a><p class="wp-caption-text">MySQL</p></div>
<p>MySQL跟其他主流数据库一样，能够存储任何类型的数据，比如字符、数值和日期。而且，大多数应用程序中只会用到这3种数据。</p>
<h2>1. 字符数据</h2>
<p>1.1 字符数据分为字符型和文本型。字符型又分为两种，一是固定长度字符型（<strong>char</strong>），存储空间为255字节，不足空间以空格填充；另一种是可变长度字符型（<strong>varchar</strong>），存储空间为65 535字节，不足空间不用空格填充。在为表列定义字符类型时，必须指定最大字符数（英文每个字母占一个字节，汉字每个字占两个字节），不能超过相应类型的字节上限，例如：</p>
<p>char(40)    /* 固定长度字符列，最多可以保存40个英文字母或20个汉字 */<br />
char(280)    /* 无效，超过了255字节 */<br />
varchar(280) /* 可变长度字符列，最多可以保存280个英文字母或140个汉字 */</p>
<p>1.2 另外，在为表列指定数据类型的同时，可以同时指定列的字符集，例如：</p>
<p>varchar(20) <strong>character set</strong> utf8 /* UTF-8字符集，可以用于保存汉字等多字节字符 */</p>
<p>甚至，在创建数据库时也可以直接指定默认的字符集，例如：</p>
<p>create database myblog <strong>character set</strong> utf8;</p>
<p>1.3 对于要求存储空间大于64KB（64×1024=65 535字节）的列，就需要声明为文本型了。文本型又分为四种：短文本型（<strong>tinytext</strong>/255）、文本型（<strong>text</strong>/65 535）、中长文本型（<strong>mediumtext</strong>/16 777 215）和长文本型（<strong>longtext</strong>/4 294 967 295）。</p>
<p>由于MySQL提供了65 535字节长的可变长度字符型（<strong>varchar</strong>），因此短文本型（<strong>tinytext</strong>）和文本型（<strong>text</strong>）并不常用。</p>
<p>关于文本型数据，有以下说明：<br />
（1）如果实际文本超出相应类型指定的最大长度，则多余文本将被截掉；<br />
（2）如果实际文本不足相应类型指定的最大长度，则不会删除后面空格；</p>
<h2>2. 数值数据</h2>
<p>数值数据分为整数和浮点数（带小数点的数，有符号），而整数又分有符号数和无符号数（用于区分正负数）。MySQL中有5种整数数值类型：</p>
<p>较小整数（<strong>tinyint</strong>/-128~127或0~255）；<br />
小整数（<strong>smallint</strong>/-32 768~32 767或0~65 535）；<br />
中长整数（<strong>mediumint</strong>/-8 388 608~8 388 607或0~16 777 215）；<br />
整数（<strong>int</strong>/-2 147 483 648~2 147 483 647或0~4 294 967 295）；<br />
大整数（<strong>bigint</strong>/-9 223 372 036 854 775 808~9 223 372 036 854 775 807或0~18 446 744 073 709 551 615）。</p>
<p>声明整数类型列时，必须指定该列是有符号（signed）还是无符号（unsigned），例如：</p>
<p>smallint unsigned  /* 表示只保存正整数 */</p>
<p>有两种浮点数值类型：单精度浮点数，float(p,s)和双精度浮点数，double(p,s)。其中，p表示精度（小数点左右两侧的数字位数和），s表示至少保留几位小数。</p>
<h2>3.时间数据</h2>
<p>时间数据可以是日期、时间、日期加时间。MySQL有5种时间数据类型：</p>
<p>日期型：<strong>date</strong> YYYY-MM-DD 1000-01-01~9999-12-31<br />
日期时间型：<strong>datetime</strong> YYYY-MM-DD HH:MI:SS 1000-01-01 00:00:00~9999-12-31 23:59:59<br />
时间戳型：<strong>timestamp</strong> YYYY-MM-DD HH:MI:SS 1970-01-01 00:00:00 to 2037-12-31 23:59:59<br />
年型：<strong>year</strong> YYYY 1901 to 2155<br />
时间型：<strong>time</strong> HHH:MI:SS -838:59:59 to 838:59:59</p>
<p>其中，HHH:MI:SS中的HHH表示已经过去的小时数，而其他日期时间组件YYYY（年）、MM（月）、DD（日）的含义是可以一目了然的。</p>
<p>如果只想在某列中保存日期（年月日），则date即可满足需要；如果想保存日期和时间（年月日时分秒），则要使用<strong>datetime</strong>。<strong>timestamp</strong>与<strong>datatime</strong>的区别除表示的时间范围不同之外，是它的值可以在记录增加或被更新时自动生成。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cn-cuckoo.com/2009/11/07/mysql-data-type-1230.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>欢迎Goolge Clouse Tools开源</title>
		<link>http://www.cn-cuckoo.com/2009/11/06/welcome-google-clouse-tools-opened-1218.html</link>
		<comments>http://www.cn-cuckoo.com/2009/11/06/welcome-google-clouse-tools-opened-1218.html#comments</comments>
		<pubDate>Fri, 06 Nov 2009 08:23:14 +0000</pubDate>
		<dc:creator>为之漫笔</dc:creator>
				<category><![CDATA[Web开发]]></category>

		<guid isPermaLink="false">http://www.cn-cuckoo.com/?p=1218</guid>
		<description><![CDATA[今天（最早在Solidot.com看到，据这里说是今天），Google开发Gmail、Google Docs、Google Maps使用的前端开发工具开源了！ Google Code没有提供Clouse Library（JavaScript库）的打包下载，因此需要使用subversion客户端工具取出（check out）所有文件。我使用的是slik subversion，Google还给用户提供了一大堆subversion客户端工具。取出速度快得有点令人惊讶，几分钟就下载了126M。 svn checkout http://closure-library.googlecode.com/svn/trunk/ closure-library-read-only Web applications have evolved from simple HTML pages into rich, interactive applications that provide a great user experience. Today&#8217;s web apps pose a challenge for developers, however: how do you create and maintain efficient JavaScript code that downloads quickly and works across different [...]]]></description>
			<content:encoded><![CDATA[<p>今天（最早<a title="Google开源JavaScript工具" href="http://developers.solidot.org/article.pl?sid=09/11/06/015021" target="_blank">在Solidot.com看</a>到，据<a title="Google开放了其内部JS开发工具：Closure Tools" href="http://www.javaeye.com/news/11189-google-closure-tools-javascript" target="_blank">这里说是今天</a>），Google开发Gmail、Google Docs、Google Maps使用的前端开发工具开源了！</p>
<p>Google Code没有提供Clouse Library（JavaScript库）的打包下载，因此需要使用subversion客户端工具取出（check out）所有文件。我使用的是<a title="下载slik subversion客户端工作" href="http://sinaurl.cn/hfFXL" target="_blank">slik subversion</a>，Google还给用户提供了<a title="一大堆subverion客户端工具，可以选择下载" href="http://sinaurl.cn/hfFet" target="_blank">一大堆subversion客户端工具</a>。取出速度快得有点令人惊讶，几分钟就下载了126M。</p>
<pre style="font-family: monospace; color: #007000; font-size: 9pt; background-color: #fafafa; line-height: 15px; margin-top: 1em; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; overflow-x: auto; overflow-y: auto; word-wrap: break-word; padding: 0.99em; border: 1px solid #bbbbbb;">svn checkout http://closure-library.googlecode.com/svn/trunk/ closure-library-read-only</pre>
<p style="padding-top: 1em; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 16px; margin: 0px;"><a title="Closure Tools (Labs) " href="http://code.google.com/intl/zh-CN/closure/" target="_blank"><img class="alignleft colorbox-1218" style="margin:0 1em 1em 0" src="http://code.google.com/closure/images/logo128px.png" alt="" width="128" height="128" /></a>Web applications have evolved from simple HTML pages into rich, interactive applications that provide a great user experience. Today&#8217;s web apps pose a challenge for developers, however: how do you create and maintain efficient JavaScript code that downloads quickly and works across different browsers?</p>
<p style="padding-top: 1em; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 16px; margin: 0px;">The Closure tools help developers to build rich web applications with JavaScript that is both powerful and efficient. The Closure tools include:</p>
<h2>一个JavaScript优化工具</h2>
<p style="padding-top: 1em; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 16px; margin: 0px;">The <a style="color: #0000cc;" href="http://code.google.com/intl/zh-CN/closure/compiler/">Closure Compiler</a> compiles JavaScript into compact, high-performance code. The compiler removes dead code and rewrites and minimizes what&#8217;s left so that it downloads and runs quickly. It also also checks syntax, variable references, and types, and warns about common JavaScript pitfalls. These checks and optimizations help you write apps that are less buggy and easier to maintain. You can use the compiler with Closure Inspector, a Firebug extension that makes debugging the obfuscated code almost as easy as debugging the human-readable source.</p>
<h2 style="font-size: 1.5em;">一个JavaScript大型工具库</h2>
<p style="padding-top: 1em; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 16px; margin: 0px;">The <a style="color: #0000cc;" href="http://code.google.com/intl/zh-CN/closure/library/">Closure Library</a> is a broad, well-tested, modular, and cross-browser JavaScript library. You can pull just what you need from a large set of reusable UI widgets and controls, and from lower-level utilities for DOM manipulation, server communication, animation, data structures, unit testing, rich-text editing, and more.</p>
<p style="padding-top: 1em; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 16px; margin: 0px;">The Closure Library is server-agnostic, and is intended for use with the Closure Compiler.</p>
<h2>一个简易的模板系统：适用于JavaScript和Java</h2>
<p style="padding-top: 1em; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 16px; margin: 0px;"><a style="color: #0000cc;" href="http://code.google.com/intl/zh-CN/closure/templates/">Closure Templates</a> simplify the task of dynamically generating HTML. They have a simple syntax that is natural for programmers. In contrast to traditional templating systems, in which you use one big template per page, you can think of Closure Templates as small components that you compose to form your user interface.</p>
<p style="padding-top: 1em; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 16px; margin: 0px;">Closure Templates are implemented for both JavaScript and Java, so that you can use the same templates on both the server and client side. For the client side, Closure Templates are precompiled into efficient JavaScript.</p>
<p style="padding-top: 1em; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 16px; margin: 0px;">
]]></content:encoded>
			<wfw:commentRss>http://www.cn-cuckoo.com/2009/11/06/welcome-google-clouse-tools-opened-1218.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>史上最贵JavaScript代码</title>
		<link>http://www.cn-cuckoo.com/2009/07/22/the-most-expensive-javascript-in-the-world-1025.html</link>
		<comments>http://www.cn-cuckoo.com/2009/07/22/the-most-expensive-javascript-in-the-world-1025.html#comments</comments>
		<pubDate>Wed, 22 Jul 2009 13:09:44 +0000</pubDate>
		<dc:creator>为之漫笔</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[原创]]></category>

		<guid isPermaLink="false">http://www.cn-cuckoo.com/?p=1025</guid>
		<description><![CDATA[这个事儿有点意思，真假未知中——不过，当作个笑话看也未尝不可。 事件的前因后果是这样的： 最近，总部位于挪威奥斯陆的、国际领先的浏览器制造商Opera公司，因为预见Opera Mini（为手机用户节省流量的服务）、Opera Turbo（提供全网加速功能的服务）以及Opera Link（支持用户数据实时同步的服务）的访问量将会激增，批准了一项价值百万克朗（100克朗兑换106元人民币）的服务器采购计划。 于是，众多知名服务器厂商应邀把服务器样机发到Opera公司参加竞标测试。然而，来自一家国际一流厂商的服务器把包括CSS之父、Opera公司首席技术官Håkon Wium Lie博士在内的所有测试人员全部当场雷倒，造成了几乎到手的百万元大单顷刻间付之东流。 到底是为什么呢？原来，当测试人员启动这家厂商的服务器，并使用Opera浏览器打开管理页面时，却被直接重定向到了错误页面。当然，这只是问题的表面而已。重定向嘛，不是服务器端脚本所为，就是客户端脚本的杰作。经过简单查找，现场人员发现管理页面的源代码中赫然写着如下一行JavaScript代码： if (is.opera) { window.location.href=&#34;config/error.htm&#34;; } 把这行代码翻译成人类语言就是：如果查看当前页面的是Opera浏览器，就在窗口地址栏中打开config目录下的error.htm页面！ 呵呵，居然胆敢如此歧视Opera浏览器，就算制造商再牛，服务器再好，搁谁那里都没有通过“测试”的道理呀。就因为这一行代码，丢掉百万元大单，称其为史上最贵的JavaScript代码，应该不为过了。 （据说，这行代码是经销商所为；而这家国际一流服务器厂商也未公开，待查中。消息来源cnBeta.com）]]></description>
			<content:encoded><![CDATA[<p>这个事儿有点意思，真假未知中——不过，当作个笑话看也未尝不可。<a href="http://www.opera.com"><img class="alignleft colorbox-1025" src="http://tbn2.google.com/images?q=tbn:qHuq8u8Cn2Vz7M:http://mag.udn.com/html/it/PCHOMEADVANCE/200706/1132_7_opera.jpg" alt="" width="137" height="91" /></a></p>
<p>事件的前因后果是这样的：</p>
<p>最近，总部位于挪威奥斯陆的、<a title="http://www.opera.com/" href="http://www.opera.com/" target="_blank">国际领先的浏览器制造商Opera公司</a>，因为预见<a title="http://www.operachina.com/mini/" href="http://www.operachina.com/mini/" target="_blank">Opera Mini（为手机用户节省流量的服务）</a>、<a title="http://team.operachina.com/" href="http://team.operachina.com/" target="_blank">Opera Turbo（提供全网加速功能的服务）</a>以及<a title="http://www.operachina.com/discover/link.htm" href="http://www.operachina.com/discover/link.htm" target="_blank">Opera Link（支持用户数据实时同步的服务）</a>的访问量将会激增，批准了一项价值百万克朗（100克朗兑换106元人民币）的服务器采购计划。</p>
<p>于是，众多知名服务器厂商应邀把服务器样机发到Opera公司参加竞标测试。然而，来自一家国际一流厂商的服务器把包括CSS之父、Opera公司首席技术官<a title="http://people.opera.com/howcome/" href="http://people.opera.com/howcome/" target="_blank">Håkon Wium Lie博士</a>在内的所有测试人员全部当场雷倒，造成了几乎到手的百万元大单顷刻间付之东流。</p>
<p>到底是为什么呢？原来，当测试人员启动这家厂商的服务器，并使用Opera浏览器打开管理页面时，却被直接重定向到了错误页面。当然，这只是问题的表面而已。重定向嘛，不是服务器端脚本所为，就是客户端脚本的杰作。经过简单查找，现场人员发现管理页面的源代码中赫然写着如下一行JavaScript代码：</p>
<pre class="brush: js; ">

if (is.opera) { window.location.href=&quot;config/error.htm&quot;; }
</pre>
<p>把这行代码翻译成人类语言就是：如果查看当前页面的是Opera浏览器，就在窗口地址栏中打开config目录下的error.htm页面！</p>
<p>呵呵，居然胆敢如此歧视Opera浏览器，就算制造商再牛，服务器再好，搁谁那里都没有通过“测试”的道理呀。就因为这一行代码，丢掉百万元大单，称其为史上最贵的JavaScript代码，应该不为过了。</p>
<p>（据说，这行代码是经销商所为；而这家国际一流服务器厂商也未公开，待查中。<a title="http://www.cnbeta.com/articles/89239.htm" href="http://www.cnbeta.com/articles/89239.htm" target="_blank">消息来源cnBeta.com</a>）</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cn-cuckoo.com/2009/07/22/the-most-expensive-javascript-in-the-world-1025.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

