<?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>PlanABC - 怿飞’s Blog &#187; JS/Ajax/AS/Flex</title>
	<atom:link href="http://www.planabc.net/category/javascript-ajax/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.planabc.net</link>
	<description>落草为根—专注前端技术&#38;&#38;关注用户体验</description>
	<lastBuildDate>Sun, 31 Jan 2010 13:23:14 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>如何在事件代理中正确使用 focus 和 blur 事件</title>
		<link>http://www.planabc.net/2010/01/30/how_to_use_focus_and_blur_event_in_event_delegation/</link>
		<comments>http://www.planabc.net/2010/01/30/how_to_use_focus_and_blur_event_in_event_delegation/#comments</comments>
		<pubDate>Fri, 29 Jan 2010 17:36:59 +0000</pubDate>
		<dc:creator>怿飞</dc:creator>
				<category><![CDATA[JS/Ajax/AS/Flex]]></category>
		<category><![CDATA[event]]></category>

		<guid isPermaLink="false">http://www.planabc.net/?p=382</guid>
		<description><![CDATA[什么是事件代理（Event Delegation）？
如果不太了解的朋友，可详细阅读：《Event delegation in JavaScript》，这里不再累述。
首先让我们一起来回顾一些常识：

通常支持事件冒泡（Event Bubbling）的事件类型为鼠标事件和键盘事件，例如：mouseover, mouseout, click, keydown, keypress。
接口事件则通常不支持事件冒泡（Event Bubbling），例如：load, change, submit, focus, blur。

很明显：focus 和 blur 都属于不支持冒泡的接口事件。既然都不支持冒泡，那又如何实现事件代理呢？
可以换个角度，逆向思维，尝试事件捕获（Event Capturing，除了IE，现在流行的标准浏览器均支持）。
测试后会发现，如果你捕获 focus 或 blur 事件，目标元素的祖先元素均执行事件函数。至于为什么？或许是实现的一个 BUG。
el.addEventListener('focus', focusHandler, true);
el.addEventListener('blur', blurHandler, true);
那对于... ]]></description>
			<content:encoded><![CDATA[<p>什么是事件代理（Event Delegation）？</p>
<p>如果不太了解的朋友，可详细阅读：<a href="http://www.nczonline.net/blog/2009/06/30/event-delegation-in-javascript/" target="_blank" title="Event delegation in JavaScript">《Event delegation in JavaScript》</a>，这里不再累述。</p>
<p>首先让我们一起来回顾一些常识：</p>
<ol>
<li>通常支持事件冒泡（Event Bubbling）的事件类型为鼠标事件和键盘事件，例如：<strong>mouseover, mouseout, click, keydown, keypress</strong>。</li>
<li>接口事件则通常不支持事件冒泡（Event Bubbling），例如：<strong>load, change, submit, focus, blur</strong>。</li>
</ol>
<p>很明显：focus 和 blur 都属于不支持冒泡的接口事件。既然都不支持冒泡，那又如何实现事件代理呢？</p>
<p>可以换个角度，逆向思维，尝试事件捕获（Event Capturing，除了IE，现在流行的标准浏览器均支持）。</p>
<p>测试后会发现，如果你捕获 focus 或 blur 事件，目标元素的祖先元素均执行事件函数。至于为什么？或许是实现的一个 BUG。</p>
<pre><code>el.addEventListener('focus', focusHandler, true);
el.addEventListener('blur', blurHandler, true);</code></pre>
<p>那对于 IE ，我们如何实现呢？</p>
<p>非常幸运，IE 下支持 focusin 和 focusout 事件，非常类似于 focus 和 blur 事件，唯一不同的是，这两种事件支持事件冒泡（Event Bubbling）。</p>
<pre><code>el.onfocusin = focusHandler;
el.onfocusout = blurHandler;</code></pre>
<p>很完美的解决方案：</p>
<pre><code>if (document.addEventListener) {
    el.addEventListener('focus', focusHandler, true);
    el.addEventListener('blur', blurHandler, true);
} else {
    el.onfocusin = focusHandler;
    el.onfocusout = blurHandler;
}</code></pre>
<p>当你下次看到 <a href="http://developer.yahoo.com/yui/2/" title="YUI 2.8" target="_blank">YUI 2.8</a> 的 event/event-debug.js 源码中下面几段代码时，一定会清晰很多：</p>
<pre><code>576    // String constants used by the addFocusListener and removeFocusListener methods
577
578     FOCUSIN = "focusin",
579     FOCUSOUT = "focusout";

        ....

750     _specialTypes: {
751         focusin: (isIE ? "focusin" : "focus"),
752         focusout: (isIE ? "focusout" : "blur")
753      },

        ....

1053    addListener: function (el, sType, fn, obj, overrideContext) {
1054
1055	    var capture = ((sType == FOCUSIN || sType == FOCUSOUT) &#038;&#038; !YAHOO.env.ua.ie) ? true : false;
1056
1057        return this._addListener(el, this._getType(sType), fn, obj, overrideContext, capture);
1058
1059    },</code></pre>
<img src="http://www.planabc.net/?ak_action=api_record_view&id=382&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.planabc.net/2010/01/30/how_to_use_focus_and_blur_event_in_event_delegation/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>修复 jQuery 中 isFunction 方法的 BUG</title>
		<link>http://www.planabc.net/2010/01/23/repair_the_bug_of_isfunction_method_in_jquery/</link>
		<comments>http://www.planabc.net/2010/01/23/repair_the_bug_of_isfunction_method_in_jquery/#comments</comments>
		<pubDate>Sat, 23 Jan 2010 09:34:09 +0000</pubDate>
		<dc:creator>怿飞</dc:creator>
				<category><![CDATA[JS/Ajax/AS/Flex]]></category>
		<category><![CDATA[bug]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://www.planabc.net/?p=376</guid>
		<description><![CDATA[jQuery 1.4 源码 449 行（core.js 431 行），判断是否为函数的方法如下（思路来源于 Douglas Crockford 的《The Miller Device》）：
isFunction: function( obj ) {
    return toString.call(obj) === "[object Function]";
},
同时 jQuery 的作者也作了部分注释：
See test/unit/core.js for details concerning isFunction. Since version 1.3, DOM methods and functions like alert aren&#8217;t supported. They return false on IE (#2968).
即：此方法在 IE 下无法正确识别 DOM 方法和一些函数（例如 alert 方法等）。
为什么会这样呢？
详细看测试页面：http://www.planabc.net/demo/isfunction/
会发现在 IE [...... ]]></description>
			<content:encoded><![CDATA[<p><a href="http://github.com/jquery/jquery" title="JQuery 1.4" target="_blank">jQuery 1.4</a> 源码 449 行（core.js 431 行），判断是否为函数的方法如下（思路来源于 <a href="http://www.crockford.com/" title="Douglas Crockford" target="_blank">Douglas Crockford</a> 的《The Miller Device》）：</p>
<pre><code>isFunction: function( obj ) {
    return toString.call(obj) === "[object Function]";
},</code></pre>
<p>同时 jQuery 的作者也作了部分注释：</p>
<blockquote><p>See test/unit/core.js for details concerning isFunction. Since version 1.3, DOM methods and functions like alert aren&#8217;t supported. They return false on IE (#2968).</p></blockquote>
<p>即：此方法在 IE 下无法正确识别 DOM 方法和一些函数（例如 alert 方法等）。</p>
<p>为什么会这样呢？</p>
<p>详细看测试页面：<a href="http://www.planabc.net/demo/isfunction/">http://www.planabc.net/demo/isfunction/</a></p>
<p>会发现在 IE 下用 typeof 检测 alert、confirm 方法以及 DOM 的方法显示 object，而其他浏览器下显示 function。</p>
<p>那如何完善这个问题呢？</p>
<ol>
<li>typeof 检测某个方法（例如：document.getElementById） 是否是 object，如何是，则重写 isFunction 函数；</li>
<li>怎样重写呢？正则判断传入的对象字符串后（&#8221;" + fn），是否起始位置含有 function，即：/^\s*\bfunction\b/.test(&#8221; + fn)。</li>
</ol>
<p>OK，看下根据以上思路修改后的 isFunction 函数：</p>
<pre><code>var isFunction = (function() {
    // Performance optimization: Lazy Function Definition
    return "object"  === typeof document.getElementById ?
           isFunction = function(fn){
                try {
                    return /^\s*\bfunction\b/.test("" + fn);
                } catch (x) {
                    return false
                }
           }:
           isFunction = function(fn){
               return "[object Function]" === Object.prototype.toString.call(fn);
           };
})()</code></pre>
<p>参考阅读：</p>
<ul>
<li><a href="http://webreflection.blogspot.com/2009/08/isfunction-hacked-iscallable-solution.html" title="isFunction hacked, isCallable solution" target="_blank">《isFunction hacked, isCallable solution》</a></li>
<li><a href="http://dbj.org/dbj/?p=286" title="isFunction() or isObject(), that is the question ?" target="_blank">《isFunction() or isObject(), that is the question ? 》</a></li>
<li><a href="http://peter.michaux.ca/articles/lazy-function-definition-pattern" title="Lazy Function Definition Pattern" target="_blank">《Lazy Function Definition Pattern》</a></li>
</ul>
<img src="http://www.planabc.net/?ak_action=api_record_view&id=376&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.planabc.net/2010/01/23/repair_the_bug_of_isfunction_method_in_jquery/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>如何将函数的实际参数转换成数组</title>
		<link>http://www.planabc.net/2010/01/06/arguments_to_array/</link>
		<comments>http://www.planabc.net/2010/01/06/arguments_to_array/#comments</comments>
		<pubDate>Wed, 06 Jan 2010 10:21:18 +0000</pubDate>
		<dc:creator>怿飞</dc:creator>
				<category><![CDATA[JS/Ajax/AS/Flex]]></category>
		<category><![CDATA[arguments]]></category>
		<category><![CDATA[Array]]></category>

		<guid isPermaLink="false">http://www.planabc.net/?p=354</guid>
		<description><![CDATA[实际参数在函数中我们可以使用 arguments 对象获得 （注：形参可通过 arguments.callee 获得），虽然 arguments 对象与数组形似，但仍不是真正意义上的数组。
值得庆幸的是，我们可以通过数组的 slice 方法将 arguments 对象转换成真正的数组：
var args = Array.prototype.slice.call(arguments, 0);
对于slice 方法，ECMAScript 262 中 15.4.4.10 Array.prototype.slice (start, end) 章节有备注：
The slice function is intentionally generic; it does not require that its this value be an Array object. Therefore it can be transferred to other kinds of objects for use as a [...... ]]></description>
			<content:encoded><![CDATA[<p>实际参数在函数中我们可以使用 <code>arguments</code> 对象获得 （注：形参可通过 <code>arguments.callee</code> 获得），虽然 <code>arguments</code> 对象与数组形似，但仍不是真正意义上的数组。</p>
<p>值得庆幸的是，我们可以通过数组的 <code>slice</code> 方法将 <code>arguments</code> 对象转换成真正的数组：</p>
<pre><code>var args = Array.prototype.slice.call(arguments, 0);</code></pre>
<p>对于<code>slice</code> 方法，<a href="http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf" title="ECMAScript" target="_blank">ECMAScript 262</a> 中 15.4.4.10 Array.prototype.slice (start, end) 章节有备注：</p>
<blockquote><p>The slice function is intentionally generic; it does not require that its this value be an Array object. Therefore it can be transferred to other kinds of objects for use as a method. Whether the slice function can be applied successfully to a host object is implementation-dependent.</p></blockquote>
<p><a href="http://jsdesignpatterns.com/" target="_blank" title="Pro JavaScript Design Patterns">《Pro JavaScript Design Patterns》</a>（《JavaScript 设计模式》）的作者 <a href="http://www.dustindiaz.com/" title="Dustin Diaz: ./with Imagination" target="_blank">Dustin Diaz</a> 曾指出：</p>
<blockquote><p>
instead of…<br />
var args = Array.prototype.slice.call(arguments, 0); // 怿飞注：下称方法一<br />
do this…<br />
var args = [].slice.call(arguments, 0); // 怿飞注：下称方法二</p></blockquote>
<p>但二者的性能差异真的存在吗？经过个人简单测试发现：</p>
<p><del datetime="2010-01-30T07:44:07+00:00">在 <code>arguments.length</code> 较小的时候，方法二性能上稍有一点点优势，而在<code>arguments.length</code> 较大的时候，方法一却又稍有优势。</del></p>
<p>2010年1月30日更新（<a href="http://www.planabc.net/demo/toarray/arguments.html" target="_blank">测试地址</a>）：几经验证，性能差异不大，反而第一张方法性能稍优势一点，或许由于第二种方法创建新数组产生开销。</p>
<p>最后附上方法三，最老土的方式：</p>
<pre><code>var args = [];
for (var i = 1; i < arguments.length; i++) {
    args.push(arguments[i]);
}</code></pre>
<p>不过对于平常来说，个人建议使用第一种方法，但任何解决方案，没有最好的，只有最合适：</p>
<pre><code>var args = Array.prototype.slice.call(arguments, 0); </code></pre>
<p>------------------------------------------------------------------</p>
<p><strong>如何将 <a href="http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#ID-536297177" target="_blank" title="NodeList">NodeList</a> （比如：document.getElementsByTagName('div')）转换成数组呢？</strong></p>
<p>解决方案简单如下：</p>
<pre><code>function nodeListToArray(nodes){
    var arr, length;

    try {
        // works in every browser except IE
        arr = [].slice.call(nodes);
        return arr;
    } catch(err){
        // slower, but works in IE
        arr = [];
        length = nodes.length;

        for(var i = 0; i < length; i++){
             arr.push(nodes[i]);
         }  

        return arr;
    }
} </code></pre>
<p>为什么 IE 中 NodeList 不可以使用 [].slice.call(nodes) 方法转换呢？</p>
<blockquote><p>In Internet Explorer it throws an error that it can't run Array.prototype.slice.call(nodes) because a DOM NodeList is not a JavaScript object.</p></blockquote>
<img src="http://www.planabc.net/?ak_action=api_record_view&id=354&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.planabc.net/2010/01/06/arguments_to_array/feed/</wfw:commentRss>
		<slash:comments>23</slash:comments>
		</item>
		<item>
		<title>删除数组中重复项（uniq）</title>
		<link>http://www.planabc.net/2009/12/26/array_uniq/</link>
		<comments>http://www.planabc.net/2009/12/26/array_uniq/#comments</comments>
		<pubDate>Sat, 26 Dec 2009 11:08:03 +0000</pubDate>
		<dc:creator>怿飞</dc:creator>
				<category><![CDATA[JS/Ajax/AS/Flex]]></category>
		<category><![CDATA[Array]]></category>
		<category><![CDATA[uniq]]></category>
		<category><![CDATA[YUI]]></category>

		<guid isPermaLink="false">http://www.planabc.net/?p=338</guid>
		<description><![CDATA[首先让我们看下 YUI 是如何处理的：
var toObject = function(a) {
    var o = {};
    for (var i = 0; i < a.length; i = i+1) {
     o[a[i]] = true;
    }
    return o;
};

var keys = function(o) {
    var a=[], i;
 [...... ]]></description>
			<content:encoded><![CDATA[<p>首先让我们看下 <a href="http://developer.yahoo.com/yui/" target="_blank" title="YUI">YUI</a> 是如何处理的：</p>
<pre><code>var toObject = function(a) {
    var o = {};
    for (var i = 0; i < a.length; i = i+1) {
     o[a[i]] = true;
    }
    return o;
};

var keys = function(o) {
    var a=[], i;
    for (i in o) {
        if (lang.hasOwnProperty(o, i)) { // YUI的方法
            a.push(i);
        }
    }
    return a;
};

var uniq = function(a) {
    return keys(toObject(a));
};</code></pre>
<p>详细分析，见同事 <a href="http://www.mytcer.com/" title="长天">长天</a> 的分享 <a href="http://www.mytcer.com/357" target="_blank" title="巧妙去除数组中的重复项">《巧妙去除数组中的重复项》</a>。</p>
<p>自己使用的方式与 <a href="http://developer.yahoo.com/yui/" target="_blank" title="YUI">YUI</a> 的方式十分相似，不过仅使用了一次循环便完成了删除数组中重复项，如下：</p>
<pre><code>var uniq = function (arr) {
    var a = [],
        o = {},
        i,
        v,
        len = arr.length;

    if (len < 2) {
        return arr;
    }

    for (i = 0; i < len; i++) {
        v = arr[i];
        if (o[v] !== 1) {
            a.push(v);
            o[v] = 1;
        }
    }

    return a;
}</code></pre>
<p>经过了简单的测试：自己使用的方式性能远远高于 <a href="http://developer.yahoo.com/yui/" target="_blank" title="YUI">YUI</a> 的方式。</p>
<p>抛砖引玉，欢迎大家提供更好的处理方法。</p>
<p><strong>2009年12月28日更新：</strong></p>
<p>以上两种函数方法暂时都不能处理复杂的含有混合类型的数组（感谢 小猫 提出的疑问），如：[0,"0",1,"1",0]、["null",null]。</p>
<p>对于能够约定类型为数字（注：要求非0开头的数字，小数除外）或字符串的数组，我们可以用改进后的函数方法（感谢 <a href="http://cfanseal.cnblogs.com/" target="_blank" title="closurecache">closurecache</a> 提供的思路）：</p>
<pre><code>var uniq = function (arr) {
    var a = [],
        o = {},
        i,
        v,
        cv, // corrected value
        len = arr.length;

    if (len < 2) {
        return arr;
    }

    for (i = 0; i < len; i++) {
        v = arr[i];

        /* closurecache 提供的函数中使用的是  cv = v + 0;，
         * 这样就无法辨别类似[1, 10, "1", "10"]的数组，
         * 因为运算后 => 1, 10, 10, 100，很明显，出现了重复的标示符。
         * 加前面就难道没问题吗？
         * 有的：数组中不能出现类似01 、001，以 0 开头的数字，
         * 但适用性比原先更广。
         */
        cv = 0 + v;

        if (!o[cv]) {
            a.push(v);
            o[cv] = true;
        }
    }

    return a;
}</code></pre>
<p>如果大家想在此解题思路的基础上，更完美一点，推荐 <a href="http://www.limboy.com/" title="Dexter.Yy" target="_blank">Dexter.Yy</a> 的方法，进行类型判断，给予唯一标示符，详见 <a href="http://www.planabc.net/2009/12/26/array_uniq/#comment-5779" target="_blank">评论 20 楼</a>。</p>
<p><strong>没有最好，只有最合适的方式</strong>，其实使用 Array.indexOf() 的思路也是不错的选择，对于已经支持的浏览器直接用原生的 Array.indexOf() 方法，对于未支持的，我们增加 Array.indexOf() 方法，如下：</p>
<pre><code>if(!Array.prototype.indexOf) {
    Array.prototype.indexOf = function (obj, fromIndex) {
        if (fromIndex == null) {
            fromIndex = 0;
        } else if (fromIndex < 0) {
            fromIndex = Math.max(0, this.length + fromIndex);
        }

        for (var i = fromIndex; i < this.length; i++) {
            if (this[i] === obj)
                return i;
            }
        return -1;
    };
}</code></pre>
<p>接下来，实现的过程就非常简单了。</p>
<p>对于使用 Array.indexOf() 方法实现方案的优化提示：找到相同值时，从数组中移除，以减少下次遍历的量。</p>
<img src="http://www.planabc.net/?ak_action=api_record_view&id=338&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.planabc.net/2009/12/26/array_uniq/feed/</wfw:commentRss>
		<slash:comments>30</slash:comments>
		</item>
		<item>
		<title>Firefox 的 Jetpack 扩展案例分析：Gmail 邮件提醒</title>
		<link>http://www.planabc.net/2009/10/14/jetpack_gmail_checker/</link>
		<comments>http://www.planabc.net/2009/10/14/jetpack_gmail_checker/#comments</comments>
		<pubDate>Wed, 14 Oct 2009 10:11:27 +0000</pubDate>
		<dc:creator>怿飞</dc:creator>
				<category><![CDATA[JS/Ajax/AS/Flex]]></category>
		<category><![CDATA[Firfox]]></category>
		<category><![CDATA[gmail]]></category>
		<category><![CDATA[Jetpack]]></category>

		<guid isPermaLink="false">http://www.planabc.net/?p=317</guid>
		<description><![CDATA[Gtalk 软件的最下方有个很好又很实用的功能，就是 Gmail 邮件提醒功能。会定时更新你 Gmail 中未读新邮件的数量。

试想如果我们将此功能移植到 Firefox 上一定有趣！
第一步，在状态栏中显示图标和数据。
通过 《如何创建 Firefox 的 Jetpack 扩展》 这篇文章，我们可以轻易的创建：
jetpack.statusBar.append({
    html: '&#60;img src="http://mail.google.com/mail/images/favicon.ico"/&#62;&#60;span id="count"&#62;&#60;/span&#62;', //Gmail邮件图标和未读新邮件数
    width: 55, //状态栏上的宽度为55
    onReady: function(widget) {
        $("#count", widget).css({ //给未读新邮件数添加样式
            [...... ]]></description>
			<content:encoded><![CDATA[<p>Gtalk 软件的最下方有个很好又很实用的功能，就是 Gmail 邮件提醒功能。会定时更新你 Gmail 中未读新邮件的数量。</p>
<p><img src="http://www.planabc.net/wp-content/uploads/2009/10/gmail01.png" alt="Gtalk" /></p>
<p>试想如果我们将此功能移植到 Firefox 上一定有趣！</p>
<p><strong>第一步，在状态栏中显示图标和数据。</strong></p>
<p>通过 <a href="http://www.planabc.net/2009/10/13/build_firefox_extensions_with_jetpack/" title="如何创建 Firefox 的 Jetpack 扩展" target="_blank">《如何创建 Firefox 的 Jetpack 扩展》</a> 这篇文章，我们可以轻易的创建：</p>
<pre><code>jetpack.statusBar.append({
    html: '&lt;img src="http://mail.google.com/mail/images/favicon.ico"/&gt;&lt;span id="count"&gt;&lt;/span&gt;', //Gmail邮件图标和未读新邮件数
    width: 55, //状态栏上的宽度为55
    onReady: function(widget) {
        $("#count", widget).css({ //给未读新邮件数添加样式
            cursor: "pointer",
            paddingLeft:"4px",
            fontFamily: "Tahoma, Arial, sans-serif",
            verticalAlign: "top",
            fontSize: "10px",
            lineHeight:"18px",
        });
    }
});</code></pre>
<p><strong>第二步，获取 Gmail 的数据，更新未读新邮件数。</strong></p>
<p>可以通过 Gmail 邮件的 Feed 获得（需登录）：<a href="https://mail.google.com/mail/feed/atom" target="_blank">https://mail.google.com/mail/feed/atom</a></p>
<p>Feed 源码中的 fullcount 标签是用来记录当前的未读新邮件数。</p>
<p>OK，首先数据源有了。接着，我们使用再熟悉不过的 Ajax 技术，获取到数据并赋给指定的元素。</p>
<pre><code>function update(widget) {
    var widget = $(widget)；

    $.get("https://mail.google.com/mail/feed/atom", function(xml) {
        var el = $(xml).find("fullcount"); // 记录未读新邮件数的节点
        if(el){
            var newcount = parseInt(el.get(0).textContent);
            widget.find("#count").text(newcount); //赋给指定的元素
        } else { //如果未登录，显示“Login”
            widget.find("#count").text( "Login" );
	}
    });
}</code></pre>
<p>我们还可以通过进行一些优化：比如当未读新邮件数大于原来的邮件数时，增加提示信息等。<br />
提示信息这里使用 <code>jetpack.notifications.show(options)</code> 方法，options 参数有三个属性：title (String)：通知的标题；icon (URL)：通知 icon 的 URL；body (String)：通知的主题内容。</p>
<p>优化后的代码如下：</p>
<pre><code>var count = 0;

function update(widget) {
    var widget = $(widget),
        notify = function(msg) { // 定义通知的公用方法
            jetpack.notifications.show({
                title: "Gmail",
                body: msg,
                icon: "http://mail.google.com/mail/images/favicon.ico"
            });
        };

    $.get("https://mail.google.com/mail/feed/atom", function(xml) {
        var el = $(xml).find("fullcount"); // 记录未读新邮件数的节点
        if(el){
            var newcount = parseInt(el.get(0).textContent);
            if(newcount > count) { // 如果未读新邮件数大于原来的邮件数，则提示来自哪里
                var sender = $(xml).find("name").get(0).textContent;
                notify("New message from "+sender);
            }
            count = newcount;
            widget.find("#count").text(count); //赋给指定的元素

        } else { //如果未登录，提示登录
            widget.find("#count").text( "Login" );
            notify("Please login to Gmail");
	}
    });
}</code></pre>
<p><strong>第三步：设置定时更新数据。</strong></p>
<p>我们设置每 1 分钟更新一次数据：</p>
<pre><code>setInterval( function() { update(widget) }, 60*1000 );</code></pre>
<p><strong>第四步：设置点击扩展后的链接窗口。</strong></p>
<pre><code>$(widget).click(function() { //设置点击扩展后的链接窗口
    jetpack.tabs.open("http://mail.google.com");
    jetpack.tabs[ jetpack.tabs.length-1 ].focus();
});</code></pre>
<p><code>jetpack.tabs</code> 为浏览器窗口的标签对象，<code>.open(url)</code> 为新打开浏览器窗口标签的方法，<code>.focus()</code>为选中此标签为当前标签的方法。</p>
<p>OK，Firefox 的 Jetpack 扩展——Gmail 邮件提醒，经过简单的四步轻松完成。</p>
<p>全部代码如下：</p>
<pre><code>var count = 0;

function update(widget) {
    var widget = $(widget),
        notify = function(msg) { // 定义通知的公用方法
            jetpack.notifications.show({
                title: "Gmail",
                body: msg,
                icon: "http://mail.google.com/mail/images/favicon.ico"
            });
        };

    $.get("https://mail.google.com/mail/feed/atom", function(xml) {
        var el = $(xml).find("fullcount"); // 记录未读新邮件数的节点
        if(el){
            var newcount = parseInt(el.get(0).textContent);
            if(newcount > count) { // 如果未读新邮件数大于原来的邮件数，则提示来自哪里
                var sender = $(xml).find("name").get(0).textContent;
                notify("New message from "+sender);
            }
            count = newcount;
            widget.find("#count").text(count); //赋给指定的元素

        } else { //如果未登录，提示登录
            widget.find("#count").text( "Login" );
            notify("Please login to Gmail");
	}
    });
}

jetpack.statusBar.append({
    html: '&lt;img src="http://mail.google.com/mail/images/favicon.ico"/&gt;&lt;span id="count"&gt;&lt;/span&gt;', //Gmail邮件图标和未读新邮件数
    width: 40, //状态栏上的宽度为40，预留3位数的宽度
    onReady: function(widget) {
        $("#count", widget).css({ //给未读新邮件数添加样式
            cursor: "pointer",
            paddingLeft:"4px",
            fontFamily: "Tahoma, Arial, sans-serif",
            verticalAlign: "top",
            fontSize: "10px",
            lineHeight:"18px",
        });

        $(widget).click(function() { //设置点击扩展后的链接窗口
            jetpack.tabs.open("http://mail.google.com");
            jetpack.tabs[ jetpack.tabs.length-1 ].focus();
        });

        update(widget);
	setInterval( function() {update(widget) }, 60*1000 );
    }
});</code></pre>
<p>测试Demo：<a href="http://www.planabc.net/lab/jetpack/gmail/" target="blank" title="Gmail 邮件提醒">http://www.planabc.net/lab/jetpack/gmail/</a></p>
<p>对于 Jetpack 详细的 API，可以阅读 about:jetpack 页面的 API Reference 标签部分。</p>
<p>案例源码来自：<a href="https://jetpack.mozillalabs.com/demos/gmail-checker.js" target="_blank">https://jetpack.mozillalabs.com/demos/gmail-checker.js</a></p>
<img src="http://www.planabc.net/?ak_action=api_record_view&id=317&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.planabc.net/2009/10/14/jetpack_gmail_checker/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>如何创建 Firefox 的 Jetpack 扩展</title>
		<link>http://www.planabc.net/2009/10/13/build_firefox_extensions_with_jetpack/</link>
		<comments>http://www.planabc.net/2009/10/13/build_firefox_extensions_with_jetpack/#comments</comments>
		<pubDate>Tue, 13 Oct 2009 09:31:41 +0000</pubDate>
		<dc:creator>怿飞</dc:creator>
				<category><![CDATA[JS/Ajax/AS/Flex]]></category>
		<category><![CDATA[Firfox]]></category>
		<category><![CDATA[Jetpack]]></category>

		<guid isPermaLink="false">http://www.planabc.net/?p=304</guid>
		<description><![CDATA[Firefox 的 Jetpack 可以让我们很轻松地创建 Firefox 插件，仅通过已掌握的前端技能（HTML/CSS/JS），估计让人更兴奋的一点—— Jetpack 还集成了 jQuery 框架。
Adobe Air 也好，Web OS 也好， Jetpack 也好，至少让我们肯定一点，前端的价值将会在机遇中越来越大的被展现。
下面让我们一起来看看如何一步步创建你的第一个 Firefox 的 Jetpack 扩展：
第一步：安装 Jetpack 插件
Jetpack 插件地址：https://jetpack.mozillalabs.com/install.html
安装完成 Jetpack 插件后，你就可以通过在地址栏中输入 about:jetpack 来访问 Jetpack 本地界面了。

第二步：创建 planabc.js 文件。
planabc.js 的详细代码为：
jetpack.statusBar.append({
    html: '&#60;img src="http://www.planabc.net/favicon.ico"/&#62;',
    width: 16,
    onReady: function(widget){
        [...... ]]></description>
			<content:encoded><![CDATA[<p>Firefox 的 <a href="https://jetpack.mozillalabs.com/index.html" title="Mozilla Labs Jetpack | Exploring new ways to extend and personalize the Web" target="_blank">Jetpack</a> 可以让我们很轻松地创建 Firefox 插件，仅通过已掌握的前端技能（HTML/CSS/JS），估计让人更兴奋的一点—— Jetpack 还集成了 jQuery 框架。</p>
<p>Adobe Air 也好，Web OS 也好， Jetpack 也好，至少让我们肯定一点，前端的价值将会在机遇中越来越大的被展现。</p>
<p>下面让我们一起来看看如何一步步创建你的<a href="http://www.planabc.net/lab/jetpack/planabc/" target="_blank" title=" Firefox 的 Jetpack 扩展">第一个 Firefox 的 Jetpack 扩展</a>：</p>
<p><strong>第一步：安装 Jetpack 插件</strong></p>
<p>Jetpack 插件地址：<a href="https://jetpack.mozillalabs.com/install.html" target="_blank" title="Jetpack ">https://jetpack.mozillalabs.com/install.html</a></p>
<p>安装完成 Jetpack 插件后，你就可以通过在地址栏中输入 <code>about:jetpack</code> 来访问 Jetpack 本地界面了。</p>
<p><img src="http://www.planabc.net/wp-content/uploads/2009/10/jetpack01.png" alt="about:jetpack" title="about:jetpack" /></p>
<p><strong>第二步：创建 planabc.js 文件。</strong></p>
<p><a href="http://www.planabc.net/lab/jetpack/planabc/planabc.js" target="_blank" title="planabc.js">planabc.js</a> 的详细代码为：</p>
<pre><code>jetpack.statusBar.append({
    html: '&lt;img src="http://www.planabc.net/favicon.ico"/&gt;',
    width: 16,
    onReady: function(widget){
        $(widget).click(function(){
            jetpack.tabs.focused.contentWindow.location = "http://www.planabc.net/";
        });
    }
});</code></pre>
<p><code>jetpack.statusBar.append</code> 将执行 JavaScript 对象（该JavaScript 对象有四个属性：html、url、width 和 onReady）。</p>
<ul>
<li>html 属性：定义初始的 HTML，将显示在状态栏。此样例中，将显示一个简单的 IMG 元素。</li>
<li>url 属性：定义将在状态栏上显示的外部 HTML 内容的 URL。此样例中，未使用该属性。</li>
<li>width 属性：定义内容在状态栏上的宽度（单位：像素）。此样例中，定义为 16 像素，也就是  IMG 元素本身的宽度。</li>
<li>onReady 属性：定义被调用的函数（一旦状态栏被创建，此函数将会被调用）。由于 Jetpack 集成了 jQuery 框架，所以可以直接使用 jQuery 的属性和方法。在此样例中定义了这样一个函数，当点击该 Jetpack 扩展时，我们将修改 <code>jetpack.tabs.focused.contentWindow.location</code> 属性为 <code>http://www.planabc.net/</code>。<code>jetpack.tabs.focused.contentWindow</code> 对象相当于 window 对象，你可以访问通过 JavaScript 访问网页。</li>
</ul>
<p><strong>第三步：测试 planabc.js 代码。</strong></p>
<p>通过在地址栏中输入 <code>about:jetpack</code> 访问到 Jetpack 本地界面，点击 Develop 标签，然后将 planabc.js 文件中的代码拷贝到页面上的输入框中。点击 “try out this code” 按钮，你将会看到一个新的 icon 出现在 Firefox 窗口的右下角。</p>
<p>Develop 非常方便在代码部署前，在 Firefox 中测试你的代码。</p>
<p><img src="http://www.planabc.net/wp-content/uploads/2009/10/jetpack02.png" alt="Develop" title="Develop" /></p>
<p><strong>第四步：部署 Jetpack 扩展。</strong></p>
<p>创建一个简单的页面，在页面的 HEAD 元素内添加如下的 LINK 元素：</p>
<pre><code>&lt;link rel="jetpack" href="planabc.js" name="怿飞的博客"/&gt;</code></pre>
<p><a href="http://www.planabc.net/lab/jetpack/planabc/index.html" target="_blank" >HTML 文件</a>源码如下：</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html&gt;
    &lt;head&gt;
        &lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8" /&gt;
        &lt;title&gt;Mozilla Jetpack 案例&lt;/title&gt;
        &lt;link rel="jetpack" href="planabc.js" name="怿飞的博客"/&gt;
    &lt;/head&gt;
    &lt;body&gt;
        &lt;a href="http://www.planabc.net/2009/10/13/build_firefox_extensions_with_jetpack/"&gt;《如何创建 Firefox 的 Jetpack 扩展》 &lt;/a&gt;
    &lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>最后，将 HTML 文件和 planabc.js 文件都上传到服务器。</p>
<p><strong>第五步：安装 Jetpack 扩展。</strong></p>
<p>在 Firefox 中浏览该 HTML 页面时，Jetpack 插件将会在屏幕的最上方显示一个安装条，点击 “install” 按钮。将会提示安装不受信任的特性，点击 “I know what I&#8217;m doing. Install It!” 按钮。</p>
<p>安装完成和第三步测试一样，将会看到一个新的 icon 出现在 Firefox 窗口的右下角。如果此时你发现状态栏有2个相同的新 icon，那意味着原先的测试代码依然还在 about:jetpack 页面的 Develop 标签页中，清空输入框的代码即可消除。</p>
<p>返回到 about:jetpack 页面，点击 Installed Features 标签，将在列表中显示有新安装的 Jetpack 扩展。</p>
<p><strong>测试Demo：</strong><a href="http://www.planabc.net/lab/jetpack/planabc/" target="_blank" title=" Firefox 的 Jetpack 扩展">http://www.planabc.net/lab/jetpack/planabc/</a></p>
<img src="http://www.planabc.net/?ak_action=api_record_view&id=304&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.planabc.net/2009/10/13/build_firefox_extensions_with_jetpack/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>判断 iframe 是否加载完成的完美方法</title>
		<link>http://www.planabc.net/2009/09/22/iframe_onload/</link>
		<comments>http://www.planabc.net/2009/09/22/iframe_onload/#comments</comments>
		<pubDate>Tue, 22 Sep 2009 03:06:38 +0000</pubDate>
		<dc:creator>怿飞</dc:creator>
				<category><![CDATA[JS/Ajax/AS/Flex]]></category>
		<category><![CDATA[iframe]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[load]]></category>

		<guid isPermaLink="false">http://www.planabc.net/?p=297</guid>
		<description><![CDATA[一般来说，我们判断 iframe 是否加载完成其实与 判断 JavaScript 文件是否加载完成 采用的方法很类似：
var iframe = document.createElement("iframe");
iframe.src = "http://www.planabc.net";

if (!/*@cc_on!@*/0) { //if not IE
    iframe.onload = function(){
        alert("Local iframe is now loaded.");
    };
} else {
    iframe.onreadystatechange = function(){
        if [...... ]]></description>
			<content:encoded><![CDATA[<p>一般来说，我们判断 iframe 是否加载完成其实与 <a href="http://www.planabc.net/2008/10/31/javascript_ready_onload/" title="如何判断脚本加载完成 " target="_blank">判断 JavaScript 文件是否加载完成</a> 采用的方法很类似：</p>
<pre><code>var iframe = document.createElement("iframe");
iframe.src = "http://www.planabc.net";

if (!/*@cc_on!@*/0) { //if not IE
    iframe.onload = function(){
        alert("Local iframe is now loaded.");
    };
} else {
    iframe.onreadystatechange = function(){
        if (iframe.readyState == "complete"){
            alert("Local iframe is now loaded.");
        }
    };
}

document.body.appendChild(iframe);</code></pre>
<p>最近， <a href="http://www.nczonline.net/" title="NCZOnline" target="_blank">Nicholas C. Zakas</a> 文章<a href="http://www.nczonline.net/blog/2009/09/15/iframes-onload-and-documentdomain/" title="Iframes, onload, and document.domain" target="_blank">《Iframes, onload, and document.domain》</a>的评论中 Christopher 提供了一个新的判断方法（很完美）：</p>
<pre><code>var iframe = document.createElement("iframe");
iframe.src = "http://www.planabc.net";

if (iframe.attachEvent){
    iframe.attachEvent("onload", function(){
        alert("Local iframe is now loaded.");
    });
} else {
    iframe.onload = function(){
        alert("Local iframe is now loaded.");
    };
}

document.body.appendChild(iframe);</code></pre>
<p>几点补充说明：</p>
<ol>
<li><a href="http://msdn.microsoft.com/en-us/library/cc197055(VS.85).aspx" target="_blank" title="onload Event (BODY, FRAME, FRAMESET, ...)<br />
">IE 支持 iframe 的 onload 事件</a>，不过是隐形的，需要通过 attachEvent 来注册。</li>
<li>第二种方法比第一种方法更完美，因为 readystatechange 事件相对于 load 事件有一些潜在的问题。</li>
</ol>
<img src="http://www.planabc.net/?ak_action=api_record_view&id=297&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.planabc.net/2009/09/22/iframe_onload/feed/</wfw:commentRss>
		<slash:comments>24</slash:comments>
		</item>
		<item>
		<title>YUI Compressor 组件压缩 JavaScript 的一些原理</title>
		<link>http://www.planabc.net/2009/08/02/javascript-compression_with_yui_compressor/</link>
		<comments>http://www.planabc.net/2009/08/02/javascript-compression_with_yui_compressor/#comments</comments>
		<pubDate>Sun, 02 Aug 2009 08:40:39 +0000</pubDate>
		<dc:creator>怿飞</dc:creator>
				<category><![CDATA[JS/Ajax/AS/Flex]]></category>
		<category><![CDATA[compressor]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[YUI]]></category>

		<guid isPermaLink="false">http://www.planabc.net/?p=287</guid>
		<description><![CDATA[YUI Compressor 压缩 JavaScript 的内容包括：

移除注释
移除额外的空格
细微优化
标识符替换（Identifier Replacement）

YUI Compressor 包括哪些细微优化呢？

object["property"] ，如果属性名是合法的 JavaScript 标识符（注：合法的 JavaScript 标识符——由一个字母开头，其后选择性地加上一个或者多个字母、数字或下划线）且不是保留字，将优化为： object.property
{"property":123} ，如果属性名是合法的 JavaScript 标识符且不是保留字，将优化为 {property:123} （注：在对象字面量中，如果属性名是一个合法的 JavaScript 标识符且不是保留字，并不强制要求用引号引住属性名）。
'abcd\'efgh'，将优化为 "abcd'efgh"。
"abcd" + "efgh"，如果是字符串相连接，将优化成 "abcdefgh"（注：所有在使用 YUI Compressor 的前提下，对于脚本中的字符串连接，使用连接符 &#8220;+&#8221; 的效率和可维护性最高... ]]></description>
			<content:encoded><![CDATA[<p><a href="http://developer.yahoo.com/yui/compressor/" target="_blank" title="YUI Compressor">YUI Compressor</a> 压缩 JavaScript 的内容包括：</p>
<ol>
<li>移除注释</li>
<li>移除额外的空格</li>
<li>细微优化</li>
<li>标识符替换（Identifier Replacement）</li>
</ol>
<p><a href="http://developer.yahoo.com/yui/compressor/" target="_blank" title="YUI Compressor">YUI Compressor</a> 包括哪些细微优化呢？</p>
<ul>
<li><code>object["property"]</code> ，如果属性名是合法的 JavaScript 标识符（注：合法的 JavaScript 标识符——由一个字母开头，其后选择性地加上一个或者多个字母、数字或下划线）且不是保留字，将优化为： <code>object.property</code></li>
<li><code>{"property":123} </code>，如果属性名是合法的 JavaScript 标识符且不是保留字，将优化为 <code>{property:123}</code> （注：在对象字面量中，如果属性名是一个合法的 JavaScript 标识符且不是保留字，并不强制要求用引号引住属性名）。</li>
<li><code>'abcd\'efgh'</code>，将优化为 <code>"abcd'efgh"</code>。</li>
<li><code>"abcd" + "efgh"</code>，如果是字符串相连接，将优化成 <code>"abcdefgh"</code>（注：所有在使用 YUI Compressor 的前提下，对于脚本中的字符串连接，使用连接符 &#8220;+&#8221; 的效率和可维护性最高）。</li>
</ul>
<p>对于 JavaScript 最有效的压缩优化，当属<strong>标识符替换</strong>。</p>
<p>比如：</p>
<pre><code>(function(){
    function add(num1, num2) {
        return num1 + num2;
    }
})();</code></pre>
<p>进行属标识符替换后：</p>
<pre><code>(function(){
    function A(C, B) {
        return C+ B;
    }
})();</code></pre>
<p>再移除额外的空格，最终成了：</p>
<pre><code>(function(){function A(C,B){return C+B;}})();</code></pre>
<p><a href="http://developer.yahoo.com/yui/compressor/" target="_blank" title="YUI Compressor">YUI Compressor</a> 标识符替换仅替换<strong>函数名和变量名</strong>，那哪些不能被替代呢？</p>
<ol>
<li>原始值：字符串、布尔值、数字、null 和 undefined。一般来说字符串占的空间最多，而非数字字面量其次（true、false，null，underfinded）。</li>
<li>全局变量：window、document、XMLHttpRequest等等。使用最多的就是 document、window。</li>
<li>属性名，比如：foo.bar。占据的空间仅次于字符串，&#8221;.&#8221; 操作符无法被代替，且 a.b.c 更加费空间。</li>
<li>关键字。经常被过度使用的关键字有：var、return。最好的优化方法：一个函数仅出现一次 var 和 return 关键字。</li>
</ol>
<p>对于原始值、全局变量、属性名的优化处理方式大致相同：<strong>任何字面量值、全局变量或者属性名被使用超过 2 次（包括2次），都应该用局部变量存储代替。</strong></p>
<p>但有部分情况下是禁止使用标识符替换的：</p>
<ol>
<li>使用 eval() 函数。解决方法：不使用或者创建一个全局函数封装 eval()。</li>
<li>使用 with 语句。解决方法：方法同上。</li>
<li>JScript 的条件注释。唯一解决的方法：不使用。</li>
</ol>
<p>由于 <a href="http://developer.yahoo.com/yui/compressor/" target="_blank" title="YUI Compressor">YUI Compressor</a> 是建立在 <a href="http://www.mozilla.org/rhino/" target="_blank" title="Rhino: JavaScript for Java">rhino interpreter</a> 基础上的，所以上述所有的优化都是安全的。</p>
<p>扩展阅读：</p>
<ul>
<li><a href="http://www.slideshare.net/nzakas/extreme-javascript-compression-with-yui-compressor" target="_blank" title="Extreme JavaScript Compression With YUI Compressor">《Extreme JavaScript Compression With YUI Compressor》</a></li>
</ul>
<img src="http://www.planabc.net/?ak_action=api_record_view&id=287&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.planabc.net/2009/08/02/javascript-compression_with_yui_compressor/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>模拟兼容性的 addDOMLoadEvent 事件</title>
		<link>http://www.planabc.net/2009/07/30/adddomloadevent/</link>
		<comments>http://www.planabc.net/2009/07/30/adddomloadevent/#comments</comments>
		<pubDate>Thu, 30 Jul 2009 06:46:49 +0000</pubDate>
		<dc:creator>怿飞</dc:creator>
				<category><![CDATA[JS/Ajax/AS/Flex]]></category>
		<category><![CDATA[DOM]]></category>
		<category><![CDATA[event]]></category>

		<guid isPermaLink="false">http://www.planabc.net/?p=268</guid>
		<description><![CDATA[由于 window.onload 事件需要在页面所有内容（包括图片等）加载完后，才执行，但往往我们更希望在 DOM 一加载完就执行脚本。其实在现在大部分主流浏览器上（Firefox 3+，Opera 9+，Safari 3+，Chrome 2+）都提供了这一事件方法：addDOMLoadEvent。
document.addEventListener("DOMContentLoaded", init, false);
那对于 IE 我们如何模拟 addDOMLoadEvent 事件呢？
Matthias Miller 最早提供了如下的解决方案：
// for Internet Explorer (using conditional comments)
/*@cc_on @*/
/*@if (@_win32)
document.write(&#34;&#60;script id=__ie_onload defer src=javascript:void(0)&#62;&#60;\/script&#62;&#34;);
var script = document.getElementById("__ie_onload");
script.onreadystatechange = function() {
    if (this.readyState == "complete") {
        init(); // call the onload handler
 [...... ]]></description>
			<content:encoded><![CDATA[<p>由于 <code>window.onload</code> 事件需要在页面所有内容（包括图片等）加载完后，才执行，但往往我们更希望在 DOM 一加载完就执行脚本。其实在现在大部分主流浏览器上（Firefox 3+，Opera 9+，Safari 3+，Chrome 2+）都提供了这一事件方法：<code>addDOMLoadEvent</code>。</p>
<pre><code>document.addEventListener("DOMContentLoaded", init, false);</code></pre>
<p>那对于 IE 我们如何模拟 addDOMLoadEvent 事件呢？</p>
<p>Matthias Miller 最早提供了如下的解决方案：</p>
<pre><code>// for Internet Explorer (using conditional comments)
/*@cc_on @*/
/*@if (@_win32)
document.write(&quot;&lt;script id=__ie_onload defer src=javascript:void(0)&gt;&lt;\/script&gt;&quot;);
var script = document.getElementById("__ie_onload");
script.onreadystatechange = function() {
    if (this.readyState == "complete") {
        init(); // call the onload handler
    }
};
/*@end @*/</code></pre>
<p>而 <a href="http://javascript.nwbox.com/" title="Javascript @ NWBOX" target="_blank">Diego Perini</a> 在其后提供了一种利用 <code>doScroll() </code>方法来模拟 addDOMLoadEvent 事件的方案，且现在主流的 JavaScript 框架（JQuery、YUI等）基本都采用的这一解决方案。</p>
<p>原理基本如下：</p>
<blockquote><p>当 ondocumentready 事件触发，文档（ document ）已经完全解析和建立。如果组件需要操作最初的文档结构，初始化代码需被安置在这之后。ondocumentready 事件告知组件，整个页面已被加载，且在 初始文档的 onload 事件触发之前立即触发。</p>
<p>一些方法，例如 doScroll，要求最初的文档被完全加载。如果这些方法是初始化函数的一部分，当ondocumentready 事件触发，他们将被执行。</p></blockquote>
<pre><code>/*
 *
 * IEContentLoaded.js
 *
 * Author: Diego Perini (diego.perini at gmail.com) NWBOX S.r.l.
 * Summary: DOMContentLoaded emulation for IE browsers
 * Updated: 05/10/2007
 * License: GPL/CC
 * Version: TBD
 *
 */

// @w    window reference
// @fn    function reference
function IEContentLoaded (w, fn) {
    var d = w.document, done = false,
    // only fire once
    init = function () {
        if (!done) {
            done = true;
            fn();
        }
    };
    // polling for no errors
    (function () {
        try {
            // throws errors until after ondocumentready
            d.documentElement.doScroll('left');
        } catch (e) {
            setTimeout(arguments.callee, 50);
            return;
        }
        // no errors, fire
        init();
    })();
    // trying to always fire before onload
    d.onreadystatechange = function() {
        if (d.readyState == 'complete') {
            d.onreadystatechange = null;
            init();
        }
    };
}</code></pre>
<p>JQuery 1.3.2 中源码实现如下：</p>
<pre><code>// If IE and not an iframe
// continually check to see if the document is ready
if ( document.documentElement.doScroll &#038;&#038; window == window.top ) (function(){
    if ( jQuery.isReady ) return;

    try {
        // If IE is used, use the trick by Diego Perini
        // http://javascript.nwbox.com/IEContentLoaded/
        document.documentElement.doScroll("left");
    } catch( error ) {
        setTimeout( arguments.callee, 0 );
        return;
    }

    // and execute any waiting functions
    jQuery.ready();
})();</code></pre>
<p>YUI 2.7.0 中源码实现如下：</p>
<pre><code>if (EU.isIE) {

    // Process onAvailable/onContentReady items when the
    // DOM is ready.
    YAHOO.util.Event.onDOMReady(
            YAHOO.util.Event._tryPreloadAttach,
            YAHOO.util.Event, true);

    var n = document.createElement('p');  

    EU._dri = setInterval(function() {
        try {
            // throws an error if doc is not ready
            n.doScroll('left');
            clearInterval(EU._dri);
            EU._dri = null;
            EU._ready();
            n = null;
        } catch (ex) {
        }
    }, EU.POLL_INTERVAL); 

}</code></pre>
<p>另外对于版本小于 Safari 3+ 的 Safari 浏览器，<a href="http://ejohn.org/" title="John Resig" target="_blank">John Resig</a> 也提供了一个解决方案：</p>
<pre><code>if (/WebKit/i.test(navigator.userAgent)) { // sniff
    var _timer = setInterval(function() {
        if (/loaded|complete/.test(document.readyState)) {
            clearInterval(_timer);
            init(); // call the onload handler
        }
    }, 10);
}</code></pre>
<p>怿飞提示：</p>
<ol>
<li>如果脚本是动态注入到页面上，则原生的 DOMContentReady 事件是不会被触发（即：IE 除外）。</li>
<li>IE 下对于在 iframe 里的使用 addDOMLoadEvent 事件，需做处理和慎用（这一点 YUI 做得不如 JQuery 细致）。
<pre><code>// form JQuery 1.3.2
// ensure firing before onload, maybe late but safe also for iframes
document.attachEvent("onreadystatechange", function(){
    if ( document.readyState === "complete" ) {
        document.detachEvent( "onreadystatechange", arguments.callee );
        jQuery.ready();
    }
});</code></pre>
</li>
</ol>
<p>扩展阅读：</p>
<ul>
<li><a href="http://www.thefutureoftheweb.com/blog/adddomloadevent" title="addDOMLoadEvent" target="_blank">《addDOMLoadEvent》</a></li>
<li><a href="http://dean.edwards.name/weblog/2006/06/again/" title="window.onload (again)" target="_blank">《window.onload (again)》</a></li>
<li><a href="http://javascript.nwbox.com/IEContentLoaded/" title="IEContentLoaded" target="_blank">《IEContentLoaded》</a></li>
</ul>
<img src="http://www.planabc.net/?ak_action=api_record_view&id=268&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.planabc.net/2009/07/30/adddomloadevent/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>JavaScript 获取事件对象的一个注意点</title>
		<link>http://www.planabc.net/2009/07/24/tips_for_getting_event_in_javascript/</link>
		<comments>http://www.planabc.net/2009/07/24/tips_for_getting_event_in_javascript/#comments</comments>
		<pubDate>Fri, 24 Jul 2009 01:59:17 +0000</pubDate>
		<dc:creator>怿飞</dc:creator>
				<category><![CDATA[JS/Ajax/AS/Flex]]></category>
		<category><![CDATA[event]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://www.planabc.net/?p=258</guid>
		<description><![CDATA[平时我们获取事件对象一般写法如下：
function getEvent(event) {
    return event &#124;&#124; window.event  // IE:window.event
}
如果没有参数，也可写成（非IE ：事件对象会自动传递给对应的事件处理函数，且为第一个参数）：
function getEvent() {
    return arguments[0] &#124;&#124; window.event // IE:window.event
}
这样的写法在除 Firefox（测试版本：3.0.12，下同） 外的浏览器上运行都不会有问题，但 Firefox 为什么例外呢？让我们这样一种情形：
&#60;button id="btn" onclick="foo()"&#62;按钮&#60;/button&#62;

&#60;script&#62;
function foo(){
   var e =  getEvent();
   alert(e);
}
&#60;/script&#62;
运行结果在 Firefox 中是 undefined，为什么呢？
在 Firefox 中调用其实是这样的，先调用执行的是：
function onclick(event) {
    foo();
}
然后调用执行的是：
function foo(){
  [...... ]]></description>
			<content:encoded><![CDATA[<p>平时我们获取事件对象一般写法如下：</p>
<pre><code>function getEvent(event) {
    return event || window.event  // IE:window.event
}</code></pre>
<p>如果没有参数，也可写成（非IE ：事件对象会自动传递给对应的事件处理函数，且为第一个参数）：</p>
<pre><code>function getEvent() {
    return arguments[0] || window.event // IE:window.event
}</code></pre>
<p>这样的写法在除 Firefox（测试版本：3.0.12，下同） 外的浏览器上运行都不会有问题，但 Firefox 为什么例外呢？让我们这样一种情形：</p>
<pre><code>&lt;button id="btn" onclick="foo()"&gt;按钮&lt;/button&gt;

&lt;script&gt;
function foo(){
   var e =  getEvent();
   alert(e);
}
&lt;/script&gt;</code></pre>
<p>运行结果在 Firefox 中是 <code>undefined</code>，为什么呢？</p>
<p>在 Firefox 中调用其实是这样的，先调用执行的是：</p>
<pre><code>function onclick(event) {
    foo();
}</code></pre>
<p>然后调用执行的是：</p>
<pre><code>function foo(){
   var e =  getEvent();
   alert(e);
}</code></pre>
<p>会发现在  Firefox 下 <code>onclick="foo()"</code> 中的 <code>foo()</code> 无法自动传入事件对象参数，而默认传递给了系统生成的 onclick 函数，那本例我们可以通过 <code>getEvent.caller.caller.arguments[0]</code> 获得事件对象。</p>
<p>因此，我们的 getEvent 可以优化成（参照 yui_2.7.0b 中的 event/event-debug.js 中 getEvent 方法）：</p>
<pre><code>function getEvent(event) {
    var ev = event || window.event;

    if (!ev) {
        var c = this.getEvent.caller;
        while (c) {
            ev = c.arguments[0];
            if (ev &#038;&#038; (Event == ev.constructor || MouseEvent  == ev.constructor)) { //怿飞注：YUI 源码 BUG，ev.constructor 也可能是 MouseEvent，不一定是 Event
                break;
            }
            c = c.caller;
        }
    }

    return ev;
}</code></pre>
<p>当然还有一个很简单的解决方法，就是手动将参数传递给 <code>onclick="foo()"</code>：</p>
<pre><code>&lt;button id="btn" onclick="foo(event)"&gt;按钮&lt;/button&gt;</code></pre>
<img src="http://www.planabc.net/?ak_action=api_record_view&id=258&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.planabc.net/2009/07/24/tips_for_getting_event_in_javascript/feed/</wfw:commentRss>
		<slash:comments>18</slash:comments>
		</item>
		<item>
		<title>JavaScript 实现 Konami Code</title>
		<link>http://www.planabc.net/2009/05/21/how_to_implement_konami_code_with_javascript/</link>
		<comments>http://www.planabc.net/2009/05/21/how_to_implement_konami_code_with_javascript/#comments</comments>
		<pubDate>Thu, 21 May 2009 09:21:24 +0000</pubDate>
		<dc:creator>怿飞</dc:creator>
				<category><![CDATA[JS/Ajax/AS/Flex]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[Konami]]></category>

		<guid isPermaLink="false">http://www.planabc.net/?p=245</guid>
		<description><![CDATA[在 Facebook 上有一个彩蛋：
登录 facebook.com ，点击你首页的任何地方，键盘输入 Up, Up, Down, Down, Left, Right, Left, Right, B, A, Enter 后，再点击页面或滚动一下滚动条，你会发现特殊的变化（如下图），嘿嘿 ^^

玩过“魂斗罗”的朋友，肯定一眼就能看出输入的字符原来就是“魂斗罗”中的“秘技”。其实“秘技”的术语叫 Konami Code，详细见图示：

那如何用 JavaScript 也在自己的页面上添加一个类似的彩蛋呢？
Abhi 在 《Konami Code on Facebook : How to implement it on your site》 一文中提供了大体思路：
var $ = {
    enabled: false,
    tmp: Array(),
    _konamiCode: Array(65,66,39,37,39,37,40,40,38,38),
  [...... ]]></description>
			<content:encoded><![CDATA[<p>在 Facebook 上有一个彩蛋：</p>
<p>登录 <a href="http://www.facebook.com" title="Facebook"  target="_blank">facebook.com</a> ，点击你首页的任何地方，键盘输入 Up, Up, Down, Down, Left, Right, Left, Right, B, A, Enter 后，再点击页面或滚动一下滚动条，你会发现特殊的变化（如下图），嘿嘿 ^^</p>
<p><img src="http://www.planabc.net/wp-content/uploads/2009/05/facebook.jpg" alt="Facebook 上有一个彩蛋" /></p>
<p>玩过“魂斗罗”的朋友，肯定一眼就能看出输入的字符原来就是“魂斗罗”中的“秘技”。其实“秘技”的术语叫 <a href="http://en.wikipedia.org/wiki/Konami_Code" title="Konami Code"  target="_blank">Konami Code</a>，详细见图示：</p>
<p><img src="http://www.planabc.net/wp-content/uploads/2009/05/konami.png" alt="Konami Code" /></p>
<p>那如何用 JavaScript 也在自己的页面上添加一个类似的彩蛋呢？</p>
<p><a href="http://abhinavsingh.com/blog/" title="Abhi’s Weblog - PHP, Apache, MySQL, XMPP and Web Development"  target="_blank">Abhi</a> 在 <a href="http://abhinavsingh.com/blog/2009/05/konami-code-on-facebook-how-to-implement-it-on-your-site/" title="Konami Code on Facebook : How to implement it on your site"  target="_blank">《Konami Code on Facebook : How to implement it on your site》</a> 一文中提供了大体思路：</p>
<pre><code>var $ = {
    enabled: false,
    tmp: Array(),
    _konamiCode: Array(65,66,39,37,39,37,40,40,38,38),
    init: function() {
        this.tmp = Array(65,66,39,37,39,37,40,40,38,38);
    },
    konamiCode: function(e) {
        if(!this.enabled) {
            var t = this.tmp.pop();
            if((e.keyCode-t) == 0) {
                if(this.tmp.length == 0) {
                    this.enabled = true;
                }
            } else {
                this.init();
            }
        } else {
            this.action();
        }
    },
    // Change the action() function to whatever you want to
    action: function() {
        //alert("Konami Code Activated");
    }
}</code></pre>
<p>然后在 load 的时候调用 $.init() 方法，在 keydown 的时候调用 $.konamiCode(event) 方法。</p>
<p>不过 <a href="http://abhinavsingh.com/blog/" title="Abhi’s Weblog - PHP, Apache, MySQL, XMPP and Web Development"  target="_blank">Abhi</a> 的方法还是冗余了点，<a href="http://www.unwrongest.com/" title="Jan Jarfalk" target="_blank">Jan Jarfalk</a> 在留言中提供了一个短小精悍的代码：</p>
<pre><code>// Tweetable Konami code
var k=[];
function(e){
    k.push(e.keyCode);
    if(k.toString().indexOf("38,38,40,40,37,39,37,39,66,65")>=0) {
        //alert("Konami Code Activated");
    }
}</code></pre>
<p>PS：有兴趣的还可以在 <a href="https://www.google.com/reader/view/" target="_blank" title="Google Reader">Google Reader</a> 上尝试下此“秘技”，一般人我还不告诉他，嘿嘿。</p>
<img src="http://www.planabc.net/?ak_action=api_record_view&id=245&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.planabc.net/2009/05/21/how_to_implement_konami_code_with_javascript/feed/</wfw:commentRss>
		<slash:comments>30</slash:comments>
		</item>
		<item>
		<title>JavaScript 在各个浏览器中执行的耐性</title>
		<link>http://www.planabc.net/2009/02/04/how_long_time_will_javascript_execute_in_browsers/</link>
		<comments>http://www.planabc.net/2009/02/04/how_long_time_will_javascript_execute_in_browsers/#comments</comments>
		<pubDate>Wed, 04 Feb 2009 11:40:49 +0000</pubDate>
		<dc:creator>怿飞</dc:creator>
				<category><![CDATA[JS/Ajax/AS/Flex]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://www.planabc.net/?p=197</guid>
		<description><![CDATA[经常会遇到这样一个情况：浏览器弹出对话框，提示脚本运行时间过长，询问“停止”还是“继续”。那究竟各个浏览器是如何判断在什么时候才弹出此对话框呢？

IE：执行超过500W条JScript引擎语句出现提示。
Firefox：执行超过10秒出现提示。
Safari：执行超过5秒出现提示。
Opera：无论执行多久都不会出现提示，最有耐性。
Chrome：执行超过约8秒（估计值）出现提示。

注：当弹出类似alert的模式对话框的时候，是不计时。
扩展阅读：

《What determines that a script is long-running?》
... ]]></description>
			<content:encoded><![CDATA[<p>经常会遇到这样一个情况：浏览器弹出对话框，提示脚本运行时间过长，询问“停止”还是“继续”。那究竟各个浏览器是如何判断在什么时候才弹出此对话框呢？</p>
<ul>
<li>IE：执行超过500W条JScript引擎语句出现提示。</li>
<li>Firefox：执行超过10秒出现提示。</li>
<li>Safari：执行超过5秒出现提示。</li>
<li>Opera：无论执行多久都不会出现提示，最有耐性。</li>
<li>Chrome：执行超过约8秒（估计值）出现提示。</li>
</ul>
<p><strong>注：</strong>当弹出类似alert的模式对话框的时候，是不计时。</p>
<p>扩展阅读：</p>
<ul>
<li><a href="http://www.nczonline.net/blog/2009/01/05/what-determines-that-a-script-is-long-running/" title="What determines that a script is long-running?" target="_blank">《What determines that a script is long-running?》</a></li>
</ul>
<img src="http://www.planabc.net/?ak_action=api_record_view&id=197&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.planabc.net/2009/02/04/how_long_time_will_javascript_execute_in_browsers/feed/</wfw:commentRss>
		<slash:comments>23</slash:comments>
		</item>
		<item>
		<title>有趣而诡异的数组</title>
		<link>http://www.planabc.net/2009/02/02/javascript_array_fun/</link>
		<comments>http://www.planabc.net/2009/02/02/javascript_array_fun/#comments</comments>
		<pubDate>Mon, 02 Feb 2009 09:00:12 +0000</pubDate>
		<dc:creator>怿飞</dc:creator>
				<category><![CDATA[JS/Ajax/AS/Flex]]></category>
		<category><![CDATA[Array]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://www.planabc.net/?p=185</guid>
		<description><![CDATA[年前在重写淘宝旺铺里的会员卡脚本的时候，无意中发现了一个有趣的事情。代码类似：
var associative_array = new Array();
associative_array["one"] = "1";
associative_array["two"] = "2";
associative_array["three"] = "3";
if(associative_array.length > 0) {
    // to do
}
会发现 associative_array.length 始终等于 0，当时有点迷惑，后来才知道这就像大家认为 IE 中支持 CSS 属性 display:inline-block 一样，纯属巧合和误解。
实际上（引自《JavaScript “Associative Arrays” Considered Harmful》）：
JavaScript arrays (which are meant to be numeric) are often used to hold key/value pairs. This is bad practice. Object should be used [...... ]]></description>
			<content:encoded><![CDATA[<p>年前在重写淘宝旺铺里的会员卡脚本的时候，无意中发现了一个有趣的事情。代码类似：</p>
<pre><code>var associative_array = new Array();
associative_array["one"] = "1";
associative_array["two"] = "2";
associative_array["three"] = "3";
if(associative_array.length > 0) {
    // to do
}</code></pre>
<p>会发现 <code>associative_array.length</code> 始终等于 0，当时有点迷惑，后来才知道这就像大家认为 IE 中支持 CSS 属性 <a href="http://www.planabc.net/2007/03/11/display_inline-block/" title="display:inline-block的深入理解" target="_blank"><code>display:inline-block</code></a> 一样，纯属巧合和误解。</p>
<p>实际上（引自<a href="http://andrewdupont.net/2006/05/18/javascript-associative-arrays-considered-harmful/" title="JavaScript “Associative Arrays” Considered Harmful" target="_blank">《JavaScript “Associative Arrays” Considered Harmful》</a>）：</p>
<blockquote><p>JavaScript arrays (which are meant to be numeric) are often used to hold key/value pairs. This is bad practice. Object should be used instead.</p>
<p>//大意：<strong>数组只支持数字的，键值对应使用于对象上。</strong>
</p></blockquote>
<ul>
<li>There is no way to specify string keys in an array constructor. //在数组构造函数中无法定义字符串键值</li>
<li>There is no way to specify string keys in an array literal. //在数组字面量中无法定义字符串键值</li>
<li>Array.length does not count them as items. // Array.length 不会计算字符串键值</li>
</ul>
<p>进一步窥探数组：</p>
<p>1、数组可以根据所赋的值自动调整大小</p>
<pre><code>var ar = [];
ar[2] = 1;
alert(ar.length)</code></pre>
<p>发现这个数组的长度为 3，就像一个经过初始化的数组一样。所有没有赋值的数组对象，都将被定义为 <code>undefined</code> 。</p>
<p>扩展阅读：</p>
<ul>
<li><a href="http://west-wind.com/Weblog/posts/608772.aspx" title="Javascript Array Fun" target="_blank">《Javascript Array Fun》</a></li>
</ul>
<p>2、可使用 <strong>“The Miller Device”</strong> 方法来判断是否是数组</p>
<pre><code>function isArray(o) {
  return Object.prototype.toString.call(o) === '[object Array]';
}</code></pre>
<p>“The Miller Device” 的妙用不仅仅在于判断数组：</p>
<pre><code>var is = {
    types : ["Array","RegExp","Date","Number","String","Object"]
};

for(var i=0,c;c=is.types[i++];){
    is[c] = (function(type){
        return function(obj){
            return Object.prototype.toString.call(obj) == “[object "+type+"]“;
        }
    })(c);
}</code></pre>
<p>扩展阅读：</p>
<ul>
<li><a href="http://blog.360.yahoo.com/blog-TBPekxc1dLNy5DOloPfzVvFIVOWMB0li?p=916" title="The Miller Device" target="_blank">《The Miller Device》</a> </li>
<li><a href="http://ajaxian.com/archives/isarray-why-is-it-so-bloody-hard-to-get-right" title="isArray: Why is it so bloody hard to get right?" target="_blank">《isArray: Why is it so bloody hard to get right?》</a></li>
</ul>
<img src="http://www.planabc.net/?ak_action=api_record_view&id=185&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.planabc.net/2009/02/02/javascript_array_fun/feed/</wfw:commentRss>
		<slash:comments>23</slash:comments>
		</item>
		<item>
		<title>IE 下 href 的 BUG</title>
		<link>http://www.planabc.net/2008/11/06/ie-href-bug/</link>
		<comments>http://www.planabc.net/2008/11/06/ie-href-bug/#comments</comments>
		<pubDate>Thu, 06 Nov 2008 13:22:48 +0000</pubDate>
		<dc:creator>怿飞</dc:creator>
				<category><![CDATA[JS/Ajax/AS/Flex]]></category>
		<category><![CDATA[bug]]></category>
		<category><![CDATA[href]]></category>
		<category><![CDATA[IE]]></category>

		<guid isPermaLink="false">http://www.planabc.net/?p=130</guid>
		<description><![CDATA[在浏览器 IE6 、IE7、Firefox2+、Firefpx3+、Opera9.6+、Safari3.1+中测试以下代码（Demo）：
&#60;div id="test"&#62;
    &#60;a href="#"&#62; test &#60;/a&#62;
&#60;/div&#62;
&#60;div id="result"&#62;&#60;/div&#62;

&#60;script type="text/javascript"&#62;
(function(){
    var test = document.getElementById('test');
    alert(test.innerHTML);

    var result =  document.getElementById('result');
    result.innerHTML = test.innerHTML;
    alert(result.innerHTML)
})();
&#60;/script&#62;
结果会发现，在 IE6、IE7 浏览器中第二次弹出的 result.innerHTML 中的 A 元素的 href 值成为了绝对路径。
其实先人们早遇到这些问题（感谢 玉伯 提供的资料）：

《getAttribute(&#8220;HREF&#8221;) is always absolute》
《getAttribute [...... ]]></description>
			<content:encoded><![CDATA[<p>在浏览器 IE6 、IE7、Firefox2+、Firefpx3+、Opera9.6+、Safari3.1+中测试以下代码（<a title="IE 下 href 的 BUG 测试" href="http://www.planabc.net/demo/ie-href-bug.html" target="_blank">Demo</a>）：</p>
<pre><code>&lt;div id="test"&gt;
    &lt;a href="#"&gt; test &lt;/a&gt;
&lt;/div&gt;
&lt;div id="result"&gt;&lt;/div&gt;

&lt;script type="text/javascript"&gt;
(function(){
    var test = document.getElementById('test');
    alert(test.innerHTML);

    var result =  document.getElementById('result');
    result.innerHTML = test.innerHTML;
    alert(result.innerHTML)
})();
&lt;/script&gt;</code></pre>
<p>结果会发现，在 IE6、IE7 浏览器中第二次弹出的 result.innerHTML 中的 A 元素的 href 值成为了绝对路径。</p>
<p>其实先人们早遇到这些问题（感谢 <a title="岁月如歌 - 关注用户体验、前端开发，记录生活点滴、岁月足迹。" href="http://lifesinger.org/blog/" target="_blank">玉伯</a> 提供的资料）：</p>
<ul>
<li><a title="getAttribute(" href="http://www.quirksmode.org/bugreports/archives/2005/02/getAttributeHREF_is_always_absolute.html" target="_blank">《getAttribute(&#8220;HREF&#8221;) is always absolute》</a></li>
<li><a title="getAttribute href bug" href="http://www.glennjones.net/Post/809/getAttributehrefbug.htm" target="_blank">《getAttribute href bug》</a></li>
</ul>
<p>在上面的文章中已提及了处理方案，就是在 IE 下使用 getAttribute( &#8216;href&#8217; , 2 ) 方法。 Microsoft 给此方法扩展了第二个参数，可设置为 0、1、2，如果设置为 2 ，则返回属性原始值。</p>
<p>脚本修正为：</p>
<pre><code>(function(){
    var test = document.getElementById('test');
    alert(test.innerHTML);

    var result =  document.getElementById('result');
    result.innerHTML = test.innerHTML;

    if(/*@cc_on!@*/0 ) { //if ie
        var links1 = test.getElementsByTagName('a');
        var links2 = result.getElementsByTagName('a');
        for(var i = 0, len = links1.length; i &lt; len; ++i ) {
            links2[i].href = links1[i].getAttribute('href', 2);
        }
    }

    alert(result.innerHTML);

})();</code></pre>
<p>在寻找此问题的过程中还搜索到 <a title="Hedger Wang" href="http://www.hedgerwow.com" target="_blank">Hedger Wang</a> 发现的一个有趣的 BUG 问题：在 IE 中当重新设置新的 href 属性值时，如果链接文字含有 &#8220;http://&#8221; 或 &#8220;@&#8221; ，则其 innerHTML 将显示不正确，显示成设置的 href 属性。</p>
<p>解决方法（sHref 为要设置的 href 新值）：</p>
<pre><code>sHref = 'http://www.hedgerwow.com';
var isMSIE = /*@cc_on!@*/false;
if( isMSIE ){
    sHref = ' ' + sHref; //add extra space before the new href
};</code></pre>
<p>详细：<a title="Internet Explorer might reset Anchor's innerHTML incorrectly when a new " href="http://www.hedgerwow.com/360/bugs/ie-anchor-bug.html" target="_blank">《Internet Explorer might reset Anchor&#8217;s innerHTML incorrectly when a new &#8220;href&#8221; is assigned》</a>。</p>
<img src="http://www.planabc.net/?ak_action=api_record_view&id=130&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.planabc.net/2008/11/06/ie-href-bug/feed/</wfw:commentRss>
		<slash:comments>22</slash:comments>
		</item>
		<item>
		<title>如何判断脚本加载完成</title>
		<link>http://www.planabc.net/2008/10/31/javascript_ready_onload/</link>
		<comments>http://www.planabc.net/2008/10/31/javascript_ready_onload/#comments</comments>
		<pubDate>Fri, 31 Oct 2008 08:33:59 +0000</pubDate>
		<dc:creator>怿飞</dc:creator>
				<category><![CDATA[JS/Ajax/AS/Flex]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[load]]></category>

		<guid isPermaLink="false">http://www.planabc.net/?p=109</guid>
		<description><![CDATA[在“按需加载”的需求中，我们经常会判断当脚本加载完成时，返回一个回调函数，那如何去判断脚本的加载完成呢？
我们可以对加载的 JS 对象使用 onload 来判断（js.onload），此方法 Firefox2、Firefox3、Safari3.1+、Opera9.6+ 浏览器都能很好的支持，但 IE6、IE7 却不支持。曲线救国 —— IE6、IE7 我们可以使用 js.onreadystatechange 来跟踪每个状态变化的情况（一般为 loading 、loaded、interactive、complete），当返回状态为 loaded 或 complete 时，则表示加载完成，返回回调函数。
对于 readyState 状态需要一个补充说明：

在 interactive 状态下，用户可以参与互动。
Opera 其实也支持 js.onreadystatechange，但他的状态和 IE 的有很大差别。

具体实现代码如下：
function include_js(file) {
    var _doc = document.getElementsByTagName('head')[0];
    var js = document.createElement('script');
    js.setAttribute('type', 'te... ]]></description>
			<content:encoded><![CDATA[<p>在“按需加载”的需求中，我们经常会判断当脚本加载完成时，返回一个回调函数，那如何去判断脚本的加载完成呢？</p>
<p>我们可以对加载的 JS 对象使用 onload 来判断（js.onload），此方法 Firefox2、Firefox3、Safari3.1+、Opera9.6+ 浏览器都能很好的支持，但 IE6、IE7 却不支持。曲线救国 —— IE6、IE7 我们可以使用 js.onreadystatechange 来跟踪每个状态变化的情况（一般为 loading 、loaded、interactive、complete），当返回状态为 loaded 或 complete 时，则表示加载完成，返回回调函数。</p>
<p>对于 readyState 状态需要一个补充说明：</p>
<ol>
<li>在 interactive 状态下，用户可以参与互动。</li>
<li>Opera 其实也支持 js.onreadystatechange，但他的状态和 IE 的有很大差别。</li>
</ol>
<p>具体实现代码如下：</p>
<pre><code>function include_js(file) {
    var _doc = document.getElementsByTagName('head')[0];
    var js = document.createElement('script');
    js.setAttribute('type', 'text/javascript');
    js.setAttribute('src', file);
    _doc.appendChild(js);

    if (!/*@cc_on!@*/0) { //if not IE
        //Firefox2、Firefox3、Safari3.1+、Opera9.6+ support js.onload
        js.onload = function () {
            alert('Firefox2、Firefox3、Safari3.1+、Opera9.6+ support js.onload');
        }
    } else {
        //IE6、IE7 support js.onreadystatechange
        js.onreadystatechange = function () {
            if (js.readyState == 'loaded' || js.readyState == 'complete') {
                alert('IE6、IE7 support js.onreadystatechange');
            }
        }
    }

    return false;
}

//execution function
include_js('http://www.planabc.net/wp-includes/js/jquery/jquery.js');</code></pre>
<p>扩展阅读：</p>
<ul>
<li><a title="JS includes - the saga continues…" href="http://www.phpied.com/javascript-include-ready-onload/" target="_blank">《JS includes &#8211; the saga continues…》</a></li>
<li><a title="Asynchrony: Loved Your Performance" href="http://msdn.microsoft.com/en-us/library/bb263994.aspx" target="_blank">《Asynchrony: Loved Your Performance》</a></li>
<li><a title="Yahoo! UI Library: Get Utility" href="http://yui.yahooapis.com/2.6.0/build/get/get-debug.js" target="_blank">《Yahoo! UI Library: Get Utility》</a></li>
</ul>
<img src="http://www.planabc.net/?ak_action=api_record_view&id=109&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.planabc.net/2008/10/31/javascript_ready_onload/feed/</wfw:commentRss>
		<slash:comments>25</slash:comments>
		</item>
		<item>
		<title>使用 window.name 解决跨域问题</title>
		<link>http://www.planabc.net/2008/09/01/window_name_transport/</link>
		<comments>http://www.planabc.net/2008/09/01/window_name_transport/#comments</comments>
		<pubDate>Sun, 31 Aug 2008 16:59:27 +0000</pubDate>
		<dc:creator>怿飞</dc:creator>
				<category><![CDATA[JS/Ajax/AS/Flex]]></category>
		<category><![CDATA[frame]]></category>
		<category><![CDATA[window]]></category>

		<guid isPermaLink="false">http://www.planabc.net/?p=90</guid>
		<description><![CDATA[window.name 传输技术，原本是 Thomas Frank 用于解决 cookie 的一些劣势（每个域名 4 x 20 Kb 的限制、数据只能是字符串、设置和获取 cookie 语法的复杂等等）而发明的（详细见原文：《Session variables without cookies》），后来 Kris Zyp 在此方法的基础上强化了 window.name 传输  ，并引入到了 Dojo  （dojox.io.windowName），用来解决跨域数据传输问题。
window.name 的美妙之处：name 值在不同的页面（甚至不同域名）加载后依旧存在，并且可以支持非常长的 name 值（2MB）。
window.name 传输技术的基本原理和步骤为：

name 在浏览器环境中是一个全局/window对象的属性，且当在 frame 中加载新页面时，name 的属性值依旧保持不变。通过在 iframe 中加载一个资源，该目标页面将设置 frame 的 name 属性。此 name 属性值可被获取到，以访问 Web 服务发送的信息。但 name 属性仅对相同域名的 fram... ]]></description>
			<content:encoded><![CDATA[<p>window.name 传输技术，原本是 <a href="http://www.thomasfrank.se/about.html" target="_blank" title="About Thomas Frank ">Thomas Frank</a> 用于解决 cookie 的一些劣势（每个域名 4 x 20 Kb 的限制、数据只能是字符串、设置和获取 cookie 语法的复杂等等）而发明的（详细见原文：<a href="http://www.thomasfrank.se/sessionvars.html" target="_blank" target="_blank">《Session variables without cookies》</a>），后来 <a href="http://www.sitepen.com/blog/2008/07/22/windowname-transport/" target="_blank" title="window.name Transport">Kris Zyp</a> 在此方法的基础上强化了 window.name 传输  ，并引入到了 <a href="http://dojotoolkit.org/" target="_blank" title="Dojo">Dojo </a> （<a href="http://bugs.dojotoolkit.org/ticket/6893" target="_blank" title="dojox.io.windowName">dojox.io.windowName</a>），用来解决跨域数据传输问题。</p>
<p>window.name 的美妙之处：<strong>name 值在不同的页面（甚至不同域名）加载后依旧存在，并且可以支持非常长的 name 值（2MB）。</strong></p>
<p>window.name 传输技术的基本原理和步骤为：<br />
<img src="http://www.planabc.net/wp-content/uploads/2008/08/windowname.png" title="window.name 技术的基本原理和步骤图示" alt="window.name 技术的基本原理和步骤图示" /></p>
<p>name 在浏览器环境中是一个全局/window对象的属性，且当在 frame 中加载新页面时，name 的属性值依旧保持不变。通过在 iframe 中加载一个资源，该目标页面将设置 frame 的 name 属性。此 name 属性值可被获取到，以访问 Web 服务发送的信息。但 name 属性仅对相同域名的 frame 可访问。这意味着为了访问 name 属性，当远程 Web 服务页面被加载后，必须导航 frame 回到原始域。同源策略依旧防止其他 frame 访问 name 属性。一旦 name 属性获得，销毁 frame 。</p>
<p>在最顶层，name 属性是不安全的，对于所有后续页面，设置在 name 属性中的任何信息都是可获得的。然而 windowName 模块总是在一个 iframe 中加载资源，并且一旦获取到数据，或者当你在最顶层浏览了一个新页面，这个 iframe 将被销毁，所以其他页面永远访问不到 window.name 属性。</p>
<p>基本实现代码，基于 <a href="http://developer.yahoo.com/yui/" target="_blank" title="_blank">YUI</a>，源自<a href="http://hikejun.com/demo/windowname/demo_windowname.html" target="_blank">克军写的样例</a>：</p>
<pre><code>(function(){
    var YUD = YAHOO.util.Dom, YUE = YAHOO.util.Event;

    dataRequest = {
        _doc: document,
        cfg: {
            proxyUrl: 'proxy.html'
        }
    };

    dataRequest.send = function(sUrl, fnCallBack){
        if(!sUrl || typeof sUrl !== 'string'){
            return;
        }

        sUrl += (sUrl.indexOf('?') > 0 ? '&#038;' : '?') + 'windowname=true';

        var frame = this._doc.createElement('iframe'), state = 0, self = this;
        this._doc.body.appendChild(frame);
        frame.style.display = 'none';

        var clear = function(){
            try{
                frame.contentWindow.document.write('');
                frame.contentWindow.close();
                self._doc.body.removeChild(frame);
            }catch(e){}
        };

        var getData = function(){
            try{
                var da = frame.contentWindow.name;
            }catch(e){}
            clear();
            if(fnCallBack &#038;&#038; typeof fnCallBack === 'function'){
                fnCallBack(da);
            }
        };

        YUE.on(frame, 'load', function(){
            if(state === 1){
                getData();
            } else if(state === 0){
                state = 1;
                frame.contentWindow.location = self.cfg.proxyUrl;
            }
        });

        frame.src = sUrl;
    };
})();</code></pre>
<p><strong>Web 服务器如何提供 window.name 数据</strong></p>
<p>为了让 Web 服务器实现 window.name，服务器应该只寻找请求中是否包含 windowname 参数。如果包含了 windowname 参数，服务器应该返回一个设置了 window.name 字符串值的 HTML 文档，回应此请求并传送到客户端。例如：<br />http://www.planabc.net/getdata.html?windowname=true</p>
<p>如果服务器想用 Hello 响应客服端，它应该返回一个 HTML 页面：</p>
<pre><code>&lt;html&gt;
    &lt;script type=&quot;text/javascript&quot;&gt;
        window.name=&quot;Hello&quot;;
    &lt;/script&gt;
&lt;/html&gt;</code></pre>
<p>同样也可以转换为 JSON 数据：</p>
<pre><code>&lt;html&gt;
    &lt;script type=&quot;text/javascript&quot;&gt;
        window.name='{&quot;foo&quot;:&quot;bar&quot;}';
    &lt;/script&gt;
&lt;/html&gt;</code></pre>
<p>如果你手动创建资源，书写大量的多行的 JSON 对象为一个引用的字符串应该是比较困难的并且易于出错的。可以使用这样的 HTML 样例简单的创建 JSON 数据，将会转换为一个 JSON 字符串而无需手动转义 JSON 为字符串：</p>
<pre><code>&lt;html&gt;
    &lt;script type=&quot;\'text/javascript\'&quot;&gt;
        window.name = document.getElementsByTagName(&quot;script&quot;)[0].innerHTML.match(/temp\s*=([\w\W]*)/)[1];
        temp= {
            foo:&quot;bar&quot;, // put json data here
            baz:&quot;foo&quot;
        }
    &lt;/script&gt;
&lt;/html&gt;</code></pre>
<p>同样的，如果你想传递 HTML/XML 数据，这里有一个样例实现，而无需手动将这些数据转换成字符串：</p>
<pre><code>&lt;html&gt;
    &lt;body&gt;
        &lt;p id=&quot;content&quot;&gt;
            some &lt;strong&gt;html/xml-style&lt;/strong&gt;data
        &lt;/p&gt;
    &lt;/body&gt;
    &lt;script type=&quot;text/javascript&quot;&gt;
        window.name = document.getElementById(&quot;content&quot;).innerHTML;
    &lt;/script&gt;
&lt;/html&gt;</code></pre>
<p>window.name 传输技术相比其他的跨域传输的一些优势：</p>
<ol>
<li>它是安全的。也就是说，它和其他的基于安全传输的 frame 一样安全，例如 Fragment Identifier messaging （FIM）和  <a href="http://research.microsoft.com/~helenw/papers/subspace.pdf" title="Subspace" target="_blank">Subspace</a>。(I)Frames 也有他们自己的安全问题，由于 frame 可以改变其他 frame 的 location，但是这个是非常不同的安全溢出，通常不太严重。</li>
<li>它比 FIM 更快，因为它不用处理小数据包大小的 Fragment Identifier ，并且它不会有更多的 IE 上的“机关枪”声音效果。它也比 Subspace 快，Subspace 需要加载两个 Iframe 和两个本地的 HTML 文件来处理一个请求。window.name 仅需要一个 Iframe 和一个本地文件。</li>
<li>它比 FIM 和 Subspace 更简单和安全。FIM 稍微复杂，而 Subspace 非常复杂。Subspace 也有一些额外的限制和安装要求，如预先声明所有的目标主机和拥有针对若干不同特殊主机的 DNS 入口。window.name 非常简单和容易使用。</li>
<li>它不需要任何插件（比如 Flash）或者替代技术（例如 Java）。</li>
</ol>
<img src="http://www.planabc.net/?ak_action=api_record_view&id=90&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.planabc.net/2008/09/01/window_name_transport/feed/</wfw:commentRss>
		<slash:comments>32</slash:comments>
		</item>
		<item>
		<title>跨浏览器的本地存储（二）：DOM:Storage</title>
		<link>http://www.planabc.net/2008/08/14/dom_storage/</link>
		<comments>http://www.planabc.net/2008/08/14/dom_storage/#comments</comments>
		<pubDate>Thu, 14 Aug 2008 06:34:03 +0000</pubDate>
		<dc:creator>怿飞</dc:creator>
				<category><![CDATA[JS/Ajax/AS/Flex]]></category>
		<category><![CDATA[cookie]]></category>
		<category><![CDATA[DOM]]></category>
		<category><![CDATA[store]]></category>

		<guid isPermaLink="false">http://www.planabc.net/?p=89</guid>
		<description><![CDATA[DOM Storage，是基于 Web Applications 1.0 specification 中介绍的 Structured client-side storage。相比 Cookies 来说，DOM Stroage 空间更大、更安全、更易于使用的。目前它只在基于Moziila的浏览器中可以使用，从 Firefox2 开始。
一、DOM:Storage: sessionStorage
浏览器支持：Firefox 2.0+
基本语法：

// 设置 key 值
sessionStorage.key = value;
// 获取 key 值
value = sessionStorage.key;

备注：

作为每个 window 对象的属性存在的全局对象，即：可以通过 sessionStorage 或者 window.sessionStorage 来访问它们。
sessionStorage 含有一个在页面会话有效期内（只要页面没有关闭，一个页面会话就始终保持着，且当页面被重新载入或恢复时“复活”，而打开一个新的标签页或新窗口都会初始化新的会话）可用的存储区域。
sessionStorage 持有那些应该保存的临时数据，一旦浏览器突然被刷新时，可恢复。
sessionStorage 暂时... ]]></description>
			<content:encoded><![CDATA[<p>DOM Storage，是基于 Web Applications 1.0 specification 中介绍的 <a href="http://www.whatwg.org/specs/web-apps/current-work/#the-storage" target="_blank" title="Structured client-side storage">Structured client-side storage</a>。相比 Cookies 来说，DOM Stroage 空间更大、更安全、更易于使用的。目前它只在基于Moziila的浏览器中可以使用，从 Firefox2 开始。</p>
<p><strong>一、DOM:Storage: sessionStorage</strong></p>
<p><strong>浏览器支持：</strong>Firefox 2.0+</p>
<p><strong>基本语法：</strong></p>
<ul>
<li>// 设置 key 值<br />
sessionStorage.key = value;</li>
<li>// 获取 key 值<br />
value = sessionStorage.key;</li>
</ul>
<p><strong>备注：</strong></p>
<ol>
<li>作为每个 window 对象的属性存在的全局对象，即：可以通过 sessionStorage 或者 window.sessionStorage 来访问它们。</li>
<li>sessionStorage 含有一个在页面会话有效期内（只要页面没有关闭，一个页面会话就始终保持着，且当页面被重新载入或恢复时“复活”，而打开一个新的标签页或新窗口都会初始化新的会话）可用的存储区域。</li>
<li>sessionStorage 持有那些应该保存的临时数据，一旦浏览器突然被刷新时，可恢复。</li>
<li>sessionStorage 暂时还没有实现在浏览器崩溃后存储和恢复数据的功能（ <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=339445" target="_blank" title="sessionStorage bug">bug 339445</a> ）。</li>
</ol>
<p>更多信息：<a href="http://www.whatwg.org/specs/web-apps/current-work/#sessionstorage" target="_blank" title="sessionStorage specification">sessionStorage specification</a></p>
<p><strong>样例：</strong>自动保存文本字段的内容，如果浏览器突然被刷新，就恢复字段内容，这样就不会丢失任何输入了。</p>
<pre><code>// 获得我们要跟踪的那个文本字段
var field = document.getElementById("field");

// 看看我们是否有一个autosave的值
// (这将只会在页面被突然刷新时发生)
if ( sessionStorage.autosave ) {
    // 恢复文本字段中的内容
    field.value = sessionStorage.autosave;
}

// 每秒钟检查一次文本字段的内容
setInterval(function(){
    // 并把结果保存到会话存储对象中
    sessionStorage.autosave = field.value;
}, 1000);</code></pre>
<p><strong>二、DOM:Storage: globalStorage（重点）</strong></p>
<p><strong>浏览器支持：</strong>Firefox 2.0+</p>
<p><strong>基本语法：</strong></p>
<ul>
<li>globalStorage['developer.mozilla.org'] —— 在developer.mozilla.org下面所有的子域都可以通过这个存储对象来进行读和写。</li>
<li>globalStorage['mozilla.org'] —— 在mozilla.org域名下面的所有网页都可以通过这个存储对象来进行读和写。</li>
<li>globalStorage['org'] —— 在.org域名下面的所有网页都可以通过这个存储对象来进行读和写。</li>
<li>globalStorage[''] —— 在任何域名下的任何网页都可以通过这个存储对象来进行读和写。</li>
</ul>
<p><strong>方法属性：</strong></p>
<ul>
<li>setItem(key, value) —— 设置或重置 key 值。</li>
<li>getItem(key) —— 获取 key 值。</li>
<li>removeItem(key) —— 删除 key 值。</li>
</ul>
<p>或者：</p>
<ul>
<li>// 设置 key 值<br />
window.globalStorage["planabc.net"].key = value;</li>
<li>// 获取 key 值<br />
value = window.globalStorage["planabc.net"].key;</li>
</ul>
<p><strong>备注：</strong></p>
<ol>
<li>作为每个 window 对象的属性存在的全局对象，即：可以通过 globalStorage 或者 window.globalStorage 来访问它们。</li>
<li>Storage 空间：整个域名的默认 Storage 大小为 5MB （不过 Storage 区域的大小用户可以自定义），globalStorage['net'] 为 2MB，globalStorage['planabc.net'] 为 3MB，如果超过限制，则会报错。</li>
<li><a href="http://xulplanet.com/ndeakin/tests/sessions/global-event.html" target="_blank">Firefox 支持 Storage 事件</a>：document.addEventListener(&#8220;storage&#8221;, eventHandler, false);。</li>
<li>Firefox 目前还没有实现 globalStorage[tld] 和 globalStorage[''] （会抛出一个安全错误），这是由于对于这些名字空间可以进行随意读写的话是有安全漏洞的。</li>
<li>Firefox 2 允许访问比当前文档域名层次高的存储的对象，由于安全的因素 Firefox 3 中不再允许。</li>
</ol>
<p>更多信息：<a href="http://www.whatwg.org/specs/web-apps/current-work/#globalstorage" target="_blank" title="globalStorage specification">globalStorage specification</a></p>
<p><strong>样例：</strong>（<a href="http://channy.creation.net/work/firefox/domstorage/" target="_blank">DOM Storage Test</a>）</p>
<pre><code>// 跟踪一个用户在你的域名下所访问的所有页面的次数
globalStorage['mozilla.org'].visits =
    parseInt( globalStorage['mozilla.org'].visits || 0 ) + 1;</code></pre>
<p><strong>参考阅读：</strong></p>
<ul>
<li><a href="http://developer.mozilla.org/en/docs/DOM:Storage" target="_blank" title="DOM:Storage">《DOM:Storage》</a></li>
<li><a href="http://ejohn.org/blog/dom-storage/" target="_blank" title="DOM Storage">《DOM Storage》</a></li>
<li><a href="http://ejohn.org/blog/dom-storage-answers/" target="_blank" title="DOM Storage Answers">《DOM Storage Answers》</a></li>
<li><a href="http://www.whatwg.org/specs/web-apps/current-work/#storage" target="_blank" title="Structured client-side storage">《Structured client-side storage》</a></li>
</ul>
<img src="http://www.planabc.net/?ak_action=api_record_view&id=89&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.planabc.net/2008/08/14/dom_storage/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>跨浏览器的本地存储（一）：userData behavior</title>
		<link>http://www.planabc.net/2008/08/05/userdata_behavior/</link>
		<comments>http://www.planabc.net/2008/08/05/userdata_behavior/#comments</comments>
		<pubDate>Tue, 05 Aug 2008 09:47:26 +0000</pubDate>
		<dc:creator>怿飞</dc:creator>
				<category><![CDATA[JS/Ajax/AS/Flex]]></category>
		<category><![CDATA[cookie]]></category>
		<category><![CDATA[store]]></category>

		<guid isPermaLink="false">http://www.planabc.net/?p=87</guid>
		<description><![CDATA[前言
现在最流行的本地存储莫过于 cookie 的应用，但浏览器对 cookie 有很多限制，最大的限制在于其对cookie 总大小，仅为 4K 左右（包括名（name）、值（value）和等号）。
对于复杂一点的应用和需求，仅有的 4K 大小还是有点相形见绌，其实很多浏览器（IE、Firefox、Safari）本身也提供了自己的本地存储的功能，或许在特定的环境下能满足我们。
一、userData behavior
浏览器支持：IE5.0 或以上
基本语法：

XML：&#60;Prefix: CustomTag id=sID style=&#8221;behavior:url(&#8216;#default#userData&#8217;)&#8221; /&#62;
HTML： &#60;ELEMENT style=&#8221;behavior:url(&#8216;#default#userData&#8217;)&#8221; id=sID&#62;object.style.behavior = &#8220;url(&#8216;#default#userData&#8217;)&#8221;
Script： object.addBehavior (&#8220;#default#userData&#8221;)

属性：

expires —— 设置或者获取 userData behavior 保存数据的失效日期。
XMLDocument —— 获取 XML ... ]]></description>
			<content:encoded><![CDATA[<p><strong>前言</strong></p>
<p>现在最流行的本地存储莫过于 cookie 的应用，但<a href="http://www.planabc.net/2008/05/22/browser_cookie_restrictions/" target="_blank" title=" 浏览器 cookie 限制">浏览器对 cookie 有很多限制</a>，最大的限制在于其对cookie 总大小，仅为 4K 左右（包括名（name）、值（value）和等号）。</p>
<p>对于复杂一点的应用和需求，仅有的 4K 大小还是有点相形见绌，其实很多浏览器（IE、Firefox、Safari）本身也提供了自己的本地存储的功能，或许在特定的环境下能满足我们。</p>
<p><strong>一、userData behavior</strong></p>
<p><strong>浏览器支持：</strong>IE5.0 或以上</p>
<p><strong>基本语法：</strong></p>
<ul>
<li>XML：&lt;Prefix: CustomTag id=sID style=&#8221;behavior:url(&#8216;#default#userData&#8217;)&#8221; /&gt;</li>
<li>HTML： <br />&lt;ELEMENT style=&#8221;behavior:url(&#8216;#default#userData&#8217;)&#8221; id=sID&gt;<br />object.style.behavior = &#8220;url(&#8216;#default#userData&#8217;)&#8221;</li>
<li>Script： object.addBehavior (&#8220;#default#userData&#8221;)</li>
</ul>
<p><strong>属性：</strong></p>
<ul>
<li>expires —— 设置或者获取 userData behavior 保存数据的失效日期。</li>
<li>XMLDocument —— 获取 XML 的引用。</li>
</ul>
<p><strong>方法：</strong></p>
<ul>
<li>getAttribute() —— 获取指定的属性值。</li>
<li>load(object) —— 从 userData 存储区载入存储的对象数据。</li>
<li>removeAttribute() —— 移除对象的指定属性。</li>
<li>save(object) —— 将对象数据存储到一个 userData 存储区。</li>
<li>setAttribute() —— 设置指定的属性值。</li>
</ul>
<p><strong>备注：</strong></p>
<p>1、从安全方面考虑，一个 userData 存储区只能用于同一目录和对同一协议进行存储。</p>
<p>2、如果使用 userData behavior 不正确可能会对你的应用造成危害，userData 存储区中的数据没有加密因而不安全的。任何可以访问 UserData 保存磁盘的应用都可以访问该数据，所以，推荐不要保存敏感的数据，比如信用卡号，详细：<a href="http://msdn.microsoft.com/en-us/library/ms531080(VS.85).aspx" target="_blank" title="Security Considerations: DHTML and Default Behaviors">《Security Considerations: DHTML and Default Behaviors》</a></p>
<p>3、userData behavior 会跨 session 存储信息到存储区，这提供了动态的数据结构和比 cookie（一般 4KB） 更大的容量。userData 存储区的容量依赖于<a href="http://msdn.microsoft.com/en-us/library/ms537186(VS.85).aspx" target="_blank" title="About URL Security Zones Templates"> domain 的安全域</a>。下表显示的是 userData 存储最大容量，对单独文档和整个域名的所有文档都适用，但基于安全域。</p>
<table>
<tbody>
<tr>
<th>Security Zone</th>
<th>Document Limit (KB)</th>
<th>Domain Limit (KB)</th>
</tr>
<tr>
<td>Local achine</td>
<td>128</td>
<td>1024</td>
</tr>
<tr>
<td>Intranet</td>
<td>512</td>
<td>10240</td>
</tr>
<tr>
<td>Trusted Sites</td>
<td>128</td>
<td>1024</td>
</tr>
<tr>
<td>Internet</td>
<td>128</td>
<td>1024</td>
</tr>
<tr>
<td>Restricted</td>
<td>64</td>
<td>640</td>
</tr>
</tbody>
</table>
<p>4、如果设置 userData behavior 到 html、head、title 或者 style 对象上，当 save 和 load 方法被调用时会出错。如果必须设置到 style 中，可以设置内联或者文档头，例如：</p>
<pre><code>&lt;style&gt;
    .storeuserData {behavior:url(#default#userData);}
&lt;/style&gt;</code></pre>
<p>5、对于 userData behavior 来说 ID 是可选的，但是如果有，则会改善执行性能。</p>
<p>6、userData 可以将数据以 XML 格式保存在客户端计算机上，一般保存在 C（WIN 系统盘）:\Documents and Settings\XXX\UserData\ 文件夹下。</p>
<p>7、userData 数据一直存在，除非人为删除或者用脚本设置该数据的失效日期（expires）。</p>
<p>大部分翻译自：<a href="http://msdn.microsoft.com/en-us/library/ms531424.aspx" target="_blank" title="userData Behavior">《userData Behavior》</a></p>
<img src="http://www.planabc.net/?ak_action=api_record_view&id=87&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.planabc.net/2008/08/05/userdata_behavior/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>Firefox 下 innerHTML 的一个 BUG</title>
		<link>http://www.planabc.net/2008/07/30/innerhtml_bug_in_firefox/</link>
		<comments>http://www.planabc.net/2008/07/30/innerhtml_bug_in_firefox/#comments</comments>
		<pubDate>Wed, 30 Jul 2008 07:43:09 +0000</pubDate>
		<dc:creator>怿飞</dc:creator>
				<category><![CDATA[JS/Ajax/AS/Flex]]></category>
		<category><![CDATA[bug]]></category>
		<category><![CDATA[Firfox]]></category>
		<category><![CDATA[innerHTML]]></category>

		<guid isPermaLink="false">http://www.planabc.net/?p=85</guid>
		<description><![CDATA[今天同事 明城 在项目中碰到一个 BUG，代码具体如下：
&#60;!DOCTYPE html PUBLIC &#34;-//W3C//DTD XHTML 1.0 Transitional//EN&#34; &#34;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&#34;&#62;
&#60;html xmlns=&#34;http://www.w3.org/1999/xhtml&#34;&#62;
&#60;head&#62;
&#60;meta http-equiv=&#34;Content-Type&#34; content=&#34;text/html; charset=gb2312&#34; /&#62;
&#60;title&#62;Firefox下innerHTML的一个BUG&#60;/title&#62;
&#60;style type=&#34;text/css&#34;&#62;
    a { display: block; border: 1px solid red;}
    div { display: inline; border: 1px solid red;}
&#60;/style&#62;
&#60;/head&#62;
&#60;body&#62;
&#60;a href=&#34;javascript:change();&#34;&#62;change&#60;div id=&#34;count&#34;&#62;20&#60;/div&#62;aaa&#60;/a&#62;
&#60;script type=&#34;text/javascript&#34;&#62;
function change() {
    var count = document.getElementById('count');
    var [...... ]]></description>
			<content:encoded><![CDATA[<p>今天同事 <a href="http://www.gracecode.com/" target="_blank" title="明城">明城</a> 在项目中碰到一个 BUG，代码具体如下：</p>
<pre><code>&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;
&lt;head&gt;
&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=gb2312&quot; /&gt;
&lt;title&gt;Firefox下innerHTML的一个BUG&lt;/title&gt;
&lt;style type=&quot;text/css&quot;&gt;
    a { display: block; border: 1px solid red;}
    div { display: inline; border: 1px solid red;}
&lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;a href=&quot;javascript:change();&quot;&gt;change&lt;div id=&quot;count&quot;&gt;20&lt;/div&gt;aaa&lt;/a&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
function change() {
    var count = document.getElementById('count');
    var c = count.innerHTML;
    var page = parseInt(c)+1;
    count.innerHTML = page;
    alert(page);
}
&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<p></code></p>
<p>当你在 Firefox2.0+ 或 Firefox3.0+ 中点击链接后，会发现 innerHTML 插入的内容为&lt;a&gt;21&lt;/a&gt;，而其他浏览器测试（IE6、IE7、Safari3.0+、Opera9.0+）都正常，插入内容均为文字 21。</p>
<p>估计是 Firefox 的一个 BUG，查找了官方网站的 <a href="https://bugzilla.mozilla.org/" target="_blank" title="Bugzilla@Mozilla">BUG库</a>，果真找到别人提交的该类问题——<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=381808" target="_blank" title="Setting innerHTML on a block element inside an inline element creates extra copies of the inline element">《Setting innerHTML on a block element inside an inline element creates extra copies of the inline element》</a>（Bug 381808）。</p>
<p>我们可以参阅下<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=381808#c8" target="_blank">8楼的 Boris Zbarsky</a> 给出的个人解释：</p>
<blockquote><p>There are two separate concepts of block vs inline.  One in CSS and one in<br />
HTML. They don't match.</p>
<p>In any case, the point is that in HTML &lt;b&gt; is not allowed to contain &lt;div&gt; (so<br />
the &lt;b&gt; needs to get closed), but the text needs to be bold for compat so we do<br />
residual style handling.  HTML5 is going to define a different method of doing<br />
this anyway, so at that point we'll need to revisit this bug.</p></blockquote>
<p>虽然这是一个 BUG，但 BUG 的造成也却是人为的不良习惯造成的，在 WEB 标准中严格来说内联元素是不允许包含块级元素的（扩展阅读：<a href="http://www.cs.tut.fi/~jkorpela/html/strict.html" target="_blank" title="Allowed nesting of elements in HTML 4 Strict (and XHTML 1.0 Strict)">《Allowed nesting of elements in HTML 4 Strict (and XHTML 1.0 Strict)》</a>）。</p>
<img src="http://www.planabc.net/?ak_action=api_record_view&id=85&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.planabc.net/2008/07/30/innerhtml_bug_in_firefox/feed/</wfw:commentRss>
		<slash:comments>18</slash:comments>
		</item>
		<item>
		<title>解决 IE6 内存泄露的另类方法</title>
		<link>http://www.planabc.net/2008/07/03/ie6_memory_leak_fix/</link>
		<comments>http://www.planabc.net/2008/07/03/ie6_memory_leak_fix/#comments</comments>
		<pubDate>Thu, 03 Jul 2008 05:46:39 +0000</pubDate>
		<dc:creator>怿飞</dc:creator>
				<category><![CDATA[JS/Ajax/AS/Flex]]></category>
		<category><![CDATA[IE6]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://www.planabc.net/?p=79</guid>
		<description><![CDATA[Hedger Wang 在国内 blog 上得到的方法：使用 try &#8230; finally 结构来使对象最终为 null ，以阻止内存泄露。
其中举了个例子：
function createButton() {
    var obj = document.createElement("button");
    obj.innerHTML = "click me";
    obj.onclick = function() {
        //handle onclick
    }

    obj.onmouseover = function() {
  [...... ]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.hedgerwow.com/" target="_blank" title="Hedger Wang">Hedger Wang</a> 在国内 blog 上得到的方法：使用 try &#8230; finally 结构来使对象最终为 null ，以阻止内存泄露。</p>
<p>其中举了个例子：</p>
<pre><code>function createButton() {
    var obj = document.createElement("button");
    obj.innerHTML = "click me";
    obj.onclick = function() {
        //handle onclick
    }

    obj.onmouseover = function() {
        //handle onmouseover
    }
    return obj;//return a object which has memory leak problem in IE6
}

var dButton = document.getElementById("d1").appendChild(createButton());
//skipped....</code></pre>
<p>对于 IE6 中，引起内存泄露的原因，可看<a href="http://msdn.microsoft.com/en-us/library/bb250448.aspx" target="_blank" title="Understanding and Solving Internet Explorer Leak Patterns">《Understanding and Solving Internet Explorer Leak Patterns》</a>一文。</p>
<p>上面的例子，应该属于上文中的 “Closures”原因。</p>
<p><img src="http://i.msdn.microsoft.com/Bb250448.ie_leak_patterns_fig02(en-us,VS.85).gif" alt="Circular Reference with Closures" /></p>
<p>再看下用  try &#8230; finally 的解决方法：</p>
<pre><code>/**
     * Use the try ... finally statement to resolve the memory leak issue
*/
 function createButton() {
    var obj = document.createElement("button");
    obj.innerHTML = "click me";
    obj.onclick = function() {
        //handle onclick
    }
    obj.onmouseover = function() {
        //handle onmouseover
    }

    //this helps to fix the memory leak issue
    try {
        return obj;
    } finally {
        obj = null;
    }
}

var dButton = document.getElementById("d1").appendChild(createButton());
//skipped....</code></pre>
<p>可能大家有疑问： finally 是如何解析的呢？</p>
<p>答案是：<strong>先执行 try 语句再执行 finally 语句。</strong></p>
<p>例如：</p>
<pre><code>function foo() {
    var x = 0;
    try {
        return print("call return " + (++x));
    } finally {
        print("call finally " + (++x));
    }
}

print('before');
print(foo());
print('after');</code></pre>
<p>返回的结果为：<br />
print » before<br />
print » call return 1<br />
print » call finally 2<br />
print » true<br />
print » after</p>
<p>更多详细的演示：<a href="http://www.hedgerwow.com/360/dhtml/ie6_memory_leak_fix/" target="_blank" title="Finally, the alternative fix for IE6's memory leak is available">《Finally, the alternative fix for IE6&#8217;s memory leak is available》</a></p>
<p>相关的一些讨论：<a href="http://ajaxian.com/archives/is-finally-the-answer-to-all-ie6-memory-leak-issues#comments" target="_blank" title="Is “finally” the answer to all IE6 memory leak issues?">《Is “finally” the answer to all IE6 memory leak issues?》</a></p>
<img src="http://www.planabc.net/?ak_action=api_record_view&id=79&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.planabc.net/2008/07/03/ie6_memory_leak_fix/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
	</channel>
</rss>
