<?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>Kane&#039;s Blog &#187; Javascript</title>
	<atom:link href="http://iamkane.com/index.php/archives/category/javascript/feed" rel="self" type="application/rss+xml" />
	<link>http://iamkane.com</link>
	<description>Bug can be anywhere,Can you find it?</description>
	<lastBuildDate>Mon, 21 Jun 2010 11:05:40 +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>通过事件委托来优化页面频繁绑定事件</title>
		<link>http://iamkane.com/index.php/archives/198</link>
		<comments>http://iamkane.com/index.php/archives/198#comments</comments>
		<pubDate>Thu, 22 Apr 2010 12:27:56 +0000</pubDate>
		<dc:creator>Kane</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[delegate]]></category>
		<category><![CDATA[事件委托]]></category>

		<guid isPermaLink="false">http://iamkane.com/?p=198</guid>
		<description><![CDATA[之前做了淘宝给的面试题，其中一题是 页面有 一个ul 里面有 n 个li， 而每个li在 mouseover 的时候，需要执行相应的function。 一般来做，我们会在每个 li上绑定 mouseover事件。而这套题的重点是怎么优化代码，提高效率。 在舜子提供的思路下，是把事件绑定在 li 的父级 ul 上面。 通过event 来判断当前对象。 这个思路，我感觉是叫时间委托吧，呵呵。代码如下：


function delegate(e){
				e = e &#124;&#124; window.event;
				return e.target &#124;&#124; e.srcElement;
			}

$(&#34;ul&#34;).bind(&#34;mouseover&#34;,function(e){
					var t = delegate(e), o=$(t),ul=o.parent(); //找到当前的对象

					if(o.is('li') &#38;&#38; ul.is('ul')) //判断对象
					{
						do something...
					}
				})

]]></description>
			<content:encoded><![CDATA[<p>之前做了淘宝给的面试题，其中一题是 页面有 一个ul 里面有 n 个li， 而每个li在 mouseover 的时候，需要执行相应的function。 一般来做，我们会在每个 li上绑定 mouseover事件。而这套题的重点是怎么优化代码，提高效率。 在舜子提供的思路下，是把事件绑定在 li 的父级 ul 上面。 通过event 来判断当前对象。 这个思路，我感觉是叫时间委托吧，呵呵。代码如下：</p>
<pre class="brush: jscript;">

function delegate(e){
				e = e || window.event;
				return e.target || e.srcElement;
			}

$(&quot;ul&quot;).bind(&quot;mouseover&quot;,function(e){
					var t = delegate(e), o=$(t),ul=o.parent(); //找到当前的对象

					if(o.is('li') &amp;&amp; ul.is('ul')) //判断对象
					{
						do something...
					}
				})
</pre>
]]></content:encoded>
			<wfw:commentRss>http://iamkane.com/index.php/archives/198/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>blur 与 focus 事件相处之道</title>
		<link>http://iamkane.com/index.php/archives/171</link>
		<comments>http://iamkane.com/index.php/archives/171#comments</comments>
		<pubDate>Wed, 10 Mar 2010 06:23:29 +0000</pubDate>
		<dc:creator>Kane</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[blur]]></category>
		<category><![CDATA[focus]]></category>

		<guid isPermaLink="false">http://iamkane.com/?p=171</guid>
		<description><![CDATA[表单的处理一般分成2种： field 单独 onblur 时进行验证并提示 与 在提交表单时验证全部 field (并行与单独验证)。 今天遇到了一个问题，可以说是低级错误。单独说一下 每个 field onblur 时验证的问题。


&#60;input type=&#34;text&#34; onblur=&#34;test(this)&#34; /&#62;

function test(o){
   if(document.getElementById(o).value=='')
   {
       alert('test');
       document.getElementById(o).focus();
    }
}

上面这种情况下是可以正常运行，但下面的情况是当多个field需要同时验证的时候就有问题了


&#60;input type=&#34;text&#34; onblur=&#34;test(this)&#34; /&#62;
&#60;input type=&#34;text&#34; onblur=&#34;test(this)&#34; /&#62;
function test(o){

if(document.getElementById(o).value=='')
 {
 alert('test');
 document.getElementById(o).focus();
 }
}

在这种情况下会出现死循环，到时IE 卡死 cpu100% [...]]]></description>
			<content:encoded><![CDATA[<p>表单的处理一般分成2种： field 单独 onblur 时进行验证并提示 与 在提交表单时验证全部 field (并行与单独验证)。 今天遇到了一个问题，可以说是低级错误。单独说一下 每个 field onblur 时验证的问题。</p>
<pre class="brush: xml;">

&lt;input type=&quot;text&quot; onblur=&quot;test(this)&quot; /&gt;

function test(o){
   if(document.getElementById(o).value=='')
   {
       alert('test');
       document.getElementById(o).focus();
    }
}
</pre>
<p>上面这种情况下是可以正常运行，但下面的情况是当多个field需要同时验证的时候就有问题了</p>
<pre class="brush: xml;">

&lt;input type=&quot;text&quot; onblur=&quot;test(this)&quot; /&gt;
&lt;input type=&quot;text&quot; onblur=&quot;test(this)&quot; /&gt;
function test(o){

if(document.getElementById(o).value=='')
 {
 alert('test');
 document.getElementById(o).focus();
 }
}
</pre>
<p>在这种情况下会出现死循环，到时IE 卡死 cpu100% 。解决方法就是多field的时候，不能 又blur又focus。 鱼与熊掌不可兼得也&#8230; </p>
]]></content:encoded>
			<wfw:commentRss>http://iamkane.com/index.php/archives/171/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>jquery1.42 $.ajax Memory Leak 内存泄露问题</title>
		<link>http://iamkane.com/index.php/archives/169</link>
		<comments>http://iamkane.com/index.php/archives/169#comments</comments>
		<pubDate>Fri, 05 Mar 2010 08:06:39 +0000</pubDate>
		<dc:creator>Kane</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[$.ajax]]></category>
		<category><![CDATA[Jquery]]></category>
		<category><![CDATA[jQuery1.4]]></category>
		<category><![CDATA[memory leak]]></category>
		<category><![CDATA[内存泄露]]></category>

		<guid isPermaLink="false">http://iamkane.com/?p=169</guid>
		<description><![CDATA[年后，把项目的jquery升级到1.42版本了，一直在想怎么优化原有的js。 因为一直在用FF调试，没留意IE。 今天用IE 试了下，居然发现了一个严重的bug。 IE 下 $.ajax 会导致内存泄露。一开始还不知道是 jquery的原因，到处找代码原因。最后在 小超 同志下的测试，发现了原来是 jquery 版本问题。 真折腾自己啊&#8230; 降回1.32 版本就不存在问题了。
在找内存泄露的过程中，找到了2个小软件 Drip-0.5  和  IEJSLeaksDetector 专门对IE内存泄露检测的2个工具。
]]></description>
			<content:encoded><![CDATA[<p>年后，把项目的jquery升级到1.42版本了，一直在想怎么优化原有的js。 因为一直在用FF调试，没留意IE。 今天用IE 试了下，居然发现了一个严重的bug。 IE 下 $.ajax 会导致内存泄露。一开始还不知道是 jquery的原因，到处找代码原因。最后在 小超 同志下的测试，发现了原来是 jquery 版本问题。 真折腾自己啊&#8230; 降回1.32 版本就不存在问题了。</p>
<p>在找内存泄露的过程中，找到了2个小软件 Drip-0.5  和  IEJSLeaksDetector 专门对IE内存泄露检测的2个工具。</p>
]]></content:encoded>
			<wfw:commentRss>http://iamkane.com/index.php/archives/169/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>兼容IE FF 的窗口标题栏跑马灯效果</title>
		<link>http://iamkane.com/index.php/archives/165</link>
		<comments>http://iamkane.com/index.php/archives/165#comments</comments>
		<pubDate>Fri, 05 Feb 2010 00:49:53 +0000</pubDate>
		<dc:creator>Kane</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[跑马灯]]></category>

		<guid isPermaLink="false">http://iamkane.com/?p=165</guid>
		<description><![CDATA[
仿WEB QQ 有新消息时，滚动窗口标题栏效果。  用了一个闭包的方法来实现。


/**
 * 调用方法
 * TitleFlash.stop();
 * TitleFlash.setTitle(str);
 * TitleFlash.go();
 */
var TitleFlash=(function(){

			var msg=&#34;&#34;;
			var msgud = &#34; &#34; + msg;
			var T;
			function titleScroll(){

				if (msgud.length &#60; msg.length)
					msgud += &#34; - &#34; + msg;
				msgud = msgud.substring(1, msgud.length);
				document.title = msgud.substring(0, msg.length);
				T=window.setTimeout(function(){titleScroll()},200)
			}
			return{
				setTitle: function(title){
					msg=title;
				},
				go:function(){
					titleScroll();
				},
				stop:function(){
					clearTimeout(T);
				}
			}

		})();

]]></description>
			<content:encoded><![CDATA[<h4>
仿WEB QQ 有新消息时，滚动窗口标题栏效果。  用了一个闭包的方法来实现。<br />
</h4>
<pre class="brush: jscript;">
/**
 * 调用方法
 * TitleFlash.stop();
 * TitleFlash.setTitle(str);
 * TitleFlash.go();
 */
var TitleFlash=(function(){

			var msg=&quot;&quot;;
			var msgud = &quot; &quot; + msg;
			var T;
			function titleScroll(){

				if (msgud.length &lt; msg.length)
					msgud += &quot; - &quot; + msg;
				msgud = msgud.substring(1, msgud.length);
				document.title = msgud.substring(0, msg.length);
				T=window.setTimeout(function(){titleScroll()},200)
			}
			return{
				setTitle: function(title){
					msg=title;
				},
				go:function(){
					titleScroll();
				},
				stop:function(){
					clearTimeout(T);
				}
			}

		})();
</pre>
]]></content:encoded>
			<wfw:commentRss>http://iamkane.com/index.php/archives/165/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>jQuery1.4 .change() 事件在IE下的bug？</title>
		<link>http://iamkane.com/index.php/archives/113</link>
		<comments>http://iamkane.com/index.php/archives/113#comments</comments>
		<pubDate>Tue, 19 Jan 2010 05:10:30 +0000</pubDate>
		<dc:creator>Kane</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[IE bug]]></category>
		<category><![CDATA[Jquery]]></category>
		<category><![CDATA[jQuery1.4]]></category>

		<guid isPermaLink="false">http://iamkane.com/?p=113</guid>
		<description><![CDATA[今天在项目里面，尝试使用 jQuery1.4 。 换了之后，感觉整个页面的交互是轻了，但是随之而来的是bug。 跟踪了一下，原来是 .change() 在IE下有一个这样的问题。 不知道是否jQuery 的bug了。代码如下：

&#60;select name=&#34;&#34; id=&#34;test&#34;&#62;
	&#60;option value=&#34;1&#34;&#62;1&#60;/option&#62;
	&#60;option value=&#34;2&#34; selected=&#34;selected&#34;&#62;2&#60;/option&#62;
	&#60;option value=&#34;3&#34;&#62;3&#60;/option&#62;
&#60;/select&#62;

&#60;select name=&#34;&#34; id=&#34;test2&#34;&#62;
	&#60;option value=&#34;1&#34;&#62;1&#60;/option&#62;
	&#60;option value=&#34;2&#34;&#62;2&#60;/option&#62;
	&#60;option value=&#34;3&#34;&#62;3&#60;/option&#62;
&#60;/select&#62;

&#60;script type=&#34;text/javascript&#34;&#62;
	$(function(){
			$(&#34;#test,#test2&#34;).change(function(){
				alert($(this).val());
			})
	})
&#60;/script&#62;

#test 下拉菜单默认绑定了2，在FF中是fire change 是鼠标点击option后，而在IE下是鼠标点了select就直接fire了。 郁闷&#8230;
]]></description>
			<content:encoded><![CDATA[<p>今天在项目里面，尝试使用 jQuery1.4 。 换了之后，感觉整个页面的交互是轻了，但是随之而来的是bug。 跟踪了一下，原来是 .change() 在IE下有一个这样的问题。 不知道是否jQuery 的bug了。代码如下：</p>
<pre class="brush: jscript;">
&lt;select name=&quot;&quot; id=&quot;test&quot;&gt;
	&lt;option value=&quot;1&quot;&gt;1&lt;/option&gt;
	&lt;option value=&quot;2&quot; selected=&quot;selected&quot;&gt;2&lt;/option&gt;
	&lt;option value=&quot;3&quot;&gt;3&lt;/option&gt;
&lt;/select&gt;

&lt;select name=&quot;&quot; id=&quot;test2&quot;&gt;
	&lt;option value=&quot;1&quot;&gt;1&lt;/option&gt;
	&lt;option value=&quot;2&quot;&gt;2&lt;/option&gt;
	&lt;option value=&quot;3&quot;&gt;3&lt;/option&gt;
&lt;/select&gt;

&lt;script type=&quot;text/javascript&quot;&gt;
	$(function(){
			$(&quot;#test,#test2&quot;).change(function(){
				alert($(this).val());
			})
	})
&lt;/script&gt;
</pre>
<p>#test 下拉菜单默认绑定了2，在FF中是fire change 是鼠标点击option后，而在IE下是鼠标点了select就直接fire了。 郁闷&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://iamkane.com/index.php/archives/113/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>2组 json diff 对比</title>
		<link>http://iamkane.com/index.php/archives/54</link>
		<comments>http://iamkane.com/index.php/archives/54#comments</comments>
		<pubDate>Wed, 02 Dec 2009 14:12:19 +0000</pubDate>
		<dc:creator>Kane</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[array]]></category>
		<category><![CDATA[json]]></category>

		<guid isPermaLink="false">http://iamkane.com/?p=54</guid>
		<description><![CDATA[


/**
*@jsonDataHandler.diff(json1,json2)
*/

Array.prototype.compareTo = function(compareAry) {
if (this.length === compareAry.length) {
var i;
for (i = 0; i &#60; compareAry.length; i+=1) {
if (Object.isArray(this[i]) === true) {
if (this[i].compareTo(compareAry[i]) === false) {
return false;
}
continue;
}
else if (this[i] !== compareAry[i]) {
return false;
}
}
return true;
}
return false;
};

(function() {
var _toString = Object.prototype.toString;
function extend(destination, source) {
for (var property in source)
destination[property] = source[property];
return destination;
}
function keys(object) {
var results = [];
for (var property [...]]]></description>
			<content:encoded><![CDATA[<p><code>
<pre class="brush: jscript;">

/**
*@jsonDataHandler.diff(json1,json2)
*/

Array.prototype.compareTo = function(compareAry) {
if (this.length === compareAry.length) {
var i;
for (i = 0; i &lt; compareAry.length; i+=1) {
if (Object.isArray(this[i]) === true) {
if (this[i].compareTo(compareAry[i]) === false) {
return false;
}
continue;
}
else if (this[i] !== compareAry[i]) {
return false;
}
}
return true;
}
return false;
};

(function() {
var _toString = Object.prototype.toString;
function extend(destination, source) {
for (var property in source)
destination[property] = source[property];
return destination;
}
function keys(object) {
var results = [];
for (var property in object)
results.push(property);
return results;
}
function isArray(object) {
return _toString.call(object) == &quot;[object Array]&quot;;
}
extend(Object, {
extend:        extend,
keys:          keys,
isArray:       isArray
});
})();
(function() {
var arrayProto = Array.prototype;

function indexOf(item, i) {
i || (i = 0);
var length = this.length;
if (i &lt; 0) i = length + i;
for (; i &lt; length; i++)
if (this[i] === item) return i;
return -1;
}

if (!arrayProto.indexOf) arrayProto.indexOf = indexOf;

})();
var jsonDataHandler = {
merge: function(j1, j2) {
if (typeof this.merging === &quot;undefined&quot; || this.merging === 0) {
this.mergeCyclicCheck = [];
this.merging = 0;
}
this.merging += 1;
if (typeof j1 === &quot;undefined&quot;) {
j1 = {};
}
if (typeof j2 === &quot;undefined&quot;) {
j2 = {};
}
if (typeof this.mergeCyclicCheck === &quot;undefined&quot;) {
this.mergeCyclicCheck = [];
}
var key;
for (key in j2) if (j2.hasOwnProperty(key)) {
if (typeof j1[key] === &quot;undefined&quot;) {
j1[key] = j2[key];
}
else {
if (typeof j2[key] === &quot;object&quot;) {
if (this.mergeCyclicCheck.indexOf(j1[key]) &gt;= 0) {
break;
}
this.merge(j1[key], j2[key]);
this.mergeCyclicCheck.push(j1[key]);
}
else {
j1[key] = j2[key];
}
}
}
this.merging -= 1;
},
diff: function(j1, j2) {
if (typeof this.diffing === &quot;undefined&quot; || this.diffing === 0) {
this.diffCyclicCheck = [];
this.diffing = 0;
}
var diffRes = {};
this.diffing += 1;
if (typeof j1 === &quot;undefined&quot;) {
j1 = {};
}
if (typeof j2 === &quot;undefined&quot;) {
j2 = {};
}
if (typeof this.diffCyclicCheck === &quot;undefined&quot;) {
this.diffCyclicCheck = [];
}
var key, bDiff;
for (key in j2) if (j2.hasOwnProperty(key)) {
bDiff = false;
if (typeof j1[key] === &quot;undefined&quot; || typeof j1[key] != typeof j2[key]) {
bDiff = true;
}
else if (j1[key] !== j2[key]) {
if (typeof j2[key] === &quot;object&quot;) {
if (this.diffCyclicCheck.indexOf(j2[key]) &gt;= 0) {
break;
}
else if (Object.isArray(j2[key])) {
if (j1[key].length !== j2[key].length || j1[key] !== j2[key]) {
if (j2[key].compareTo(j1[key]) === false) {
bDiff = true;
}
}
}
else if (typeof j1[key] === &quot;object&quot;) {
var dR = this.diff(j1[key], j2[key]);
if (Object.keys(dR).length &gt; 0) {
diffRes[key] = dR;
}
}
else {
bDiff = true;
}
this.diffCyclicCheck.push(j2[key]);
}
else if (j1[key] !== j2[key]) {
bDiff = true;
}
}
if (bDiff) {
diffRes[key] = j2[key];
}
}
for (key in j1) if (j1.hasOwnProperty(key)) {
bDiff = false;
if (typeof j2[key] === &quot;undefined&quot;) {
diffRes[key] = j1[key];
}
}
this.diffing -= 1;
return diffRes;
}
};
</pre>
]]></content:encoded>
			<wfw:commentRss>http://iamkane.com/index.php/archives/54/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>2组Array diff 对比</title>
		<link>http://iamkane.com/index.php/archives/53</link>
		<comments>http://iamkane.com/index.php/archives/53#comments</comments>
		<pubDate>Wed, 02 Dec 2009 09:12:28 +0000</pubDate>
		<dc:creator>Kane</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[array]]></category>
		<category><![CDATA[json]]></category>

		<guid isPermaLink="false">http://iamkane.com/?p=53</guid>
		<description><![CDATA[2组array 进行对比，取其差异部分。
&#160;

/**
* @array_diff(new,old)
*/

function array_diff(){var arr1=arguments[0],retArr={};var k1='',i=1,k='',arr={};arr1keys:for(k1 in arr1){for(i=1;i&#38;lt;arguments.length;i++){arr=arguments[i];for(k in arr){if(arr[k]===arr1[k1]){continue arr1keys;}}

retArr[k1]=arr1[k1];}}

return retArr;}

]]></description>
			<content:encoded><![CDATA[<p>2组array 进行对比，取其差异部分。</p>
<p>&nbsp;</p>
<pre class="brush: jscript;">
/**
* @array_diff(new,old)
*/

function array_diff(){var arr1=arguments[0],retArr={};var k1='',i=1,k='',arr={};arr1keys:for(k1 in arr1){for(i=1;i&amp;lt;arguments.length;i++){arr=arguments[i];for(k in arr){if(arr[k]===arr1[k1]){continue arr1keys;}}

retArr[k1]=arr1[k1];}}

return retArr;}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://iamkane.com/index.php/archives/53/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Javascript 闭包Closure 的入门与运用</title>
		<link>http://iamkane.com/index.php/archives/51</link>
		<comments>http://iamkane.com/index.php/archives/51#comments</comments>
		<pubDate>Tue, 10 Nov 2009 10:48:26 +0000</pubDate>
		<dc:creator>Kane</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[闭包]]></category>

		<guid isPermaLink="false">http://iamkane.com/?p=51</guid>
		<description><![CDATA[闭包这个词看过很多网站都有说。大家说的方法都大致一样。 今天看了一些大陆的文章，看到我头晕眼花，没看懂它的真正意识。 找了篇 Mozilla 关于闭包运用的文章。 讲述的比较系统易懂。
&#160;



&#160;
1. 闭包的运用


1.1. 实用的闭包


1.2. 使用闭包模拟私有的方法


1.3. 在循环中建立闭包︰常见的错误


1.4. 效能的考虑






闭包的运用
闭包（Closure）经常会被认为是 JavaScript 的高级机能，但了解闭包是精通语言的必要之事。
思考以下的函数︰

function init() {
  var name = &#38;quot;Mozilla&#38;quot;;
  function displayName() {
    alert(name);
  }
  displayName();
}
init() 函数建立了称为 name 的局域变量，然后定义了称为 displayName() 的函数。displayName() 是内部的函数 &#8211; 他是在 init() 内部定义的，而且只在函数本体内部才可使用。displayName() 没有他自己的局域变量，但会重复使用在外部函数里所宣告的 name 变量。
本例只会做一点事 &#8211; 试试执行代码看会发生什么。这是词汇作用域的范例︰在 JavaScript 中，变量的作用域是由他自己在原始码中的位置所定义的，且内部的函数能够存取宣告于外部作用域的变量。
现在思考下例︰

function makeFunc() {
  var name = [...]]]></description>
			<content:encoded><![CDATA[<p>闭包这个词看过很多网站都有说。大家说的方法都大致一样。 今天看了一些大陆的文章，看到我头晕眼花，没看懂它的真正意识。 找了篇 Mozilla 关于闭包运用的文章。 讲述的比较系统易懂。</p>
<div id="page-up&#100;ate" class="pageStatus  hastoc">&nbsp;</div>
<div id="page-top">
<div id="pageToc">
<div class="pageToc">
<h5>&nbsp;</h5>
<h3><span>1.</span> <a href="#.e9.96.89.e5.8c.85.e7.9a.84.e9.81.8b.e7.94.a8" rel="internal">闭包的运用</a></h3>
<ol style="list-style-type: none; margin-left: 0px; padding-left: 0px;">
<li>
<h3><span>1.1.</span> <a href="#.e5.af.a6.e7.94.a8.e7.9a.84.e9.96.89.e5.8c.85" rel="internal">实用的闭包</a></h3>
</li>
<li>
<h3><span>1.2.</span> <a href="#.e4.bd.bf.e7.94.a8.e9.96.89.e5.8c.85.e6.a8.a1.e6.93.ac.e7.a7.81.e6.9c.89.e7.9a.84.e6.96.b9.e6.b3.95" rel="internal">使用闭包模拟私有的方法</a></h3>
</li>
<li>
<h3><span>1.3.</span> <a href="#.e5.9c.a8.e5.be.aa.e7.92.b0.e4.b8.ad.e5.bb.ba.e7.ab.8b.e9.96.89.e5.8c.85.ef.b8.b0.e5.b8.b8.e8.a6.8b.e7.9a.84.e9.8c.af.e8.aa.a4" rel="internal">在循环中建立闭包︰常见的错误</a></h3>
</li>
<li>
<h3><span>1.4.</span> <a href="#.e6.95.88.e8.83.bd.e7.9a.84.e8.80.83.e9.87.8f" rel="internal">效能的考虑</a></h3>
</li>
</ol>
</div>
</div>
<div class="pageText" id="pageText">
<div id="section_1">
<h3 class="editable">闭包的运用</h3>
<p>闭包（Closure）经常会被认为是 JavaScript 的高级机能，但了解闭包是精通语言的必要之事。</p>
<p>思考以下的函数︰</p>
<pre class="brush: jscript;">
function init() {
  var name = &amp;quot;Mozilla&amp;quot;;
  function displayName() {
    alert(name);
  }
  displayName();
}</pre>
<p><code>init()</code> 函数建立了称为 <code>name</code> 的局域变量，然后定义了称为 <code>displayName()</code> 的函数。<code>displayName()</code> 是内部的函数 &#8211; 他是在 <code>init()</code> 内部定义的，而且只在函数本体内部才可使用。<code>displayName()</code> 没有他自己的局域变量，但会重复使用在外部函数里所宣告的 name 变量。</p>
<p>本例只会做一点事 &#8211; 试试执行代码看会发生什么。这是<em>词汇作用域</em>的范例︰在 JavaScript 中，变量的作用域是由他自己在原始码中的位置所定义的，且内部的函数能够存取宣告于外部作用域的变量。</p>
<p>现在思考下例︰</p>
<pre class="brush: jscript;">
function makeFunc() {
  var name = &amp;quot;Mozilla&amp;quot;;
  function displayName() {
    alert(name);
  }
  return displayName;
}

var myFunc = makeFunc();
myFunc();</pre>
<p>如果你执行这个代码，将会发生和前一个 <code>init()</code> 例子完全相同的效果︰字符串 &quot;Mozilla&quot; 将会被显示在 JavaScript 的警告方框中。其中的不同点 &#8211; 以及有趣的一点 &#8211; 是内部的 <code>displayName()</code> 函数会在执行之前从外部的函数所返回。</p>
<p>代码的运作看起来也许很不直觉。通常说，在函数内部的局域变量只存在于函数执行的期间。一旦 <code>makeFunc()</code> 执行完毕，预期不再需要 name 变量是很合理的。由于代码仍旧以预期般的运作，很明显情况并不如此。</p>
<p>对于这个难题的解答是 <code>myFunc</code> 已经变成<em>闭包</em>了。闭包是一种特殊的对象，其中结合了两样东西︰函数，和函数所建立的环境。环境由任意的局域变量所组成，这些变量是由在闭包建立的时间点上存在于作用域里的所有变量。既然如此，<code>myFunc</code> 就是结合了 <code>displayName</code> 函数和闭包建立之后就存在的 &quot;Mozilla&quot; 字符串这两者的闭包。</p>
<p>这里还有更为有趣的范例 &#8211; <code>makeAdder</code> 函数︰</p>
<pre class="brush: jscript;">
function makeAdder(x) {
  return function(y) {
    return x + y;
  };
}

var add5 = makeAdder(5);
var add10 = makeAdder(10);

print(add5(2));  // 7
print(add10(2)); // 12</pre>
<p>在这个范例中，我们已经定义了函数 <code>makeAdder(x)</code>，可接受单一参数 <code>x</code>，并返回新的函数。返回的函数会接受单一参数 <code>y</code>，并返回 <code>x</code> 和 <code>y</code> 的合。</p>
<p>就本质而言，<code>makeAdder</code> 是函数的制造机 &#8211; 他会建立可以把指定的值和他们的参数相加的函数。在上例中，我们使用了我们的函数制造机来建立两个新的函数 &#8211; 一个给他自己的参数加上 5，另一个则加上 10。</p>
<p><code>add5</code> 和 <code>add10</code> 两个都是闭包。他们共享相同的函数本体的定义，但保存了不同的环境变量。在 <code>add5</code> 的环境中，<code>x</code> 是 5。至于互有关连的 <code>add10</code>，<code>x</code> 是 10。</p>
<div id="section_2">
<h4 class="editable">实用的闭包</h4>
<p>该是抛开理论的时候了 &#8211; 但是闭包真的有用吗？让我们思考闭包潜在的用处。闭包让你把一些数据（环境）和可操作数据的函数联系在一起。这一点明显和面向对象程序设式并行不悖，对象可让我们把一些数据（对象的属性）和一个以上的方法联系在一起。</p>
<p>因此，如果通常你会在某个地方使用附有单一方法的对象，你可以在这些地方使用闭包。</p>
<p>视情况你可能会想这样做，这在 Web 上尤其常见。我们写在 Web 上的 JavaScript 代码多半是以事件为基础 &#8211; 我们定义了一些行为，然后把这些行为和由使用者所触发的事件（如 click 或 keypress）连系在一起。我们的代码通常被连系为 Callback︰在响应事件时，所执行的单一函数。</p>
<p>这里有个实际的例子︰假如我们希望在页面上加入可以调整页面文字的按钮。以像素为单位，指定 body 元素的 font-size 是一个方法，然后以 em 为单位，设定在页面上（如页眉）的其他元素的大小︰</p>
<pre name="code" class="css">
body {
  font-family: Helvetica, Aria, sans-serif;
  font-size: 12px;
}

h1 {
  font-size: 1.5em;
}
h2 {
  font-size: 1.2em;
}[/code]

我们的交互式文字大小按钮可以改变 body 元素的 font-size 属性，拜相对单位之赐，接着对其他的元素做调整。

JavaScript 代码︰
<pre class="brush: jscript;">
function makeSizer(size) {
  return function() {
    document.body.style.fontSize = size + 'px';
  };
}

var size12 = makeSizer(12);
var size14 = makeSizer(14);
var size16 = makeSizer(16);</pre>
<p>现在 <code>size12</code>、<code>size14</code> 和 <code>size16</code> 这些函数可分别调整 body 文字的大小为 12、14 和 16 像素。我们可以把代码和按钮（本例中使用的是连结）连系在一起，如下︰</p>
<pre class="brush: jscript;">
function setupButtons() {
  document.getElementById('size-12').onclick = size12;
  document.getElementById('size-14').onclick = size14;
  document.getElementById('size-16').onclick = size16;
}</pre>
<pre class="brush: xml;">
&amp;lt;a href=&amp;quot;#&amp;quot; id=&amp;quot;size-12&amp;quot;&amp;gt;12&amp;lt;/a&amp;gt;
&amp;lt;a href=&amp;quot;#&amp;quot; id=&amp;quot;size-14&amp;quot;&amp;gt;14&amp;lt;/a&amp;gt;
&amp;lt;a href=&amp;quot;#&amp;quot; id=&amp;quot;size-16&amp;quot;&amp;gt;16&amp;lt;/a&amp;gt;</pre>
<p>&nbsp;</p>
</div>
<div id="section_3">
<h4 class="editable">使用闭包模拟私有的方法</h4>
<p>像 Java 这类语言可以把方法宣告为私有的，意思是这些方法只能被同一类别的其他方法所呼叫。</p>
<p>JavaScript 并不提供做这些事的原生方式，但可以使用闭包来模拟私有方法。私有方法不只是对限制代码的存取这方面有用︰同时也是管理你的全局命名空间的强大方式，把非必要的方法堆在公开的界面里。</p>
<p>这里是如何使用闭包来定义可以存取私有函数和变量的公开函数︰</p>
<pre class="brush: jscript;">
var Counter = (function() {
  var privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }
  return {
    increment: function() {
      changeBy(1);
    },
    decrement: function() {
      changeBy(-1);
    },
    value: function() {
      return privateCounter;
    }
  }
})();

alert(Counter.value()); /* 显示 0 */
Counter.increment();
Counter.increment();
alert(Counter.value()); /* 显示 2 */
Counter.decrement();
alert(Counter.value()); /* 显示 1 */</pre>
<p>在此完成了很多事。在上一个范例中，每一个闭包都有他自己的环境；此处我们建立了由三个函数所共享的单一环境<span style="font-family: monospace;">︰</span><code>Counter.increment</code>、<code>Counter.decrement</code>、<code>Counter.value</code>。</p>
<p>共享的环境是建立在无名函数的本体内，无名函数一经定义就会开始执行。环境内含两个私有项︰称作 <code>privateCounter</code> 的变量，以及称作 <code>changeBy</code> 的函数。这两个私有项都不能在无名函数外部被直接存取。相对的，必须由三个公开的函数来存取这些私有项，这三个函数是从无名函数的封装器所返回的。</p>
<p>这三个公开的函数共享闭包的同一个环境。感谢 JavaScript 的词汇作用域，这三个函数都能存取 <code>privateCounter</code> 变量和 <code>changeBy</code> 函数。</p>
<p>按照这个方式来运用闭包，可以得到通常是附加在面向对象程序设计里的数据隐藏和封装的好处。</p>
</div>
<div id="section_4">
<h4 class="editable">在循环中建立闭包︰常见的错误</h4>
<p>在 JavaScript 1.7 引入 <code>let</code> 关键词以前，闭包常见的问题出现在当闭包是在循环内部建立的时候。思考以下的例子︰</p>
<pre class="brush: xml;">
&amp;lt;p id=&amp;quot;help&amp;quot;&amp;gt;这里会显示有用的提示&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;E-mail: &amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;email&amp;quot; name=&amp;quot;email&amp;quot;&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;姓名: &amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;name&amp;quot; name=&amp;quot;name&amp;quot;&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;年龄: &amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;age&amp;quot; name=&amp;quot;age&amp;quot;&amp;gt;&amp;lt;/p&amp;gt;</pre>
<pre name="code" class="brush:js">
function showHelp(help) {
  document.getElementById('help').innerHTML = help;
}

function setupHelp() {
  var helpText = [
      {'id': 'email', 'help': '你的 e-mail 地址'},
      {'id': 'name', 'help': '你的完整姓名'},
      {'id': 'age', 'help': '你的年龄（你必须大于 16 岁）'}
    ];

  for (var i = 0; i &lt; helpText.length; i++) {
    var item = helpText[i];
    document.getElementById(item.id).onfocus = function() {
      showHelp(item.help);
    }
  }
}[/code]

<code>helpText</code> 数组定义了三个有用的提示，每一个都和文件中的输入字段的 ID 连系在一起。循环会在这些定义里巡回一圈，给每一个显示相关连的说明的方法使用 onfocus 事件。

如果你试着执行这个代码，你会发现他并不如预期般的运作。不管你把焦点放在哪一个字段上，都会显示关于你的年龄的讯息。

这其中的原因是代入给 onfocus 的函数是闭包；这些闭包是由函数的定义和从 <code>setupHelp</code> 函数的作用域所捕捉到的环境所组成的。这三个闭包已经建立了，但每一个都共享同一个环境。每次执行 onfocus 的 Callback 的时候，循环执行的是他自己的闭包，以及指向 <code>helpText</code> 列表中的最后一项的变量 item（由三个闭包所共享）。

本例的解决方法是使用更多的闭包︰特别是使用稍早已描述过的函数制造机︰
<pre class="brush: jscript;">
function showHelp(help) {
  document.getElementById('help').innerHTML = help;
}

function makeHelpCallback(help) {
  return function() {
    showHelp(help);
  };
}

function setupHelp() {
  var helpText = [
      {'id': 'email', 'help': '你的 e-mail 地址'},
      {'id': 'name', 'help': '你的完整姓名'},
      {'id': 'age', 'help': '你的年龄（你必须大于 16 岁）'}
    ];

  for (var i = 0; i &amp;lt; helpText.length; i++) {
    var item = helpText[i];
    document.getElementById(item.id).onfocus = makeHelpCallback(item.help);
  }
}</pre>
<p>这次就如预期般运作。而不是所有的 Callback 都共享单一的环境，<code>makeHelpCallback</code> 给每一个 <code>help</code> 建立新的环境，此处的 <code>help</code> 参照了相对应的 <code>helpText</code> 数组的字符串。</p>
<p>如果你使用 JavaScript 1.7 以上的版本，你可以使用 <code>let</code> 关键词建立具有区块层级作用域的变量来解决这个问题︰</p>
<pre class="brush: jscript;">
for (var i = 0; i &amp;lt; helpText.length; i++) {
    let item = helpText[i];
    document.getElementById(item.id).onfocus = function() {
      showHelp(item.help);
    }
  }</pre>
<p><code>let</code> 关键词使 item 变量改用具有区块层级的作用域来建立，导致 for 循环每一次反复都能建立新的参考。意思是每一个闭包都会捕捉到个别的变量，解决因为共享同一环境所引起的问题。</p>
</div>
<div id="section_5">
<h4 class="editable">效能的考虑</h4>
<p>如果并没有特定的任务需要用到闭包，且闭包对 Script 的效能会有负面的影响，因此在其他函数的内部里建立不必要的函数是很不智的。</p>
<p>例如，当建立新的对象或类别时，通常应该要把方法和对象的原型连系在一起，而不是在对象的建构子中定义。这其中的理由是，每当呼叫建构子的时候，就要把方法代入（也就是每一个对象正在建立的时候）。</p>
<p>思考以下不切实际的例子︰</p>
<pre class="brush: jscript;">
function MyObject(name, message) {
  this.name = String(name);
  this.message = String(message);
  this.getName = function() {
    return this.name;
  };

  this.getMessage = function() {
    return this.message;
  };
}</pre>
<p>上面的代码并未从闭包的行为中取得好处，应该改用重整过的形式︰</p>
<pre class="brush: jscript;">
function MyObject(name, message) {
  this.name = String(name);
  this.message = String(message);
}
MyObject.prototype = {
  getName: function() {
    return this.name;
  },
  getMessage: function() {
    return this.message;
  }
};</pre>
<p>或者是︰</p>
<pre class="brush: jscript;">
function MyObject(name, message) {
  this.name = String(name);
  this.message = String(message);
}
MyObject.prototype.getName = function() {
  return this.name;
};
MyObject.prototype.getMessage = function() {
  return this.message;
};</pre>
</div>
</div>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://iamkane.com/index.php/archives/51/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>jQuery Tagger 插件- 一个输入框实现多项，以数组形式提交</title>
		<link>http://iamkane.com/index.php/archives/50</link>
		<comments>http://iamkane.com/index.php/archives/50#comments</comments>
		<pubDate>Wed, 04 Nov 2009 07:06:39 +0000</pubDate>
		<dc:creator>Kane</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Jquery]]></category>

		<guid isPermaLink="false">http://iamkane.com/?p=50</guid>
		<description><![CDATA[今天无聊，逛了下Jquery 插件超市，看到个 Tagger插件。&#160; 现在我们写Blog，填写 Tag的时候，多数都是用分号逗号方式隔开。而这个插件使用了input 数组的方式。原理使用相同的name：&#60;input type=&#34;text&#34; name=&#34;test[]&#34;/&#62;
接收的时候，会以数组的形式接收。 看看具体的 Demo

]]></description>
			<content:encoded><![CDATA[<p>今天无聊，逛了下Jquery 插件超市，看到个 Tagger插件。&nbsp; 现在我们写Blog，填写 Tag的时候，多数都是用分号逗号方式隔开。而这个插件使用了input 数组的方式。原理使用相同的name：&lt;input type=&quot;text&quot; name=&quot;test[]&quot;/&gt;</p>
<p>接收的时候，会以数组的形式接收。 看看具体的 <a href="http://chrisiufer.com/tagger/" target="_blank"><span style="font-size: 18px;">Demo</span></a></p>
<p><img width="24" height="24" id="myFxSearchImg" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAADsElEQVR4nK2VTW9VVRSGn33OPgWpYLARbKWhQlCHTogoSkjEkQwclEQcNJEwlfgD/AM6NBo1xjhx5LyJ0cYEDHGkJqhtBGKUpm3SFii3vb2956wPB/t+9raEgSs52fuus89613rftdcNH8/c9q9++oe/Vzb5P+3McyNcfm2CcPj9af9w6gwjTwzvethx3Bx3x8xwd1wNM8dMcTNUHTfFLPnX6nVmZpeIYwf3cWD/PhbrvlPkblAzVFurKS6GmmGqqComaS+qmBoTI0Ncu3mXuGvWnrJ+ZSxweDgnkHf8ndVTdbiT3M7cQp2Z31dRTecHAfqydp4ejhwazh6Zezfnu98E1WIQwB3crEuJ2Y45PBTAQUVR9X4At66AppoEVO1Q8sgAOKJJjw6Am6OquDmvHskZ3R87gW+vlHz98zpmiqphkkRVbQtsfPTOC30lJKFbFTgp83bWh7Zx/uX1B6w3hI3NkkZTqEpBRDBRzG2AQHcwcYwEkOGkTERREbLQ/8HxJwuW7zdYrzfZ2iopy4qqEspKaDYravVm33k1R91Q69FA1VBRzFIVvXbx5AgXT44A8MWP81yfu0utIR2aVK3vfCnGrcUNxp8a7gKYKiLCvY2SUvo/aNtnM3e49ucK9S3p0aDdaT0UAVsKi2tVi6IWwNL9JvdqTdihaz79/l+u/rHMxmaJVMLkS2OoKKLWacdeE3IsSxctc2D5Qcl6vUlVVgNt+fkPPcFFmTw1xruvT7SCd7nuVhDQvECzJH90h0azRKoKFRkAmP5lKTWAGRdefoZL554FQNUxB92WvYeA5UN4PtSqwB2phKqsqMpBgAunRhFR3j49zuU3jnX8k6fHEQKXzh1jbmGDuYU6s4t1rt6socUeLLZHhYO2AHSHmzt19ihTZ48O8Hzl/AmunD/BjTvrvPfNX3hWsNpwJCvwYm+ngug4UilSCSq6k8YPtxDwfA+WRawIWFbgscDiULcCEaWqBFOlrLazurupOSHLqGnEKJAY8TwBEHumqUirAjNm52vEPPRV4p01XXMPAQhUBjcWm9QZwijwokgAeYHlHYA06KR1cT6ZvoV56pDUJQEjw0KeaMgj1hPEY4vz2A4eW0/e1qA7KtQdsxTYAG0H3iG4xyK1Y+xm7XmEPOJZDiENzLi2WZHngeOjj2Pe+sMg4GRYyLAsx7ME4FnsyTD9pr0PEc8zPGRAwKXBkYOPEd96cZRvf11g9MDe7e3R4Z4Q+vyEnn3P4t0XzK/W+ODN5/kPfRLewAJVEQ0AAAAASUVORK5CYII%3D" style="border: medium none ; position: absolute; z-index: 2147483647; opacity: 0.6; display: none;" alt="" hidden="true" /></p>
]]></content:encoded>
			<wfw:commentRss>http://iamkane.com/index.php/archives/50/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Jquery 判断DOM对象是否存在</title>
		<link>http://iamkane.com/index.php/archives/47</link>
		<comments>http://iamkane.com/index.php/archives/47#comments</comments>
		<pubDate>Tue, 28 Jul 2009 01:18:00 +0000</pubDate>
		<dc:creator>Kane</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Jquery]]></category>

		<guid isPermaLink="false">http://iamkane.com/?p=47</guid>
		<description><![CDATA[最近在研究 greenmonkey ，发现 userscripts.org 里面提供了很多网站的一些 script。
回归正题，jquery 如何判断DOM 是否存在..
if($(&#34;#test&#34;).length&#62;0)&#160; 或者&#160; if($(&#34;#test&#34;).size()&#62;0)
&#160;
&#160;
]]></description>
			<content:encoded><![CDATA[<p>最近在研究 greenmonkey ，发现 <a target="_blank" href="http://userscripts.org.">userscripts.org</a> 里面提供了很多网站的一些 script。</p>
<p>回归正题，jquery 如何判断DOM 是否存在..</p>
<p>if($(&quot;#test&quot;).length&gt;0)&nbsp; 或者&nbsp; if($(&quot;#test&quot;).size()&gt;0)</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://iamkane.com/index.php/archives/47/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
