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

<channel>
	<title>西红柿爱番茄 &#187; Javascript</title>
	<atom:link href="http://www.ilovejs.net/archives/tag/javascript/feed" rel="self" type="application/rss+xml" />
	<link>http://www.ilovejs.net</link>
	<description>到了创造为主的阶段，不忘继续学习</description>
	<lastBuildDate>Thu, 15 Dec 2011 06:18:39 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>美化按需加载js文件的形式</title>
		<link>http://www.ilovejs.net/archives/1545</link>
		<comments>http://www.ilovejs.net/archives/1545#comments</comments>
		<pubDate>Sun, 03 Jul 2011 03:41:43 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[代码设计]]></category>
		<category><![CDATA[按需加载]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1545</guid>
		<description><![CDATA[按需加载，顾名思义就是在用户需要这个功能的时候就初始化这个功能，加载相关的脚本和样式文件等等。普通我们使用的方式，就是在需要的时候，就添加一个文件的url进行加载，并且用一个对象来记录已经加载过的文件。这种方式有些散乱，对于是随意加载的，那倒是不可避免，但是对于一个项目来说，页面的的功能和相应的文件是确定的，那么还是使用上面的方式的话，那么在后期的维护上会比较混乱，增加了成本。 对项目之外的文件加载，使用普通的方式散乱在代码中，也不太合适，那么就需要一个封装的加载器，统一加载文件的接口和调用方式。我下面将要讲的“加载器”，不是传说中的模块化中的加在方式，我更多的是从代码维护方面来考虑，使得一目了然的看到页面本身的功能需要按需加载一些什么文件列表，并且可以标记已经加载的文件，而不会使得url散乱在页面中。 //需要按需加载的内部文件列表映射 mis.classFiles = { 'AjaxEvent': 'includes/ajax.lib.js', 'AjaxRequest': 'includes/request.lib.js', 'colorFade': 'includes/effects.lib.js' } //标记已经include的内部文件 mis.includedFiles = {}; //对内的文件加载 mis.include = &#8230; <a href="http://www.ilovejs.net/archives/1545" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
按需加载，顾名思义就是在用户需要这个功能的时候就初始化这个功能，加载相关的脚本和样式文件等等。普通我们使用的方式，就是在需要的时候，就添加一个文件的url进行加载，并且用一个对象来记录已经加载过的文件。这种方式有些散乱，对于是随意加载的，那倒是不可避免，但是对于一个项目来说，页面的的功能和相应的文件是确定的，那么还是使用上面的方式的话，那么在后期的维护上会比较混乱，增加了成本。
</p>
<p>
对项目之外的文件加载，使用普通的方式散乱在代码中，也不太合适，那么就需要一个封装的加载器，统一加载文件的接口和调用方式。我下面将要讲的“加载器”，不是传说中的模块化中的加在方式，我更多的是从代码维护方面来考虑，使得一目了然的看到页面本身的功能需要按需加载一些什么文件列表，并且可以标记已经加载的文件，而不会使得url散乱在页面中。
</p>
<pre class="wp-code-highlight prettyprint">
//需要按需加载的内部文件列表映射
mis.classFiles = {
  'AjaxEvent': 'includes/ajax.lib.js',
  'AjaxRequest': 'includes/request.lib.js',
  'colorFade': 'includes/effects.lib.js'
}

//标记已经include的内部文件
mis.includedFiles = {};

//对内的文件加载
mis.include = function(classname,callback){
  if(mis.includedFiles[classname]){
    callback &amp;amp;&amp;amp; callback();
	  return true;
  }else if(mis.classFiles[classname]){
	  return mis.loadJavaScript(mis.classFiles[classname],callback);
  }else{
	  return false;
  }
}

//标记已经load的内部和外部文件
mis.loadedJavaScript = {}

//无限制的加载file文件
mis.loadJavaScript = function(file,callback){
  callback = callback || function(){};
  if(mis.loadedJavaScript[file]){
	  callback(true);
	  return true;
  }else{
	  var head = document.getElementsByTagName(&amp;quot;head&amp;quot;)[0];
	  var script = head.appendChild(document.createElement(&amp;quot;script&amp;quot;));

    script.onload = script.onreadystatechange = function(){
		  if((!/*@cc_on!@*/0) || (/loaded|complete/).test(script.readyState)){
        script.onreadystatechange = null;
	      mis.loadedJavaScript[file] = true;
	      callback(true);
		  }
	  }

	  script.src = file;
	  return true;
  }
}
</pre>
<p>
代码上没啥技巧，只是让它看起来更直观了点而已。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1545/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>优化if~else几种应用场合的代码编写方式，提高代码可读性</title>
		<link>http://www.ilovejs.net/archives/1528</link>
		<comments>http://www.ilovejs.net/archives/1528#comments</comments>
		<pubDate>Sat, 23 Apr 2011 07:14:34 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[代码风格]]></category>
		<category><![CDATA[可读性]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1528</guid>
		<description><![CDATA[条件表达式通常有两种表现形式，第一种：所有分支都是属于正常行为；第二种：条件表达式提供的答案只有一种是正常行为。其他都是不常见的情况。如果两条分支都是正常行为，就应该使用if~else的条件表达式；如果某个条件极其罕见，就应该单独检查该条件，并在该条件为真时立刻从函数中返回。 function getPayAmount(){ var result; if(isDead) result = deadAmount(); else{ if(isSeparated) result = separatedAmount(); else{ if(isRetired) result = retiredAmount(); else &#8230; <a href="http://www.ilovejs.net/archives/1528" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<ol>
<li>
<p>条件表达式通常有两种表现形式，第一种：所有分支都是属于正常行为；第二种：条件表达式提供的答案只有一种是正常行为。其他都是不常见的情况。如果两条分支都是正常行为，就应该使用if~else的条件表达式；如果某个条件极其罕见，就应该单独检查该条件，并在该条件为真时立刻从函数中返回。</p>
<pre class="wp-code-highlight prettyprint">
function getPayAmount(){
  var result;
  if(isDead) result = deadAmount();
  else{
    if(isSeparated) result = separatedAmount();
	else{
	  if(isRetired) result = retiredAmount();
	  else result = normalPayAmount();
	}
  }
  return result;
}
</pre>
<p>可以转化为：</p>
<pre class="wp-code-highlight prettyprint">
function getPayAmount(){
  if(isDead) return deadAmount();
  if(isSeparated) return separatedAmount();
  if(isRedired) return retiredAmount();
  return normalAmount();
}
</pre>
</li>
<li>
<p>在条件表达式的每个分支上有着相同的一段执行代码，这段代码跟分支的逻辑无关的时候，将这段重复代码搬移到条件表达式之外。</p>
<pre class="wp-code-highlight prettyprint">
if(isSpecialDeal()){
  total = price * 0.95;
  send();
}else{
  total = price * 0.98;
  send();
}
</pre>
<p>可以转化为：</p>
<pre class="wp-code-highlight prettyprint">
if(isSpecialDeal()){
  total = price * 0.95;
}else{
  total = price * 0.98;
}
send();
</pre>
</li>
<li>
<p>如果分支条件过于复杂，那么可以将分支条件提炼出来作为一个独立函数，并提供一个语义化更好的名称用于分支判断中。使用它的优势是使得在分支中的代码可读性更好，以至于我不需要知道具体的分支判断条件，就可以理解代码的意图。</p>
<pre class="wp-code-highlight prettyprint">
if(date.before(SUMMER_START) || date.after(SUMMER_END)){
  charge = quantity * _winterRate * _winterServiceCharge;
}else{
  charge = quantity * _summerRate;
}
</pre>
<p>可以转化为：</p>
<pre class="wp-code-highlight prettyprint">
if(notSummer(date)){
  charge = winterCharge(quantity);
}else{
  charge = summerCharge(quantity);
}

function notSummer(date){
  return date.before(SUMMER_START) || date.after(SUMMER_END);
}
function summerCharge(quantity){
  return quantity * _summerRate;
}
function winterCharge(quantity){
  return quantity * _winterRate * _winterServiceCharge;
}
</pre>
</li>
<li>
<p>合并条件表达式。如果有一系列的条件判断，都得到相同的结果；或者嵌套的条件判断。那么将这些条件合并为一个条件表达式，可能的话将这个合并的表达式提炼为一个独立的函数。</p>
<pre class="wp-code-highlight prettyprint">
function disabilityAmount(){
  if(_seniority &amp;lt; 2) return 0;
  if(_monthsDisabled) return 0;
  if(_isPartTime) return 0;
  return 1;
}
</pre>
<p>可以转化为：</p>
<pre class="wp-code-highlight prettyprint">
function disabilityAmount(){
  if(_seniority &amp;lt; 2 || _monthsDisabled || _isPartTime) return 0;
  return 1;
}
</pre>
<p>还可以转化为：</p>
<pre class="wp-code-highlight prettyprint">
function disabilityAmount(){
  if(isNotEligibleForDisability()) return 0;
  return 1;
}

function isNotEligibleForDisability(){
  return _seniority &amp;lt; 2 || _monthsDisabled || _isPartTime;
}
</pre>
</li>
<li>
<p>将条件逻辑反转。有时候使用条件反转的方式，可以很大程度上简化if判断逻辑，特别是在嵌套if判断的时候。</p>
<pre class="wp-code-highlight prettyprint">
function getAdjustedCapital(){
  var result = 0;
  if(_capital &amp;gt; 0){
    if(_intRate &amp;gt; 0 &amp;amp;&amp;amp; _duration &amp;gt; 0){
      result = (_income / _duration) * ADJ_FACTOR;
	}
  }
  return result;
}
</pre>
<p>可以转化为：</p>
<pre class="wp-code-highlight prettyprint">
function getAdjustedCapital(){
  if(_capital &amp;lt;= 0) return 0;
  if(_intRate &amp;lt;= 0 || _duration &amp;lt;=0) return 0;
  return (_income / _duration) * ADJ_FACTOR;
}
</pre>
<p>再简化为：</p>
<pre class="wp-code-highlight prettyprint">
function getAdjustedCapital(){
  if(_capital &amp;lt;= 0 || _intRate &amp;lt;= 0 || _duration &amp;lt;=0) return 0;
  return (_income / _duration) * ADJ_FACTOR;
}
</pre>
</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1528/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>检测link元素加载完成的方式</title>
		<link>http://www.ilovejs.net/archives/1505</link>
		<comments>http://www.ilovejs.net/archives/1505#comments</comments>
		<pubDate>Sun, 20 Mar 2011 06:35:59 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[style]]></category>
		<category><![CDATA[异步加载]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1505</guid>
		<description><![CDATA[检测外联js是否加载完毕，这个相对来说比较简单，只需要处理onload和onreadystatechange在非IE和IE下做兼容，但是需要检测外联的CSS文件是否加载完毕，这个就有点恶心了，大致分成了三类：IE和Opera；Chrome和Safari、FF，这时候FF没有跟着大部队走了，这或许也是FF中的一个bug。 最理想的方式，无非就是统一使用onload来检测link元素是否加载完毕。但是事不与程序猿人愿~ 但是兼容办法还是有的。 在IE、Opera下，可以直接使用onload、onreadystatechange这两种方式都可以检测link元素是否加载完成，跟检测script一样的原理。 在Chrome、Safari等基于Webkit内核的浏览器下，估计就要监控document.styleSheets.length的变化了。Webkit内核的浏览器在处理document.styleSheets.length的方式是这样的，当加载完了一个link之后，length就会加1，那么这样的话，就可以使用setInterval的方式来检测length的变化了，对于同时检测多个link是否加载完成的方式也可以利用这个，看length增加了多少。《测试用例》示例如下： [javascript] var link = document.createElement(&#34;link&#34;); var cn = document.styleSheets.length; var ti = setInterval(function() { if &#8230; <a href="http://www.ilovejs.net/archives/1505" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
检测外联js是否加载完毕，这个相对来说比较简单，只需要处理onload和onreadystatechange在非IE和IE下做兼容，但是需要检测外联的CSS文件是否加载完毕，这个就有点恶心了，大致分成了三类：IE和Opera；Chrome和Safari、FF，这时候FF没有跟着大部队走了，这或许也是FF中的一个bug。
</p>
<p>
最理想的方式，无非就是统一使用onload来检测link元素是否加载完毕。但是事不与程序猿人愿~ 但是兼容办法还是有的。
</p>
<p>
在IE、Opera下，可以直接使用onload、onreadystatechange这两种方式都可以检测link元素是否加载完成，跟检测script一样的原理。
</p>
<p>
在Chrome、Safari等基于Webkit内核的浏览器下，估计就要监控document.styleSheets.length的变化了。Webkit内核的浏览器在处理document.styleSheets.length的方式是这样的，当加载完了一个link之后，length就会加1，那么这样的话，就可以使用setInterval的方式来检测length的变化了，对于同时检测多个link是否加载完成的方式也可以利用这个，看length增加了多少。《<a href="http://www.ilovejs.net/lab/css/loadCSS-Webkit.html">测试用例</a>》示例如下：
</p>
<p>[javascript]<br />
var link = document.createElement(&quot;link&quot;);<br />
var cn = document.styleSheets.length;</p>
<p>var ti = setInterval(function() {<br />
  if (document.styleSheets.length &gt; cn) {<br />
    alert(&quot;CSS loaded&quot;);<br />
    clearInterval(ti);<br />
  }<br />
}, 10);</p>
<p>link.href=&quot;http://www.ilovejs.net/lab/css.php&quot;;<br />
link.rel = &quot;stylesheet&quot;;<br />
document.getElementsByTagName(&quot;head&quot;)[0].appendChild(link);<br />
[/javascript]</p>
<p>
但是在Firefox下，情况就有些恶心了，所使用到的方式跟上面的两类浏览器的处理方式都不太相同。对于document.styleSheets.length的处理也不同于Webkit，它的处理方式是只要link元素一附加到document之后，length就会立即加1，而不管css文件是否加载完毕（测试用例如上面的链接）。为此，对于Firefox的处理方式，使用style标签，而不是link，并且使用传统的@import的方式，通过判断style.sheet.cssRules是否存在来检测css文件是否加载完成，具体如下所示《<a href="http://www.ilovejs.net/lab/css/loadCSS-FF.html">测试用例</a>》：
</p>
<p>[javascript]<br />
var head = document.getElementsByTagName(&quot;head&quot;)[0];</p>
<p>var style = document.createElement(&#8216;style&#8217;);<br />
//加载css.php文件，需要2秒之后才会返回响应内容<br />
style.textContent = &#8216;@import &quot;http://www.ilovejs.net/lab/css/css.php&quot;&#8217;;<br />
style.rel=&quot;stylesheet&quot;;</p>
<p>var fi = setInterval(function() {<br />
  try {<br />
    style.sheet.cssRules; // 这句是关键，在css加载完成的时候，style元素就会有这么个对象。</p>
<p>	alert(&quot;CSS loaded&quot;);</p>
<p>    clearInterval(fi);</p>
<p>  } catch (e){}</p>
<p>}, 10);  </p>
<p>head.appendChild(style);<br />
[/javascript]</p>
<p>
为此，想要写一个兼容性的检测CSS文件是否加载完成的代码，估计看起来会比较丑陋，差异大，处理的方式各异，期待onload统一的那一天咯~~</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1505/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>[翻译] 十条js代码优化原则</title>
		<link>http://www.ilovejs.net/archives/1336</link>
		<comments>http://www.ilovejs.net/archives/1336#comments</comments>
		<pubDate>Wed, 08 Dec 2010 14:29:30 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[性能优化]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1336</guid>
		<description><![CDATA[网上看到的一篇文章，说的是js脚本优化的十条细则，看了下文章，优化的知识都很普通，搞前端的人都知道，罗列一下，增强记忆吧： 定义局部变量。对于当前函数作用域内，如果需要使用这个作用域外部的一些变量，那么就尽量使用局部变量储存外部的变量吧，特别是对于嵌套多级的作用域查询，这个耗时也是比较严重的。还有就是获取DOM节点、NodeList、HTMLCollection等等，可以将NodeList、HTMLCollection转化为数组的形式进行操作，减少DOM即时更新所造成的性能消耗。 不要使用with语句。with语句会在当前作用域下面增加作用域链，造成当前作用域下面变量的遍历性能消耗更大。 对于闭包的使用，节省点，不要太过多了。闭包就是提供一个所谓的“封闭式”的作用域，只允许向包含它向别人访问，而不允许别人访问它。但是声明一个闭包的代价比声明普通的函数的代价是要更高的，况且还有IE下内存泄漏的危险。 获取字面量对象的属性和数组的项比获取变量更慢。如果你要获取一些数据的时候，使用变量比用数组、字面量对象的索引来访问来的更快。在循环中经常会需要访问数据，使用变量存储一下，来的更快。 在数组中不要嵌套的过深。js中没有二维数组的概念，但是可以自己编写一个二维数组，并且可以无限的嵌套下去，json很经常就是这么干的。但是嵌套的越深，访问数组中的项就更难了，级数和性能消耗成正比的。 少用for-in循环。众所周知，for-in用于遍历对象的属性和方法，它所要消耗比for、while、do-while更多的性能。在for-in循环中，对于每一个循环，javasript需要创建一个函数来处理每一个循环，这就带来这么两个性能问题：函数创建、销毁的过程；这个函数在创建之后，又会储存它直接上级的作用域的活动对象。 对于循环，合并控制循环的语句，以及控制变量变化方式。在一个控制循环的语句中，比如循环结束条件、索引的递增等等，如果可以优化这些操作，那么对于整个循环的性能是有帮助的。比如对于结束循环条件：for(var i =0;i]]></description>
			<content:encoded><![CDATA[<p>
网上看到的一篇文章，说的是js脚本优化的十条细则，看了下文章，优化的知识都很普通，搞前端的人都知道，罗列一下，增强记忆吧：
</p>
<ol>
<li>定义局部变量。对于当前函数作用域内，如果需要使用这个作用域外部的一些变量，那么就尽量使用局部变量储存外部的变量吧，特别是对于嵌套多级的作用域查询，这个耗时也是比较严重的。还有就是获取DOM节点、NodeList、HTMLCollection等等，可以将NodeList、HTMLCollection转化为数组的形式进行操作，减少DOM即时更新所造成的性能消耗。</li>
<li>不要使用with语句。with语句会在当前作用域下面增加作用域链，造成当前作用域下面变量的遍历性能消耗更大。</li>
<li>对于闭包的使用，节省点，不要太过多了。闭包就是提供一个所谓的“封闭式”的作用域，只允许向包含它向别人访问，而不允许别人访问它。但是声明一个闭包的代价比声明普通的函数的代价是要更高的，况且还有IE下内存泄漏的危险。</li>
<li>获取字面量对象的属性和数组的项比获取变量更慢。如果你要获取一些数据的时候，使用变量比用数组、字面量对象的索引来访问来的更快。在循环中经常会需要访问数据，使用变量存储一下，来的更快。</li>
<li>在数组中不要嵌套的过深。js中没有二维数组的概念，但是可以自己编写一个二维数组，并且可以无限的嵌套下去，json很经常就是这么干的。但是嵌套的越深，访问数组中的项就更难了，级数和性能消耗成正比的。</li>
<li>少用for-in循环。众所周知，for-in用于遍历对象的属性和方法，它所要消耗比for、while、do-while更多的性能。在for-in循环中，对于每一个循环，javasript需要创建一个函数来处理每一个循环，这就带来这么两个性能问题：函数创建、销毁的过程；这个函数在创建之后，又会储存它直接上级的作用域的活动对象。</li>
<li>对于循环，合并控制循环的语句，以及控制变量变化方式。在一个控制循环的语句中，比如循环结束条件、索引的递增等等，如果可以优化这些操作，那么对于整个循环的性能是有帮助的。比如对于结束循环条件：for(var i =0;i<10;i++)，每次循环的时候，都要执行：#1 i是否存在；#2 i是否 < 10；#3 i++。优化一下，使用while或者do-while：var i = 9;do { ...} while(i--)，那么这样之后，每一个循环需要执行的操作：#1 i--；#2 i是否为true。这样就对循环条件的执行步骤进行了简化。</li>
<li>对于HTMLCollection，尽量定义一个数组来储存它。这样可以避免DOM即时更新所造成的影响。</li>
<li>在操作DOM节点的时候，尽量让它飘了吧。让DOM元素脱离document之后再对它进行操作，最后再重新插回document中，最小化reflow（改变了DOM元素布局性的相关的属性之后就会触发，比如：height、width等）、repaint（改变了DOM元素显示上的变化就会触发，比如：background、color等）所造成的影响。</li>
<li>改变DOM节点样式的时候，尽量改变DOM元素的class而不是style属性。原因你懂的……</li>
</ol>
<p>
规则是死的，不能泛用；规则又是活的，看你是否活学活用，用到思维里去，在你编写代码的时候就可以随手写出符合这些规则的代码。
</p>
<p>英文原文：<a  href="http://jonraasch.com/blog/10-javascript-performance-boosting-tips-from-nicholas-zakas">http://jonraasch.com/blog/10-javascript-performance-boosting-tips-from-nicholas-zakas</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1336/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>说点javascript的加载、解析、执行对浏览器渲染的影响</title>
		<link>http://www.ilovejs.net/archives/1322</link>
		<comments>http://www.ilovejs.net/archives/1322#comments</comments>
		<pubDate>Thu, 18 Nov 2010 16:08:49 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[性能优化]]></category>
		<category><![CDATA[动态加载]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1322</guid>
		<description><![CDATA[javascript的加载方式，总得来说是在页面上使用script来声明，以及动态的加载这些方式，而动态的加载，在很多js库中都能够很好的去处理，从而不至于阻塞其他资源的加载，并与其并行加载下来。这样的动态异步的加载方式罗列起来有：Ajax的方式、DOM Element Insert、Iframe、document.write、defer等等。这些都能够很好的处理js在加载的时候不会阻塞资源加载的问题，但是，js的执行仍然会阻塞浏览器的渲染。或许这是不得不需要付出的代价，有没有一些方式去缓解js在执行的时候对浏览器的渲染所造成的延迟的影响呢？ 首先，让我们从UI Thread、UI Queue、UI Upate的角度去分析整个页面和javascript的行为。浏览器在加载HTML到最后呈现出来的这段过程，整个就是一个UI Thread进程，这个UI Thread里是一个浏览器的响应队列，而UI Queue则是浏览器的行为队列，包括UI Update，javascript的执行行为。那么在页面加载的过程中，UI Queue里面就储存了UI Update、js加载、js解析、js执行等。不管是UI Thread，还是UI Queue，都是按照顺序来的。页面在刚开始未遇到js的加载和执行的时候，是UI Update的一个过程，一旦遇到js，就会等待js的加载、解析、执行完毕之后，接着又开始UI Update，如此这样的一个相应顺序。 那么当js的加载是异步了之后呢，这个时候，js的加载和解析不会在UI Queue的执行队列里，而是等到js加载、解析完毕，一到执行的时候，就添加到UI Queue队列中，从而阻塞了UI &#8230; <a href="http://www.ilovejs.net/archives/1322" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
javascript的加载方式，总得来说是在页面上使用script来声明，以及动态的加载这些方式，而动态的加载，在很多js库中都能够很好的去处理，从而不至于阻塞其他资源的加载，并与其并行加载下来。这样的动态异步的加载方式罗列起来有：Ajax的方式、DOM Element Insert、Iframe、document.write、defer等等。这些都能够很好的处理js在加载的时候不会阻塞资源加载的问题，但是，js的执行仍然会阻塞浏览器的渲染。或许这是不得不需要付出的代价，有没有一些方式去缓解js在执行的时候对浏览器的渲染所造成的延迟的影响呢？
</p>
<p>
首先，让我们从UI Thread、UI Queue、UI Upate的角度去分析整个页面和javascript的行为。浏览器在加载HTML到最后呈现出来的这段过程，整个就是一个UI Thread进程，这个UI Thread里是一个浏览器的响应队列，而UI Queue则是浏览器的行为队列，包括UI Update，javascript的执行行为。那么在页面加载的过程中，UI Queue里面就储存了UI Update、js加载、js解析、js执行等。不管是UI Thread，还是UI Queue，都是按照顺序来的。页面在刚开始未遇到js的加载和执行的时候，是UI Update的一个过程，一旦遇到js，就会等待js的加载、解析、执行完毕之后，接着又开始UI Update，如此这样的一个相应顺序。
</p>
<p><span id="more-1322"></span></p>
<p>
那么当js的加载是异步了之后呢，这个时候，js的加载和解析不会在UI Queue的执行队列里，而是等到js加载、解析完毕，一到执行的时候，就添加到UI Queue队列中，从而阻塞了UI Queue中后面的行为（UI Update）的执行。这就是开头所说的在js的执行期总会阻塞页面的渲染，也就是UI Update。但是这个动态加载的方式跟普通在页面中使用script标签来加载的时候的优势是：将js的加载、解析的行为独立出来，不影响浏览器的UI Update，知道执行期才阻塞。这就很多的程度上加快了页面的渲染和展现。
</p>
<p>
再来说说defer和async属性，defer属性最开始是为IE所实现的，现代的浏览器也都逐渐实现了，那么它的工作原理是什么呢。它的作用跟上面动态加载的优势很相同，js的加载和解析是独立的，但是有一点不同的是：使用了defer属性之后，js代码会等到DOM加载完成的时候才执行，这个时候就又更大限度的让浏览器尽快的UI Update部分完成，让js的执行对浏览器的渲染所造成的影响更小化。那么async呢，是跟上面所说的动态加载js的优势是一样的，也是独立js的加载、解析，解析完成的时候就立即添加到UI Queue队列中去等待执行，阻塞后面的UI Update行为。
</p>
<p>
那么怎样将js的执行对UI Update的影响更小呢？使用HTML5的Worker机制吧，将复杂的js执行交给Worker去执行，Worker是一个独立的js执行环境，这个环境里没有window、DOM的概念，只是用来处理复杂的运算，再将处理后的结果通过postMessage方法发送会浏览器，Worker和页面之间通过postMessage方法来实现跟浏览器的数据交换。这样，将复杂运算交给Worker之后，在页面中所执行的js代码，将会是大大的减小，减小到只需要处理一个onmessage事件，将页面的js执行时间最小化。
</p>
<p>
杯具的还是defer、async、Worker还不能够完全的被目前市面上流行的浏览器所兼容，期待浏览器统一的那一天。
</p>
<p>
&#8212;- EOF &#8212;-</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1322/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>说说将Javascript和CSS合并为一个文件</title>
		<link>http://www.ilovejs.net/archives/1309</link>
		<comments>http://www.ilovejs.net/archives/1309#comments</comments>
		<pubDate>Thu, 04 Nov 2010 04:04:10 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[性能优化]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[合并]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1309</guid>
		<description><![CDATA[今天逛网的时候，看到一种技巧是将js代码和css代码混合在一起，利用CSS parser和Js parser的解析原理，来区分两种不同的代码。这个技巧估计老早就有人知道并讨论的乱套了，我又凹凸了一回。（合并javascript和css作为一个文件，Combine CSS with JS and make it into a single download!，Squeeze CSS and JS into one file） 起初看到这个标题觉得很惊奇，细看了上面罗列的文章之后，发现也只是利用了解析器的原理（解析器本来就是这么设计的，或许不是bug吧），对&#60;!- &#8230; <a href="http://www.ilovejs.net/archives/1309" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
今天逛网的时候，看到一种技巧是将js代码和css代码混合在一起，利用CSS parser和Js parser的解析原理，来区分两种不同的代码。这个技巧估计老早就有人知道并讨论的乱套了，我又凹凸了一回。（<a  href="http://hi.baidu.com/xzkcz/blog/item/61fb8313858a1cd8f7039eaa.html">合并javascript和css作为一个文件</a>，<a  href="http://blogs.msdn.com/b/shivap/archive/2007/05/01/combine-css-with-js-and-make-it-into-a-single-download.aspx?PageIndex=1#comments">Combine CSS with JS and make it into a single download!</a>，<a  href="http://ajaxian.com/archives/squeeze-css-and-js-into-one-file">Squeeze CSS and JS into one file</a>）
</p>
<p>
起初看到这个标题觉得很惊奇，细看了上面罗列的文章之后，发现也只是利用了解析器的原理（解析器本来就是这么设计的，或许不是bug吧），对&lt;!- &#8211; 的处理的不同，来实现将js和css代码混合在一起的方法。从PLT(page load time)来讲，确实将两个HTTP请求减少到一个了，从某种程度上可以减少PLT，但是它所带来的负面的影响和风险也还是比较大的，比如：
</p>
<ol>
<li>增加了代码的复杂度，难以阅读。</li>
<li>增加了代码量。特别是需要在处理CSS代码的时候，每一行都需要添加&lt;!- -，这个无形中增加了文件的代码量。</li>
<li>无法进行代码压缩。</li>
<li>在IE下会出现出错的风险。经过测试发现：如果在body中存在&lt;!- &#8211; - -&gt;，或者在body和head标签之间存在这个HTML注释，在IE下就会出错。<a  href="/lab/js-css-ie.html">试试看</a></li>
</ol>
<p>
所以并不太推荐使用，也不太看好。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1309/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>一个carousel-slide模块的设计思路</title>
		<link>http://www.ilovejs.net/archives/1267</link>
		<comments>http://www.ilovejs.net/archives/1267#comments</comments>
		<pubDate>Wed, 13 Oct 2010 07:45:24 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[代码设计]]></category>
		<category><![CDATA[carousel-slide]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[模块]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1267</guid>
		<description><![CDATA[前段时间，整理出了属于自己的一个动画核心库，虽然渐变动画核心是复制Tweener的代码，但是在实现上，根据自己实际情况以及项目中所使用到的特效，编写了符合自己习惯的接口和参数调用方式，整理这个的主要目的是为了方便自己以后在想要开发一些特效以及提高用户体验相关的项目的时候能够用上，同时也是对自己编码的一点点锻炼吧。Tweener.js 现在觉得嘛，只要这个动画核心建立起来了，其他的fadein、fadeout、opacity、border、font-size等等的变化都可以随心所欲了，只需要找到一个平衡点：使用多长的动画时间才能够在IE、非IE下都能够有一个比较良好的体验。因为IE下处理动画的能力始终是那么的弱，这点很让人烦恼。这些就不多说了，来说一下之前自己写的一个tab slide模块的设计思路和使用到的技巧。 设计思路： 让CSS、HTML、JS分离，尽量是它们处理分内的事情。 使用函数节流方式。 使用HTML元素的id来定位元素，使用class来给元素设置样式。避免使用元素的id和class混合的方式来添加样式，如果有自定义样式，可以使用多个class，而不是使用元素的id。 自动记录前一次mouseover移动过的Trigger元素。 事件逻辑和应用逻辑相分离。 把一切可变的、或者可以自定义的变量通过参数设置为可以自定义的。 从上面的几点设计出发，逐步完善整个模块的编码： 让CSS、HTML、JS都负责各自分内的事情。CSS负责样式，并且是通过在指定命名空间下的className来给每一个carousel-slide添加样式，如果需要自定义样式，可以使用多一个className，并在HTML中进行声明。HTML则负责基本的结构，比如：容器div、内容ul标签、Trigger的ul标签等等，同时，为了解决在Trigger下除了使用数字导航外，还要兼容使用图片等等之外的内容，就给每一个Trigger下的li添加了一个自定义属性data-trigger来记录索引，这样就不依赖于li的内容，而是依赖于属性的设置。JS方面则出要是为了处理事件逻辑和应用处理逻辑，而不过多的去处理结构和样式的问题。 使用函数节流的技巧主要是为了解决事件太频繁触发导致浏览器过度繁忙并造成运行缓慢、奔溃的问题。这类事件主要有resize、mousemove、mouseover、mouseout等等，如果无节制的去处理每一次事件出发，对于动画来说，或许还会造成很大的性能消耗和无意义的行为。为此，使用函数节流，给这类事件添加一个定时器，在时间触发之后，在指定的时间内才开始处理，如果在这段时间内又出发了另外一个事件，就清除掉之前定时器，并设置一个新的定时器来处理事件逻辑，原理就这么简单。 自动记录前一次触发事件的Trigger的元素，这样在接下来的事件出发的元素中，就可以首先取消掉上一个元素的样式、事件等逻辑，从而避免了使用循环来把全部同级的li元素进行遍历进行各个方面的清除工作。 事件逻辑和应用逻辑相分离，这个是从方便后期维护的角度去设计的。事件逻辑主要是处理跟事件相关的逻辑，但是对于在该事件出发之后，会执行更新、删除、插入、修改等等操作则需要独立出来，不至于导致处理事件程序过度复杂，方便后期的维护。 把把一切可变的、或者可以自定义的变量通过参数设置为可以自定义的。这点很重要，可以使得模块可以应对需求多样性的变化，而不至于在需求变化的时候对模块进行过大的修改，比如国际化、标题文字、样式等等。同时也是为了给使用者更多自定义功能的方便。这点由于时间关系，在本示例中就没有明显的体现了。 明确了这些之后，编码就有章可循了： CSS样式： [html] .div{ &#8230; <a href="http://www.ilovejs.net/archives/1267" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
前段时间，整理出了属于自己的一个动画核心库，虽然渐变动画核心是复制Tweener的代码，但是在实现上，根据自己实际情况以及项目中所使用到的特效，编写了符合自己习惯的接口和参数调用方式，整理这个的主要目的是为了方便自己以后在想要开发一些特效以及提高用户体验相关的项目的时候能够用上，同时也是对自己编码的一点点锻炼吧。<a  href="http://www.ilovejs.net/lab/tween/tweener.js">Tweener.js</a>
</p>
<p>
现在觉得嘛，只要这个动画核心建立起来了，其他的fadein、fadeout、opacity、border、font-size等等的变化都可以随心所欲了，只需要找到一个平衡点：使用多长的动画时间才能够在IE、非IE下都能够有一个比较良好的体验。因为IE下处理动画的能力始终是那么的弱，这点很让人烦恼。这些就不多说了，来说一下之前自己写的一个tab slide模块的设计思路和使用到的技巧。
</p>
<p>
设计思路：
</p>
<ol>
<li>让CSS、HTML、JS分离，尽量是它们处理分内的事情。</li>
<li>使用函数节流方式。</li>
<li>使用HTML元素的id来定位元素，使用class来给元素设置样式。避免使用元素的id和class混合的方式来添加样式，如果有自定义样式，可以使用多个class，而不是使用元素的id。</li>
<li>自动记录前一次mouseover移动过的Trigger元素。</li>
<li>事件逻辑和应用逻辑相分离。</li>
<li>把一切可变的、或者可以自定义的变量通过参数设置为可以自定义的。</li>
</ol>
<p><span id="more-1267"></span></p>
<p>
从上面的几点设计出发，逐步完善整个模块的编码：
</p>
<ol>
<li>让CSS、HTML、JS都负责各自分内的事情。CSS负责样式，并且是通过在指定命名空间下的className来给每一个carousel-slide添加样式，如果需要自定义样式，可以使用多一个className，并在HTML中进行声明。HTML则负责基本的结构，比如：容器div、内容ul标签、Trigger的ul标签等等，同时，为了解决在Trigger下除了使用数字导航外，还要兼容使用图片等等之外的内容，就给每一个Trigger下的li添加了一个自定义属性data-trigger来记录索引，这样就不依赖于li的内容，而是依赖于属性的设置。JS方面则出要是为了处理事件逻辑和应用处理逻辑，而不过多的去处理结构和样式的问题。</li>
<li>使用函数节流的技巧主要是为了解决事件太频繁触发导致浏览器过度繁忙并造成运行缓慢、奔溃的问题。这类事件主要有resize、mousemove、mouseover、mouseout等等，如果无节制的去处理每一次事件出发，对于动画来说，或许还会造成很大的性能消耗和无意义的行为。为此，使用函数节流，给这类事件添加一个定时器，在时间触发之后，在指定的时间内才开始处理，如果在这段时间内又出发了另外一个事件，就清除掉之前定时器，并设置一个新的定时器来处理事件逻辑，原理就这么简单。</li>
<li>自动记录前一次触发事件的Trigger的元素，这样在接下来的事件出发的元素中，就可以首先取消掉上一个元素的样式、事件等逻辑，从而避免了使用循环来把全部同级的li元素进行遍历进行各个方面的清除工作。</li>
<li>事件逻辑和应用逻辑相分离，这个是从方便后期维护的角度去设计的。事件逻辑主要是处理跟事件相关的逻辑，但是对于在该事件出发之后，会执行更新、删除、插入、修改等等操作则需要独立出来，不至于导致处理事件程序过度复杂，方便后期的维护。</li>
<li>把把一切可变的、或者可以自定义的变量通过参数设置为可以自定义的。这点很重要，可以使得模块可以应对需求多样性的变化，而不至于在需求变化的时候对模块进行过大的修改，比如国际化、标题文字、样式等等。同时也是为了给使用者更多自定义功能的方便。这点由于时间关系，在本示例中就没有明显的体现了。</li>
</ol>
<p>
明确了这些之后，编码就有章可循了：
</p>
<p>CSS样式：<br />
[html]<br />
.div{<br />
  border:1px solid #ccc;<br />
  width:600px;<br />
  height:150px;<br />
  overflow:hidden;<br />
  padding:4px;<br />
  position:relative;<br />
}<br />
.container{<br />
  width:600px;<br />
  padding:0;<br />
  margin:0;<br />
   list-style:none;<br />
}<br />
.container li{<br />
  height:150px;<br />
  padding:0;<br />
}<br />
.trigger{<br />
  position:absolute;<br />
  top:103px;<br />
  left:440px;<br />
  list-style:none;<br />
}<br />
.trigger li{<br />
  float:left;<br />
  padding:2px 6px;<br />
  background-color:#FCF2CF;<br />
  border:1px solid #F27602;<br />
  margin-right:8px;<br />
  cursor:pointer;<br />
}<br />
.trigger .cur{<br />
  background-color:#FFB442;<br />
  border:1px solid #F27602;<br />
  font-weight:bold;<br />
}<br />
.div2{<br />
  height:100px;<br />
}<br />
.container2 li{<br />
  height:100px;<br />
}<br />
.trigger2{<br />
  top:63px;<br />
}<br />
[/html]<br />
HTML结构：<br />
[html]<br />
&lt;div class=&quot;div&quot;&gt;<br />
&lt;ul id=&quot;container&quot; class=&quot;container&quot;&gt;<br />
  &lt;li&gt;&#8230;&lt;/li&gt;<br />
  &lt;li&gt;&#8230;&lt;/li&gt;<br />
  &lt;li&gt;&#8230;&lt;/li&gt;<br />
  &lt;li&gt;&#8230;&lt;/li&gt;<br />
&lt;/ul&gt;<br />
&lt;ul id=&quot;trigger&quot; class=&quot;trigger&quot;&gt;<br />
  &lt;li class=&quot;cur&quot; data-trigger=&quot;0&quot;&gt;1&lt;/li&gt;<br />
  &lt;li data-trigger=&quot;1&quot;&gt;2&lt;/li&gt;<br />
  &lt;li data-trigger=&quot;2&quot;&gt;3&lt;/li&gt;<br />
  &lt;li data-trigger=&quot;3&quot;&gt;4&lt;/li&gt;<br />
&lt;/ul&gt;<br />
&lt;/div&gt;<br />
[/html]<br />
Javascript逻辑：<br />
[javascript]<br />
;(function(g){<br />
  //获取HTML5中使用data-xxx自定义属性的值<br />
  var getUserData=function(el,attr){<br />
    return (el.dataset &amp;&amp; el.dataset[attr]) || el.getAttribute(attr);<br />
  }</p>
<p>  //获取DOM元素最终的样式<br />
  var getFinalStyle = function(el,attr){<br />
    return el.currentStyle ? el.currentStyle[attr] : window.getComputedStyle(el, null)[attr] || el.style[attr];<br />
  }</p>
<p>  //document.getElementById的简写方式<br />
  var $ = function(o){<br />
    return typeof o === &quot;string&quot; ? document.getElementById(o) : o;<br />
  }</p>
<p>  //处理trigger导航的应用逻辑<br />
  var addTweenForContainer = function(oContainer,oTrigger,target){<br />
    var triggerNum = 0;</p>
<p>	/*获取储存上一次鼠标移动到trigger导航的某个元素*/<br />
	var lastTrigger = oContainer.lastTrigger || oTrigger.getElementsByTagName(&quot;li&quot;)[0];</p>
<p>	/*如果是储存的元素跟当前的元素相同，则直接退出*/<br />
	if(lastTrigger == target){<br />
	  return;<br />
	}</p>
<p>	/*样式的切换*/<br />
	lastTrigger &amp;&amp; (lastTrigger.className=&quot;&quot;);<br />
	target.className=&quot;cur&quot;;</p>
<p>	/*储存上一次鼠标移动到trigger导航的某个元素*/<br />
	oContainer.lastTrigger = target;</p>
<p>	/*获取trigger中自定义属性的值*/<br />
	triggerNum = parseInt(getUserData(target,&quot;data-trigger&quot;),10);</p>
<p>	/*记录当前的trigger索引，用于下面开启自动slide的起始项*/<br />
	oContainer.trigger_index = triggerNum;</p>
<p>	/*添加动画*/<br />
	Tweener.addTweener(oContainer,{<br />
	  time:0.5,<br />
	  to:{marginTop:-oContainer.height*triggerNum}<br />
	});<br />
  }</p>
<p>  /*设置自动slide*/<br />
  var autoStartSlide = function(oContainer,oTrigger,fAutoStart){<br />
    if(!fAutoStart){<br />
	  return;<br />
	}<br />
    var trigger_index = oContainer.trigger_index || 0,<br />
		triggers = oTrigger.getElementsByTagName(&quot;li&quot;),<br />
	    len = triggers.length;</p>
<p>	oContainer.autoTimeoutId = setTimeout(function(){</p>
<p>	  trigger_index = ++trigger_index % len;</p>
<p>	  addTweenForContainer(oContainer,oTrigger,triggers[trigger_index]);<br />
	  oContainer.autoTimeoutId = setTimeout(arguments.callee,2000);<br />
    },2000);<br />
  }</p>
<p>  /*声明slideContainer对象*/<br />
  g.slideContainer = g.slideContainer || {<br />
    init:function(containerId,triggerId,fAuto){<br />
	  var oContainer = $(containerId),<br />
	      oTrigger = $(triggerId);<br />
      /*获取container父元素的高度，用于addTweenForContainer函数中动画的移动距离*/<br />
	  oContainer.height = parseInt(getFinalStyle(oContainer.parentNode,&quot;height&quot;)); </p>
<p>	  //给Trigger添加mouseover事件<br />
	  oTrigger.onmouseover=function(e){</p>
<p>	    //函数节流的技巧，方式事件触发太频繁<br />
	    oContainer.autoTimeoutId &amp;&amp; clearTimeout(oContainer.autoTimeoutId);</p>
<p>		e = e || window.event;<br />
		var target = e.target || e.srcElement;<br />
		if((/li$/i).test(target.nodeName)){<br />
		  oContainer.timeoutId = setTimeout(function(){<br />
		    addTweenForContainer(oContainer,oTrigger,target);<br />
		  },300);<br />
		}<br />
	  }</p>
<p>	  //给Trigger添加mouseout事件<br />
	  oTrigger.onmouseout=function(e){<br />
	    clearTimeout(oContainer.timeoutId || 0);<br />
		/*开启自动slide*/<br />
		autoStartSlide(oContainer,oTrigger,fAuto);<br />
	  }</p>
<p>	  /*通过fAuto参数决定是否开启自动slide*/<br />
	  autoStartSlide(oContainer,oTrigger,fAuto);<br />
	}<br />
  }<br />
})(this);<br />
slideContainer.init(&quot;container&quot;,&quot;trigger&quot;,true);<br />
slideContainer.init(&quot;container2&quot;,&quot;trigger2&quot;,true);<br />
[/javascript]<br />
<a  href="http://www.ilovejs.net/lab/tween/tweener_tab_modify.html">[具体实例页面]</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1267/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>所谓的javascript高级技巧</title>
		<link>http://www.ilovejs.net/archives/1232</link>
		<comments>http://www.ilovejs.net/archives/1232#comments</comments>
		<pubDate>Fri, 01 Oct 2010 16:00:29 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[性能优化]]></category>
		<category><![CDATA[高级技巧]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1232</guid>
		<description><![CDATA[Js学的也差不多了，该是来总结一下Js中一些比较高级的智慧结晶了。基于Js的动态性、对象都是易变的、函数是第一对象等等其他语言所不包含的特性，可以在使用Js的时候创造出更高效、组织性更好的代码。下面提到的一些概念，是不是很熟悉： 分支、惰性实例化、惰性载入函数、单例的两种模式、享元类、函数绑定（纠正函数一个执行上下文）、函数curry化、高级定时器、保护上下文的构造函数、函数节流、自定义事件…… js中的继承、原型、构造函数这些都是老生常谈的了。但是对于构造函数式继承和原型式继承的优缺点，还是有必要了解一下的。原型式继承的主要优点就是共享方法和属性，使得从原型对象中继承出来的子对象都可以在内存中共享全部的方法和属性，这如果是在大型的继承链中将会大大的改善性能和减少内存的使用量。 接下来看看上面所罗列的每一个所谓的“高级”技巧的具体细节咧： 惰性实例化 惰性实例化所要解决的问题是这样的：避免了在页面中js初始化执行的时候就实例化了类，如果在页面中没有使用到这个实例化的对象，那么这就造成了一定的内存的浪费和性能的消耗，那么如果将一些类的实例化推迟到需要使用它的时候才开始去实例化，那么这就避免了刚才说的问题，做到了“按需供应”，简单代码示例如下： [javascript] var myNamespace = function(){ var Configure = function(){ var privateName = &#34;someone&#8217;s name&#34;; &#8230; <a href="http://www.ilovejs.net/archives/1232" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
Js学的也差不多了，该是来总结一下Js中一些比较高级的智慧结晶了。基于Js的动态性、对象都是易变的、函数是第一对象等等其他语言所不包含的特性，可以在使用Js的时候创造出更高效、组织性更好的代码。下面提到的一些概念，是不是很熟悉：
</p>
<p>
分支、惰性实例化、惰性载入函数、单例的两种模式、享元类、函数绑定（纠正函数一个执行上下文）、函数curry化、高级定时器、保护上下文的构造函数、函数节流、自定义事件……
</p>
<p>
js中的继承、原型、构造函数这些都是老生常谈的了。但是对于构造函数式继承和原型式继承的优缺点，还是有必要了解一下的。原型式继承的主要优点就是共享方法和属性，使得从原型对象中继承出来的子对象都可以在内存中共享全部的方法和属性，这如果是在大型的继承链中将会大大的改善性能和减少内存的使用量。
</p>
<p><span id="more-1232"></span></p>
<p>
接下来看看上面所罗列的每一个所谓的“高级”技巧的具体细节咧：
</p>
<ol>
<li><b>惰性实例化</b><br />
惰性实例化所要解决的问题是这样的：避免了在页面中js初始化执行的时候就实例化了类，如果在页面中没有使用到这个实例化的对象，那么这就造成了一定的内存的浪费和性能的消耗，那么如果将一些类的实例化推迟到需要使用它的时候才开始去实例化，那么这就避免了刚才说的问题，做到了“按需供应”，简单代码示例如下：<br />
[javascript]<br />
var myNamespace = function(){<br />
   var Configure = function(){<br />
     var privateName = &quot;someone&#8217;s name&quot;;<br />
	 var privateReturnName = function(){<br />
	   return privateName;<br />
	 }<br />
	 var privateSetName = function(name){<br />
	   privateName = name;<br />
	 }<br />
	 //返回单例对象<br />
	 return {<br />
	   setName:function(name){<br />
	     privateSetName(name);<br />
	   },<br />
	   getName:function(){<br />
	     return privateReturnName();<br />
	   }<br />
	 }<br />
   }<br />
   //储存configure的实例<br />
   var instance;</p>
<p>   return {<br />
     getInstance:function(){<br />
	   if(!instance){<br />
	     instance = Configure();<br />
	   }<br />
	   return instance;<br />
	 }<br />
   }<br />
}();<br />
//使用方法上就需要getInstance这个函数作为中间量了：<br />
myNamespace.getInstance().getName();<br />
[/javascript]<br />
上面的就是简单的惰性实例化的示例，但是有一点缺点就是需要使用中间量来调用内部的Configure函数所返回的对象的方法（当然也可以使用变量来储存myNamespace.getInstance()返回的实例对象）。将上面的代码稍微修改一下，就可以只用比较得体的方法来使用内部的方法和属性：<br />
[javascript]<br />
//惰性实例化的变体<br />
var myNamespace2 = function(){<br />
   var Configure = function(){<br />
     var privateName = &quot;someone&#8217;s name&quot;;<br />
	 var privateReturnName = function(){<br />
	   return privateName;<br />
	 }<br />
	 var privateSetName = function(name){<br />
	   privateName = name;<br />
	 }<br />
	 //返回单例对象<br />
	 return {<br />
	   setName:function(name){<br />
	     privateSetName(name);<br />
	   },<br />
	   getName:function(){<br />
	     return privateReturnName();<br />
	   }<br />
	 }<br />
   }<br />
   //储存configure的实例<br />
   var instance;</p>
<p>   return {<br />
     init:function(){<br />
	   //如果不存在实例，就创建单例实例<br />
	   if(!instance){<br />
	     instance = Configure();<br />
	   }<br />
	   //将Configure创建的单例<br />
	   for(var key in instance){<br />
	     if(instance.hasOwnProperty(key)){<br />
		   this[key]=instance[key];<br />
		 }<br />
	   }<br />
	   this.init = null;<br />
	   return this;<br />
	 }<br />
   }<br />
}();<br />
//使用方式：<br />
myNamespace2.init();<br />
myNamespace2.getName();<br />
[/javascript]<br />
上面修改了自执行函数返回的对象的代码，在获取Configure函数返回的对象的时候，将该对象的方法赋给myNamespace2，这样，调用方式就发生了一点改变了。
</li>
<li><b>分支</b><br />
分支技术解决的一个问题是处理浏览器之间兼容性的重复判断的问题。普通解决浏览器之间的兼容性的方式是使用if逻辑来进行特性检测或者能力检测，来实现根据浏览器不同的实现来实现功能上的兼容，但问题是，没执行一次代码，可能都需要进行一次浏览器兼容性方面的检测，这个是没有必要的，能否在代码初始化执行的时候就检测浏览器的兼容性，在之后的代码执行过程中，就无需再进行检测了呢？答案是有的，分支技术就可以解决这个问题（同样，惰性载入函数也可以实现Lazy Definied，这个在后面将会讲到），下面以声明一个XMLHttpRequest实例对象为例子：<br />
[javascript]<br />
//分支<br />
var XHR= function(){<br />
  var standard = {<br />
    createXHR : function(){<br />
	  return new XMLHttpRequest();<br />
	}<br />
  }<br />
  var newActionXObject = {<br />
    createXHR : function(){<br />
	  return new ActionXObject(&quot;Msxml2.XMLHTTP&quot;);<br />
	}<br />
  }<br />
  var oldActionXObject = {<br />
    createXHR : function(){<br />
	  return new ActionXObject(&quot;Microsoft.XMLHTTP&quot;);<br />
	}<br />
  }<br />
  if(standard.createXHR()){<br />
    return standard;<br />
  }else{<br />
    try{<br />
	  newActionXObject.createXHR();<br />
	  return newActionXObject;<br />
	}catch(o){<br />
	  oldActionXObject.createXHR();<br />
	  return oldActionXObject;<br />
	}<br />
  }<br />
}();<br />
[/javascript]</p>
<p>
从上面的例子可以看出，分支的原理就是：声明几个不同名称的对象，但是给这些对象都声明一个名称相同的方法（这个就是关键），并给这些来自于不同的对象但是拥有相同的方法进行浏览器之间各自的实现，接着就开始进行一次浏览器检测，并经过浏览器检测的结果来决定返回哪一个对象，这样不论返回的是哪一个对象，最后名称相同的方法都作为了对外一致的接口。
</p>
<p>这个是在Javascript运行期期间进行动态检测，并将检测的结果返回赋值给其他的对象，并提供相同的接口，这样储存的对象就可以使用名称相同的接口了。其实，惰性载入函数跟分支在原理是非常相近的，只是在代码实现方面有差异而已。
</li>
<li><b>惰性载入函数</b><br />
惰性载入函数就是英文中传说的“Lazy Defined”，它的主要解决的问题也是为了处理兼容性。原理跟分支类似，下面是简单的代码示例：<br />
[javascript]<br />
var addEvent = function(el,type,handle){<br />
  addEvent = el.addEventListener ? function(el,type,handle){<br />
    el.addEventListener(type,handle,false);<br />
  }:function(el,type,handle){<br />
    el.attachEvent(&quot;on&quot;+type,handle);<br />
  };<br />
  //在第一次执行addEvent函数时，修改了addEvent函数之后，必须执行一次。<br />
  addEvent(el,type,handle);<br />
}<br />
[/javascript]<br />
从代码上看，惰性载入函数也是在函数内部改变自身的一种方式，这样之后，当重复执行的时候，就不会再进行兼容性方面的检测了。
</li>
<li><b>单例的两种模式</b><br />
单例模式是家喻户晓的了，也是当前最流行的一种编写方式，注明的模块模式的编写方式也是从这个思想中衍生出来的。单例模式有两种方式：一种是所谓的“门户大开型”，另外一种就是使用闭包来创建私有属性和私有方法的方式。第一种方式跟构造函数的“门户大开型”是一个样的，声明的方法和属性对外都是开放的，可以通过实例来调用。但是使用闭包来实现的单例模式，可以在一个“封闭”的作用域内声明一些不为外部所调用的私有属性和私有方法，而且还有一个很主要的功能，就是私有属性可以作为一个“数据存储器”，在闭包内声明的方法都可以访问这些私有属性，但是外部不可访问。那么重复添加、修改、删除这些私有属性所储存的数据是安全的，不受外部其他程序的影响。
</li>
<li><b>享元类</b><br />
顾名思义，“享”、“元”。就是共享通用的方法和属性，将差异比较大的类中相同功能的方法集中到一个类中声明，这样需要这些方法的类就可以直接从享元类中进行扩展，这样使得这样通用的方法只需要声明一遍就行了。这个从代码的大小、质量来说还是有一定的效益的。
</li>
<li><b>函数绑定</b><br />
函数绑定就是为了纠正函数的执行上下文，特别是函数中带有this关键字的时候，这点尤其显得重要，稍微不小心，使得函数的执行上下文发生了跟预期的不同的改变，导致了代码执行上的错误（有时候也不会出现错误，这样调试起来，会很变态）。对于这个问题，bind函数是再熟悉不过的了，bind函数的功能就是提供一个可选的执行上下文传递给函数，并且在bind函数内部返回一个函数，来纠正在函数调用上出现的执行上下文发生的变化。最容易出现的错误就是回调函数和事件处理程序一起使用了，下面是摘自《Javascript高级程序设计第二版》的一个示例：<br />
[javascript]<br />
var handler = {<br />
  message:&quot;Event handler&quot;,<br />
  handlerClick:function(e){<br />
    alert(this.message);<br />
  }<br />
}<br />
var btn = document.getElementById(&quot;my-btn&quot;);<br />
//这句就造成了回调函数执行上下文的改变了<br />
EventUtil.addHandler(btn,&quot;click&quot;,handler.handlerClick);<br />
[/javascript]<br />
解决的办法之一，就是纠正一下handler.handlerClick执行的上下文环境，改为：<br />
[javascript]<br />
//这样运行的很好<br />
EventUtil.addHandler(btn,&quot;click&quot;,function(e){<br />
  handler.handlerClick(e);<br />
});<br />
[/javascript]<br />
上面就很好的纠正了回调函数的执行上下文了。而且，也可以使用传说中的bind函数来解决：<br />
[javascript]<br />
var bind = function(fn,context){<br />
  return function(){<br />
     return fn.apply(context || this,arguments);<br />
  }<br />
}<br />
EventUtil.addHandler(btn,&quot;click&quot;,bind(handler.handlerClick));// So Good！<br />
[/javascript]
</li>
<li><b>函数curry化</b><br />
函数curry化的主要功能就是提供了强大的动态函数创建的功能。通过调用另一个函数并为它传入要curry的函数和必要的参数。说白点就是利用已有的函数，再创建一个动态的函数，该动态的函数内部还是通过该已有的函数来发生作用，只是传入更多的参数来简化函数的参数方面的调用。具体示例：<br />
[javascript]<br />
//curry function<br />
function curry(fn){<br />
  var args = [].slice.call(arguments,1); //这个就相当于一个存储器了。<br />
  return function(){<br />
    return fn.apply(null,args.concat([].slice.call(arguments,0)));<br />
  }<br />
}<br />
//Usage:<br />
function add(num1,num2){<br />
  return num1+num2;<br />
}<br />
var newAdd = curry(add,5);<br />
alert(newAdd(6));<br />
[/javascript]<br />
在curry函数的内部，私有变量args就相当于一个存储器，来暂时的存储在curry函数调用的时候所传递的参数值，这样跟后面的动态创建的函数调用的时候的参数合并，并执行，就得到了一样的效果了。
</li>
<li><b>高级定时器</b><br />
提到定时器，无非就是利用setTimeout/setInterval了。但问题是定时器并不是相当于新开一个线程来执行js程序，也不会说是在指定的时间间隔内就会一定执行。指定的时间间隔表示何时将定时器的代码添加到浏览器的执行队列，而不是合适实际执行代码。对此，就有这样的一个问题了：如果代码执行时间超过了定时器指定的时间间隔，那么在指定的时间里代码还是加入的执行队列，但是并没有执行，这样就会造成了无意义的代码执行，这也是使用setInterval的弊端。为此，使用setTimeout才能更好的避免这个问题，在代码本身中执行完毕了，再通过setTimeout来重新设定定时器，把代码加入到执行队列。比如：<br />
[javascript]<br />
setTimeout(function(){<br />
  //many code here&#8230;<br />
  setTimeout(arguments.callee,100); //Key<br />
},100);<br />
[/javascript]<br />
当然了，定时器还有很多其他的技巧和实际作用，看需求而定，更详细的解释可以查看《Javascript高级程序设计第二版》（第467页）。
</li>
<li><b>保护上下文的构造函数</b><br />
这个主要是避免构造函数在没有使用new来实例化的时候，内部的this指向错误问题。通常没有使用new的话，this一般执行window去了，因此造成了执行错误，给代码带来了灾难。使用下面的方式就可以避免这个问题：<br />
[javascript]<br />
function myClass(name,size){<br />
  if(this instanceof myClass){  //Key,使用instanceof来检测当前实例是否是myClass的实例化对象<br />
    this.name = name;<br />
    this.size = size;<br />
 }else{<br />
    return new myClass(name,size);<br />
  }<br />
}<br />
[/javascript]</p>
<p>
但是上面通过instanceof的方式，给继承造成了一定的困扰，因为子类并不是myClass的实例对象，所以会出现属性和方法无法被继承的方式。在说解决办法之前，先来了解一下instanceof操作符的原理：它首先会检测对象当前的原型是否指向右边的构造函数，如果找不到，就会往上一级的原型去查找，直到找到为止，并返回true，否则就返回false。
</p>
<p>基于上面的instanceof的原理，在继承的时候，就可以给子类的prototype原型赋于一个父类的实例化对象就行了，这样就可以在子类继承的时候绕过instanceof的检测。
</li>
<li><b>函数节流</b>
<p>
函数节流函数节流解决的问题是一些代码（特别是事件）在无间断的执行，这严重的影响了浏览器的性能，再没有给它设定间断来执行的话，可能造成浏览器反应速度变慢或者直接就崩溃了。比如：resize事件、mousemove、mouseover、mouseout等等事件。
</p>
<p>
这个时候，就可以加入定时器的功能了，将事件进行“节流”，即是：在事件触发的时候，设定一个定时器来执行事件处理程序，这样可以很大的程度上缓解浏览器的负担，又缓冲的余地去更新页面。具体的实例可以查看支付宝中部“导购场景”的导航：<a  href="http://life.alipay.com/?src=life_alipay_index_big">http://life.alipay.com/?src=life_alipay_index_big</a>，以及当当网首页左边的导航栏：<a  href="http://www.dangdang.com/">http://www.dangdang.com/</a>等等，这些都是为了解决mouseover和mouseout移动过快的时候加大浏览器处理的负担，特别是在涉及到有Ajax调用，而且Ajax调用是么有缓存的情况下，给服务器也造成了很大的负担。为此，函数节流就派上用场了。比如简单的示例如下（出自本人写的：<a  href="http://www.ilovejs.net/lab/tween/tweener_tab_modify.html">http://www.ilovejs.net/lab/tween/tweener_tab_modify.html</a>）：<br />
[javascript]<br />
oTrigger.onmouseover=function(e){<br />
  //如果上一个定时器还没有执行，则先清除掉定时器<br />
  oContainer.autoTimeoutId &amp;&amp; clearTimeout(oContainer.autoTimeoutId);<br />
  e = e || window.event;<br />
  var target = e.target || e.srcElement;<br />
  if((/li$/i).test(target.nodeName)){<br />
    oContainer.timeoutId = setTimeout(function(){<br />
      addTweenForContainer(oContainer,oTrigger,target);<br />
    },300);<br />
   }<br />
}<br />
[/javascript]
</p>
</li>
<li><b>自定义事件</b>
<p>
首先要说的是，这里并不是说自定义事件可以真的自定义跟mouseout、click等一样性质的“事件”。这里的自定义事件在执行的时候还是需要依赖已有的键盘、鼠标、HTML等事件来执行，或者又其他函数“触发”执行，这里的“触发”是指直接调用自定义事件中声明的某个接口方法，来轮询的执行全部相关的添加到自定义事件中的函数。
</p>
<p>
自定义事件内部有一个“事件”存储器，根据添加的事件的类型的不同，来储存各类的事件执行函数，这样再出发这类事件的时候，就轮询执行添加到该类型下的函数。“自定义事件背后的概念是创建一个管理事件的对象，让其他对象监听那些事件”来自《Javascript高级程序设计第二版》的解释。基于自定义事件的原理，可以想象自定义事件很多时候是用于“订阅&#8212;发布&#8212;接收”性质的功能。
</p>
</li>
</ol>
<p>
文章写的有点多了，但是上面介绍的Javascript高级技巧还远不止这些，特别是在Ajax方面的一些模式和技巧都还没有介绍，何况是客户端和服务端结合的一些技巧（比如压缩、Minify、服务器“推技术”等等）。更多的有待以后了解了介绍一二。
</p>
<p>
在前端基本技术方面，Javascript、HTML、CSS等大家都是已经掌握的差不多了，但是利用这些已有的基本技术，能否创造出不一般的应用和模式呢？这个才是在掌握了基本的能力之后接下来需要掌握的，比如下面是本人在每天晚上睡觉之前所总结的几点：
</p>
<ol>
<li>学会重构代码的技术，有计划性的重构下自己之前所编写过的一些代码，加强自己掌控代码的能力。</li>
<li>Code review。这里说的review，并不是指个人，而是对团队来说的，一个人编写的代码的想象空间有限，如果在自己编写代码完成之后，邀请其他团队内的伙伴来查看你的代码，及时发现问题以及提出更好的解决方案，这也不失为一种即时重构的方式，提高代码的质量。</li>
<li>编写具体的功能代码之前，首先设计代码、规划代码、组织代码的模式。</li>
<li>在代码的质量、性能、大小之间能作出合理的权衡。</li>
<li>编写阅读性良好、一目了然、扩展性、可维护性良好、重复利用的代码，也是一门艺术。</li>
<li>关注web前端的性能优化，包括Javascript、HTML、CSS、客户端、服务端、前端、后端等整体性的优化。</li>
<li>最后一点或许也是最重要的：善于总结。这点比上面的任何一点都来的重要，因为上面的每一点都是出自这点的积累。</li>
</ol>
<p>上面我总结的几点，也是后期自己要着重提高的能力，当然了，在实际的编码方面，还有很多的东西还需要去挖掘和了解。继续革命吧，将互联网革命进行到底……</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1232/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>读JET有感</title>
		<link>http://www.ilovejs.net/archives/1219</link>
		<comments>http://www.ilovejs.net/archives/1219#comments</comments>
		<pubDate>Mon, 27 Sep 2010 11:50:11 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Javascript Library]]></category>
		<category><![CDATA[Jet]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1219</guid>
		<description><![CDATA[腾讯内部使用的js库也开源了&#8212; JET(Javascript Extension Tools &#8211; Javascript 扩展工具包)，很难得的一件事情，赶紧下了Jet 1.1.1版本的整个源码，包括说明文档来看看源码，看看腾讯强大的前端技术的后面会有一个怎样的js库来支撑的。http://code.google.com/p/j-et/wiki/JET 查看了Jet的使用方式之后，首先不禁冒出了一个词“复制”。是的，Jet复制了YUI3的编写方式，提供了“包”的概念package： [javascript] Jet().$package(function(J){ //code here&#8230; }; [/javascript] 采用的也是颗粒化的方式，将负责不同功能的代码整理到独立的js文件里，比如：DOM、string、Event、http、fx、ui等等，不过Jet方法里并不能像YUI3那样直接导入该包的js文件，查看它的DEMO，需要自由组合几个js文件来实现想要的功能，做到了无缝的插入包，这个就得益于Jet中的微内核&#8212;jet.core.js。 上面是第一个“复制”，在查看jet.base.js这个文件源码的时候，看到了很多熟悉的函数呀：$try、clone、timedChunk、bind、random等等，这些都还是似乎直接复制。这个base文件包含了微内核、dom、browser、event、date、Class（用于继承和扩展的相关方法和属性）。但是，感觉看Jet的源码很爽，读起来很顺畅，整体来看Jet的各个文件的组织是：微内核来提供包以及仿照YUI3的这种操作方式，而其他的dom、event、browser等则是作为工具代码包的概念组织起来的。这就更像是一种函数功能集合，在各个包里对提供的各种接口API，也是过程函数的编写方式，增加、删除、修改都非常的容易，颗粒化的程度较高，这点非常赞~。核心逻辑简单了，代码组合的方式也就简单的多了。 Jet中Class的继承方式还是比较简单的，并且只提供原型的继承，对于父类中的使用this声明的方法和属性则不继承。这点不知道开发人员是怎么考虑的。 还有一个非常赞的地方，是event包中addEventListener、removeEventListener在IE下的处理方式。在IE下使用一个包装函数来对事件event对象做属性扩展，来使得跟W3C的事件的属性接口达成统一。同时通过一个事件储存容器，来储存每一个事件，在window设置了unload的情况下，删除全部已注册的事件。onDomReady原理跟我之前所写的类似，通过定时器来检测document、document.body、document.getElementById、document.getElementsByTagName是否可用来实现。 在代码的编写方式上也有值得借鉴的地方：在包的开头将全部的功能函数用变量声明了，之后实现每一个功能函数，最后把功能函数注册到包的命名空间下面。这样组织代码，看起来比较清晰，对实现代码的颗粒化也是有很大帮助。 &#8230; <a href="http://www.ilovejs.net/archives/1219" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>腾讯内部使用的js库也开源了&#8212; JET(Javascript Extension Tools &#8211; Javascript 扩展工具包)，很难得的一件事情，赶紧下了Jet 1.1.1版本的整个源码，包括说明文档来看看源码，看看腾讯强大的前端技术的后面会有一个怎样的js库来支撑的。<a href="http://code.google.com/p/j-et/wiki/JET">http://code.google.com/p/j-et/wiki/JET</a></p>
<p>查看了Jet的使用方式之后，首先不禁冒出了一个词“复制”。是的，Jet复制了YUI3的编写方式，提供了“包”的概念package：</p>
<p>[javascript]<br />
Jet().$package(function(J){<br />
  //code here&#8230;<br />
};<br />
[/javascript]</p>
<p>采用的也是颗粒化的方式，将负责不同功能的代码整理到独立的js文件里，比如：DOM、string、Event、http、fx、ui等等，不过Jet方法里并不能像YUI3那样直接导入该包的js文件，查看它的DEMO，需要自由组合几个js文件来实现想要的功能，做到了无缝的插入包，这个就得益于Jet中的微内核&#8212;jet.core.js。</p>
<p><span id="more-1219"></span></p>
<p>上面是第一个“复制”，在查看jet.base.js这个文件源码的时候，看到了很多熟悉的函数呀：$try、clone、timedChunk、bind、random等等，这些都还是似乎直接复制。这个base文件包含了微内核、dom、browser、event、date、Class（用于继承和扩展的相关方法和属性）。但是，感觉看Jet的源码很爽，读起来很顺畅，整体来看Jet的各个文件的组织是：微内核来提供包以及仿照YUI3的这种操作方式，而其他的dom、event、browser等则是作为工具代码包的概念组织起来的。这就更像是一种函数功能集合，在各个包里对提供的各种接口API，也是过程函数的编写方式，增加、删除、修改都非常的容易，颗粒化的程度较高，这点非常赞~。核心逻辑简单了，代码组合的方式也就简单的多了。</p>
<p>Jet中Class的继承方式还是比较简单的，并且只提供原型的继承，对于父类中的使用this声明的方法和属性则不继承。这点不知道开发人员是怎么考虑的。</p>
<p>还有一个非常赞的地方，是event包中addEventListener、removeEventListener在IE下的处理方式。在IE下使用一个包装函数来对事件event对象做属性扩展，来使得跟W3C的事件的属性接口达成统一。同时通过一个事件储存容器，来储存每一个事件，在window设置了unload的情况下，删除全部已注册的事件。onDomReady原理跟我之前所写的类似，通过定时器来检测document、document.body、document.getElementById、document.getElementsByTagName是否可用来实现。</p>
<p>在代码的编写方式上也有值得借鉴的地方：在包的开头将全部的功能函数用变量声明了，之后实现每一个功能函数，最后把功能函数注册到包的命名空间下面。这样组织代码，看起来比较清晰，对实现代码的颗粒化也是有很大帮助。</p>
<p>不过在代码的细节上，还是有很多可以优化的地方：包括减少属性查询、执行语句，字符串的处理，以及在一些功能的实现上等等也都可以使用比较优雅的方式来实现的。但整体上来说是：简洁、代码组织有序、在兼容性方面做的也不错……</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1219/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>谈谈一点体会</title>
		<link>http://www.ilovejs.net/archives/1211</link>
		<comments>http://www.ilovejs.net/archives/1211#comments</comments>
		<pubDate>Sat, 25 Sep 2010 12:48:31 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[分离]]></category>
		<category><![CDATA[重构]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1211</guid>
		<description><![CDATA[不知道怎么给这篇文章起个标题，因为也是YY几句而已，就谈谈啦。 翻完了《Javascript高级程序设计第二版》，对其中的最佳实践认同度很高。整体来说，看了这本书，对作用域、原型、构造函数、解耦、分离等等理解都有了另一种体会，原来测试中发现的很多疑问，在书中都能够找到答案，很阔然开朗。来聊聊内容、行为、表现分离吧。 或者也可以说是：结构、数据、行为、表现相分离，因为内容具体的就是指结构和数据，而这点是比较容易误解的：数据和结构也一定程度上需要保持分离。而数据和结构分离的一种应用场合就是模板技术，模板提供结构，后端提供数据，前端或者后端技术提供模板解析行为，CSS控制表现。 行为和结构、数据容易造成混淆的原因之一就是在js中使用了innerHTML包含了一段html字符串。在当前应用中可能实现了很多功能，也很稳定，但是后期的维护以及页面的调试可就会造成问题了，因为是动态生成的一段HTML代码，在源代码中查看不到（但是通过firebug、DOM Inspector等都可以查看到）。在后期的代码反反复复的修改中，可能就存在问题了。而且，使用innerHTML的一个性能问题是：在调用了innerHTML方法后，会启动一个新的HTML parser来解析html字符串。同理，使用eval、setTimeout/setInterval、new Function来执行一个字符串类型的js代码的时候，也会启动一个新的js parser来解析js代码，都会造成一个性能问题。一种解决方案是：在页面中先生成那段innerHTML，在CSS中设置为display:none，当需要显示的时候，就通过js来显示该html片段（但是这样也存在可用性问题，当js被禁用的时候，就无法再查看该内容了）。还有一种情况，就是使用js的createElement、appendChild来生成一大段HTML片段并插入到页面中，这种情况后期的维护更艰难，谁知道哪天要修改这个HTML结构了，那时候就痛苦了，解决方案可以是在服务端来生成这样的一段HTML，通过js动态插入到相应的位置；或者使用Ajax的方式，来将整段HTML片段插入到页面中。 行为和样式混淆的一种原因是在js中使用了style、cssText等属性动态给DOM元素生成行内样式，这存在同样的问题。js应该只负责功能，而CSS负责表现。所以解决方案就可以是通过className或者动态嵌入一个css文件来实现。 在书中的最佳实践中提到的代码维护，也是说的很在理的，不过这些都是通用性的组件、大型应用、将会经常维护更新的项目才会涉及到的。“对于不是自己维护的对象/类，千万不要随意去修改它的任何方法和属性。”确实如此，因为你不知道这个对象或者类，你就不知道它嵌入到了那些对象/类/方法中，稍微的一点修改可能造成其他功能的崩溃。也可能出现的情况是其他人不知道这个对象/类修改了，而是用了原来没修改前的方法/属性。但是原来的对象/类所拥有的方法已经不能满足你的需求，那么就使用适配器吧，切勿修改接口。 上面所说的代码维护的方法，也是从重构的角度去考虑问题的：解决今天的问题之后，能不能也解决下预期内的明天的问题。比如，你要在原来的代码的基础上添加新功能（或者说是新方法），可是发现在当前的代码的模式下，扩展性很不好，突然想到如果修改修改，那么扩展性就好多了，后期的添加其他的功能也可以更容易，那么重构就开始了。一段代码，今天看起来很爽，明天再看起来，可能就很糟糕了。 并不是处处都需要把重构挂在脑边，重构也有它的使用场合以及何时不能使用重构。当添加新特性、修改bug等等的时候，可以考虑下代码是否需要重构，使得后期的维护可以花费更少的成本。当然了，如果添加一个新特性，上头要求要尽快完成，时间不用了，重构要花费一段时间，那么这时候就不需要考虑重构了，实现功能优先级更高，这也从中说明你的上头是“重进度”，而不是“重质量”的类型。 因此，重构有一个三次原则：第一次编写代码实现一个功能的时候，无须考虑重构；第二次做这个功能类似的重复性的工作的时候，会有些恶心，而你也可能不打算去重构，第三次又重复性的对这个功能做修改的时候，那么这时候，就该考虑重构了。 重构更重要的是：给你一种重构的思想，以及进行重构的技巧。别把它当作一个“银弹”，而是要深入到你编写的代码中。 有多少人会回过头来看自己写过的代码呢？]]></description>
			<content:encoded><![CDATA[<p>不知道怎么给这篇文章起个标题，因为也是YY几句而已，就谈谈啦。</p>
<p>翻完了《Javascript高级程序设计第二版》，对其中的最佳实践认同度很高。整体来说，看了这本书，对作用域、原型、构造函数、解耦、分离等等理解都有了另一种体会，原来测试中发现的很多疑问，在书中都能够找到答案，很阔然开朗。来聊聊内容、行为、表现分离吧。</p>
<p>或者也可以说是：结构、数据、行为、表现相分离，因为内容具体的就是指结构和数据，而这点是比较容易误解的：数据和结构也一定程度上需要保持分离。而数据和结构分离的一种应用场合就是模板技术，模板提供结构，后端提供数据，前端或者后端技术提供模板解析行为，CSS控制表现。</p>
<p><span id="more-1211"></span></p>
<p>行为和结构、数据容易造成混淆的原因之一就是在js中使用了innerHTML包含了一段html字符串。在当前应用中可能实现了很多功能，也很稳定，但是后期的维护以及页面的调试可就会造成问题了，因为是动态生成的一段HTML代码，在源代码中查看不到（但是通过firebug、DOM Inspector等都可以查看到）。在后期的代码反反复复的修改中，可能就存在问题了。而且，使用innerHTML的一个性能问题是：在调用了innerHTML方法后，会启动一个新的HTML parser来解析html字符串。同理，使用eval、setTimeout/setInterval、new Function来执行一个字符串类型的js代码的时候，也会启动一个新的js parser来解析js代码，都会造成一个性能问题。一种解决方案是：在页面中先生成那段innerHTML，在CSS中设置为display:none，当需要显示的时候，就通过js来显示该html片段（但是这样也存在可用性问题，当js被禁用的时候，就无法再查看该内容了）。还有一种情况，就是使用js的createElement、appendChild来生成一大段HTML片段并插入到页面中，这种情况后期的维护更艰难，谁知道哪天要修改这个HTML结构了，那时候就痛苦了，解决方案可以是在服务端来生成这样的一段HTML，通过js动态插入到相应的位置；或者使用Ajax的方式，来将整段HTML片段插入到页面中。</p>
<p>行为和样式混淆的一种原因是在js中使用了style、cssText等属性动态给DOM元素生成行内样式，这存在同样的问题。js应该只负责功能，而CSS负责表现。所以解决方案就可以是通过className或者动态嵌入一个css文件来实现。</p>
<p>在书中的最佳实践中提到的代码维护，也是说的很在理的，不过这些都是通用性的组件、大型应用、将会经常维护更新的项目才会涉及到的。“对于不是自己维护的对象/类，千万不要随意去修改它的任何方法和属性。”确实如此，因为你不知道这个对象或者类，你就不知道它嵌入到了那些对象/类/方法中，稍微的一点修改可能造成其他功能的崩溃。也可能出现的情况是其他人不知道这个对象/类修改了，而是用了原来没修改前的方法/属性。但是原来的对象/类所拥有的方法已经不能满足你的需求，那么就使用适配器吧，切勿修改接口。</p>
<p>上面所说的代码维护的方法，也是从重构的角度去考虑问题的：解决今天的问题之后，能不能也解决下预期内的明天的问题。比如，你要在原来的代码的基础上添加新功能（或者说是新方法），可是发现在当前的代码的模式下，扩展性很不好，突然想到如果修改修改，那么扩展性就好多了，后期的添加其他的功能也可以更容易，那么重构就开始了。一段代码，今天看起来很爽，明天再看起来，可能就很糟糕了。</p>
<p>并不是处处都需要把重构挂在脑边，重构也有它的使用场合以及何时不能使用重构。当添加新特性、修改bug等等的时候，可以考虑下代码是否需要重构，使得后期的维护可以花费更少的成本。当然了，如果添加一个新特性，上头要求要尽快完成，时间不用了，重构要花费一段时间，那么这时候就不需要考虑重构了，实现功能优先级更高，这也从中说明你的上头是“重进度”，而不是“重质量”的类型。</p>
<p>因此，重构有一个三次原则：第一次编写代码实现一个功能的时候，无须考虑重构；第二次做这个功能类似的重复性的工作的时候，会有些恶心，而你也可能不打算去重构，第三次又重复性的对这个功能做修改的时候，那么这时候，就该考虑重构了。</p>
<p>重构更重要的是：给你一种重构的思想，以及进行重构的技巧。别把它当作一个“银弹”，而是要深入到你编写的代码中。</p>
<p>有多少人会回过头来看自己写过的代码呢？</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1211/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>客户端存储</title>
		<link>http://www.ilovejs.net/archives/1184</link>
		<comments>http://www.ilovejs.net/archives/1184#comments</comments>
		<pubDate>Fri, 10 Sep 2010 08:20:39 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[localStorage]]></category>
		<category><![CDATA[User Data]]></category>
		<category><![CDATA[客户端存储]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1184</guid>
		<description><![CDATA[搜索了几种客户端存储的方式：Flash SharedObject、Google Gears、Cookie、DOM Storage、User Data、window.name、Silverlight、Open Database等等，都存在或多或少的缺点以至于无法跨浏览器、跨页面、跨目录的方式来储存客户端的数据。因此很多应用在需要这个客户端存储数据功能的时候，就需要权衡这几种方案，看哪一种能更接近于应用的功能，将影响和差异降低到最小。（可以参考：http://ningxiaotao.javaeye.com/blog/683611） 需要安装插件、新版的现代浏览器才支持的方案都存在很大的缺陷，在可用性方面得不到最大的保障，如果能充分利用各大浏览器都普遍支持的方案来实现，这样才能更加符合大部分应用的需求，window.name能在当前页面刷新或者在当前窗口跳转到其他页面的时候仍然存在（试试吧），不过不能跨窗口传值；还有User Data在IE下也支持完好（缺点是：只能在相同目录下的页面之间共享数据）；再加上HTML5提倡的localStorage方案来实现其他支持它的现代浏览器，来做到渐进增强、稳步退化。这是经常会使用的方式，来做到一个比较好的权衡。 但是有一点必须注意：不宜在客户端存储敏感的信息。使用window.name、localStorage、globalStorage等在客户端存储的信息都非常的容易暴露，所以建议在完成数据存储或者设定一个过期时间清除掉来保证用户帐号等的安全。 从上面的所说的出发，使用window.name、User Data在IE6、7上实现存储、IE8+等现代浏览器使用localStorage或者globalStorage来实现，得到了一个比较权衡的兼容，但是缺点仍然存在：IE6、IE7下使用User Data不能跨目录读取存储的数据，这时候就可以使用window.name来实现跨页面的存储数据；localStorage或者globalStorage就可以实现跨页面、跨目录的读取存储的数据，但是都不能跨域。下面是使用示例： [javascript] storeLocalData.setItem(&#34;test1&#34;,&#34;shafeng00453sfsdfsd1&#34;); //storeLocalData.setItem(&#34;test&#34;,&#34;supersha001&#34;); //storeLocalData.removeItem(&#34;test&#34;); alert(storeLocalData.getItem(&#34;test1&#34;)); toreLocalData.setItem(&#34;test2&#34;,&#34;fsd1&#34;); alert(storeLocalData.getItem(&#34;test2&#34;)); //================================ &#8230; <a href="http://www.ilovejs.net/archives/1184" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
搜索了几种客户端存储的方式：Flash SharedObject、Google Gears、Cookie、DOM Storage、User Data、window.name、Silverlight、Open Database等等，都存在或多或少的缺点以至于无法跨浏览器、跨页面、跨目录的方式来储存客户端的数据。因此很多应用在需要这个客户端存储数据功能的时候，就需要权衡这几种方案，看哪一种能更接近于应用的功能，将影响和差异降低到最小。（可以参考：<a  href="http://ningxiaotao.javaeye.com/blog/683611">http://ningxiaotao.javaeye.com/blog/683611</a>）
</p>
<p>
需要安装插件、新版的现代浏览器才支持的方案都存在很大的缺陷，在可用性方面得不到最大的保障，如果能充分利用各大浏览器都普遍支持的方案来实现，这样才能更加符合大部分应用的需求，window.name能在当前页面刷新或者在当前窗口跳转到其他页面的时候仍然存在（<a  href="http://www.ilovejs.net/lab/winname.html">试试吧</a>），不过不能跨窗口传值；还有User Data在IE下也支持完好（缺点是：只能在相同目录下的页面之间共享数据）；再加上HTML5提倡的localStorage方案来实现其他支持它的现代浏览器，来做到渐进增强、稳步退化。这是经常会使用的方式，来做到一个比较好的权衡。
</p>
<p>
<em>但是有一点必须注意：<strong>不宜在客户端存储敏感的信息</strong>。使用window.name、localStorage、globalStorage等在客户端存储的信息都非常的容易暴露，所以建议在完成数据存储或者设定一个过期时间清除掉来保证用户帐号等的安全。</em>
</p>
<p>
从上面的所说的出发，使用window.name、User Data在IE6、7上实现存储、IE8+等现代浏览器使用localStorage或者globalStorage来实现，得到了一个比较权衡的兼容，但是缺点仍然存在：IE6、IE7下使用User Data不能跨目录读取存储的数据，这时候就可以使用window.name来实现跨页面的存储数据；localStorage或者globalStorage就可以实现跨页面、跨目录的读取存储的数据，但是都不能跨域。下面是使用示例：
</p>
<p>[javascript]<br />
storeLocalData.setItem(&quot;test1&quot;,&quot;shafeng00453sfsdfsd1&quot;);<br />
//storeLocalData.setItem(&quot;test&quot;,&quot;supersha001&quot;);<br />
//storeLocalData.removeItem(&quot;test&quot;);<br />
alert(storeLocalData.getItem(&quot;test1&quot;));<br />
toreLocalData.setItem(&quot;test2&quot;,&quot;fsd1&quot;);<br />
alert(storeLocalData.getItem(&quot;test2&quot;));<br />
//================================<br />
//storeLocalData.clear(); //clear all data<br />
//alert(storeLocalData.getItem(&quot;test1&quot;));<br />
//alert(storeLocalData.getItem(&quot;test2&quot;));<br />
//================================<br />
//还可以添加&quot;onchange事件&quot;，来检测指定name的值是否改变，并执行事件函数。<br />
storeLocalData.setItem(&quot;test1&quot;,&quot;shafeng00453sfsdfsd1&quot;,function(k,v){<br />
    alert(&quot;you have change the value&quot;);<br />
});<br />
storeLocalData.setItem(&quot;test1&quot;,&quot;shafeng00453sfsdfsd1&quot;); //这个就会“触发”所谓的onchange事件了<br />
[/javascript]<br />
<span id="more-1184"></span></p>
<p>
来测试看看咯：<a  href="/lab/storage/set.html">开始存储</a>&#8211;><a  href="/lab/storage/get.html">另外的页面来读取</a>&#8211;><a  href="/lab/storage/sub/get.html">跨目录的读取</a>&#8211;><a  href="/lab/storage/get.html">你可以在关闭浏览器之后再浏览这个</a>。
</p>
<p>
源码展示：
</p>
<p>[javascript]<br />
var storeLocalData = function(g){<br />
  var storageEvents={},docElement,w3cStorage,storage,names=[];<br />
  !document.all ? (w3cStorage = true,storage = g.localStorage || g.globalStorage[location.hostname] ) : (docElement = document.documentElement) &amp;&amp; docElement.addBehavior(&#8216;#default#userdata&#8217;);<br />
  return {<br />
    &quot;setItem&quot;:function(key,value,onchange,isow){<br />
	  var evt = null;<br />
	  if(onchange){<br />
	    storageEvents[key]={};<br />
		storageEvents[key][&quot;onchange&quot;]=onchange;<br />
	  }<br />
	  if(this.getItem(key) &amp;&amp; (this.getItem(key) != value)){<br />
	    (evt=storageEvents[key]) &amp;&amp; evt[&quot;onchange&quot;] &amp;&amp; evt[&quot;onchange&quot;](key,value);<br />
	  }<br />
	  if(w3cStorage){<br />
	    var ls = localStorage[key];<br />
		storage[key] = !isow ? value : ls ? ls : value;<br />
	  }else{<br />
	    docElement.setAttribute(&#8216;value&#8217;, value);<br />
		docElement.save(key);<br />
		names.push(key);<br />
	  }<br />
	},<br />
	&quot;getItem&quot;:function(key){<br />
	  return w3cStorage ? storage[key] : (docElement.load(key),docElement.getAttribute(&#8216;value&#8217;));<br />
	},<br />
	&quot;removeItem&quot;:function(key){<br />
	  w3cStorage ? storage.removeItem(key) : (docElement.removeAttribute(&#8216;value&#8217;),docElement.save(key));<br />
	},<br />
	&quot;clear&quot;:function(){<br />
	  if(w3cStorage){<br />
	    storage.clear();<br />
	  }else{<br />
	    for(var i=0,l=names.length;i&lt;l;i++){<br />
		  this.removeItem(names[i]);<br />
		}<br />
	  }<br />
	},<br />
	&quot;setWinName&quot;:function(value){<br />
	  g.name=value;<br />
	},<br />
	&quot;getWinName&quot;:function(){<br />
	  return g.name;<br />
	}<br />
  }<br />
}(this);<br />
[/javascript]</p>
<p>
暂时还没找到更好的方案来解决IE6、IE7下的跨目录的读取存储数据。有待观察……
</p>
<p>
扩展阅读：<a  href="http://diveintohtml5.org/storage.html">http://diveintohtml5.org/storage.html</a>，<a  href="http://blog.tugai.net/2010/01/16/browser-local-stroage/">常用浏览器本地存储的几种方案对比</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1184/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>妙用字面量对象来设计代码</title>
		<link>http://www.ilovejs.net/archives/1177</link>
		<comments>http://www.ilovejs.net/archives/1177#comments</comments>
		<pubDate>Fri, 03 Sep 2010 18:28:04 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[javascript pattern]]></category>
		<category><![CDATA[字面量对象]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1177</guid>
		<description><![CDATA[最近一直在学习一些巧妙的设计代码编写的技巧，比如：单例模式，模块模式，类模式，字面量模式等等。其中单例模式、模块模式的写法又可以根据不同的特点有几种不同的变体。哈哈，有点走题了，本文主要说的不是这些，而是怎样利用字面量对象来设计代码。 当初利用三元运算符来代替多个if的逻辑，使得代码看起来简单，虽然牺牲了一点代码可读性，但是代码看起来没有那么臃肿了。对于if逻辑多的时候，可以使用switch来代替众多的if&#8230;else if逻辑，但是对于每一个分支比较复杂或者是很类似的时候，看到switch&#8230;case一连串，也感觉不爽，那么就是用字面量对象来代替吧，就如我下面所写的那样： [javascript] var checkFn=function(operation){ return { &#8216;=&#8217;:function(e) { return (e.getAttribute(attr) == attrValue); }, &#8216;~&#8217;:function(e) { return (e.getAttribute(attr).match(new RegExp(&#8216;\\b&#8217;+attrValue+&#8217;\\b&#8217;))); &#8230; <a href="http://www.ilovejs.net/archives/1177" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
最近一直在学习一些巧妙的设计代码编写的技巧，比如：单例模式，模块模式，类模式，字面量模式等等。其中单例模式、模块模式的写法又可以根据不同的特点有几种不同的变体。哈哈，有点走题了，本文主要说的不是这些，而是怎样利用字面量对象来设计代码。
</p>
<p>
当初利用三元运算符来代替多个if的逻辑，使得代码看起来简单，虽然牺牲了一点代码可读性，但是代码看起来没有那么臃肿了。对于if逻辑多的时候，可以使用switch来代替众多的if&#8230;else if逻辑，但是对于每一个分支比较复杂或者是很类似的时候，看到switch&#8230;case一连串，也感觉不爽，那么就是用字面量对象来代替吧，就如我下面所写的那样：
</p>
<p>[javascript]<br />
var checkFn=function(operation){<br />
  return {<br />
	&#8216;=&#8217;:function(e) { return (e.getAttribute(attr) == attrValue); },<br />
        &#8216;~&#8217;:function(e) { return (e.getAttribute(attr).match(new RegExp(&#8216;\\b&#8217;+attrValue+&#8217;\\b&#8217;))); },<br />
        &#8216;|&#8217;:function(e) { return (e.getAttribute(attr).match(new RegExp(&#8216;^&#8217;+attrValue+&#8217;-?&#8217;))); },<br />
        &#8216;^&#8217;:function(e) { return (e.getAttribute(attr).indexOf(attrValue) == 0); },<br />
        &#8216;$&#8217;:function(e) { return (e.getAttribute(attr).lastIndexOf(attrValue) == e.getAttribute(attr).length &#8211; attrValue.length); },<br />
        &#8216;*&#8217;:function(e) { return (e.getAttribute(attr).indexOf(attrValue) &gt; -1); },<br />
        &#8216;a&#8217;:function(e) { return e.getAttribute(attr);}<br />
   }[operation];<br />
}<br />
[/javascript]<br />
上面就可以避免使用switch来罗列基于operation的分支了，代码简洁多了。很多时候，利用字面量对象可以很巧妙地去处理if等判断逻辑，使得程序无需判断，就可以直接通过字面量对象得到想要的结果。下面是摘自MoolTools库开头的一段代码，读起来很顺畅，也很巧妙：<br />
[javascript]<br />
//用于给对象添加静态方法<br />
Native.genericize = function(object, property, check){<br />
	if ((!check || !object[property]) &amp;&amp; typeof object.prototype[property] == &#8216;function&#8217;) object[property] = function(){<br />
		var args = Array.prototype.slice.call(arguments);<br />
		return object.prototype[property].apply(args.shift(), args);<br />
	};<br />
};<br />
//用于给对象添加type属性<br />
Native.typize = function(object, family){<br />
	if (!object.type) object.type = function(item){<br />
		return ($type(item) === family);<br />
	};<br />
};<br />
//具体的实现过程<br />
;(function(){<br />
	var natives = {&#8216;Array&#8217;: Array, &#8216;Date&#8217;: Date, &#8216;Function&#8217;: Function, &#8216;Number&#8217;: Number, &#8216;RegExp&#8217;: RegExp, &#8216;String&#8217;: String};<br />
	for (var n in natives) new Native({name: n, initialize: natives[n], protect: true});</p>
<p>	var types = {&#8216;boolean&#8217;: Boolean, &#8216;native&#8217;: Native, &#8216;object&#8217;: Object};<br />
	for (var t in types) Native.typize(types[t], t);</p>
<p>	var generics = {<br />
		&#8216;Array&#8217;: [&quot;concat&quot;, &quot;indexOf&quot;, &quot;join&quot;, &quot;lastIndexOf&quot;, &quot;pop&quot;, &quot;push&quot;, &quot;reverse&quot;, &quot;shift&quot;, &quot;slice&quot;, &quot;sort&quot;, &quot;splice&quot;, &quot;toString&quot;, &quot;unshift&quot;, &quot;valueOf&quot;],<br />
		&#8216;String&#8217;: [&quot;charAt&quot;, &quot;charCodeAt&quot;, &quot;concat&quot;, &quot;indexOf&quot;, &quot;lastIndexOf&quot;, &quot;match&quot;, &quot;replace&quot;, &quot;search&quot;, &quot;slice&quot;, &quot;split&quot;, &quot;substr&quot;, &quot;substring&quot;, &quot;toLowerCase&quot;, &quot;toUpperCase&quot;, &quot;valueOf&quot;]<br />
	};<br />
	for (var g in generics){<br />
		for (var i = generics[g].length; i&#8211;;) Native.genericize(natives[g], generics[g][i], true);<br />
	}<br />
})();<br />
[/javascript]</p>
<p>
别看上面的代码多，也别看它这样做是否合理，其实它已经很好的处理了使用相应的原型的方法来实现静态方法，它的实现方式感觉不错，看起来有种恍然一亮的感觉，思维上可以借鉴的地方很多。
</p>
<p>字面量对象还可以做很多其他的事情，来简化代码的编写，有待你去发觉，^_^。</p>
<p>
扩展阅读：《<a  href="http://blog.mixu.net/2010/01/26/organizing-javascript-code/">Organizing Javascript code</a>》、《<a  href="http://peter.michaux.ca/articles/how-i-write-javascript-widgets">How I write JavaScript Widgets</a>》、《<a  href="http://www.klauskomenda.com/code/javascript-programming-patterns/">http://www.klauskomenda.com/code/javascript-programming-patterns/</a>（需要翻墙）》</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1177/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>javascript coding patterns</title>
		<link>http://www.ilovejs.net/archives/1165</link>
		<comments>http://www.ilovejs.net/archives/1165#comments</comments>
		<pubDate>Wed, 25 Aug 2010 06:49:59 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[javascript pattern]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1165</guid>
		<description><![CDATA[JavaScript code的编写模式多种多样，那么接下来总结一下大概都有哪几种，看看你是否都使用到了这些模式和思维： Separation of concerns 即是我们平时挂在嘴边的行为、样式、结构分离（Content-markup、Presentation-CSS、Behavior-JavaScript），这在代码的扩展性、可维护性、易迁移性方面都可以得到很大的提升 Literals，JSON，namespace Literals指的是codding尽量字面量化，对象字面量、数组字面量、函数字面量、正则字面量等等，这些都比使用new来实例Object、Array、Function性能上更好，甚至也推荐使用变脸的形式来声明函数，避免直接使用function来声明一个函数。 JSON提供一种更简洁、更直观的数据传输，在大小和解析方面都胜于XML。 namespace是尽量将每一个APP封装在一个独立的命名空间下，避免跟其他的APP模块产生耦合，产生错误。“低耦合”是namespace的一个终极目标。 Self-executing functions 顾名思义，就是指自定义函数，它用的比较多的场合是在闭包中，提供给code一个纯净的上下文执行环境，而不会造成全局变量泛滥 Callbacks 回调函数，用过“鸡查询(jQuery)”的人都知道，在执行完一个函数之后，再调用回调函数进行下一步的操作，做到了“流畅的执行流”。 Borrowing methods 别看Borrowing这个单词是“借”的意思，感觉有点高深，其实就是利用了apply和call两个方法来借用其他类或者对象的方法来实现功能，比较多的场合是借用数组的一些方法，比如slice、join等等，比如：[].apply(arguments,[1,3])。这只是普通用的比较多的情况，但是它还可以用在这样的一个场合，类似于“继承”：我首先使用一个“基类”&#8212;即是一个包含通用的方法和属性的对象，之后其他的结构跟它类似的对象就可以通过apply或者call来“借用”这个“基类”的方法，说的可能有些枯燥，上点代码： [javascript] var &#8230; <a href="http://www.ilovejs.net/archives/1165" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>JavaScript code的编写模式多种多样，那么接下来总结一下大概都有哪几种，看看你是否都使用到了这些模式和思维：</p>
<ol>
<li>
<strong><em>Separation of concerns</em></strong><br />
即是我们平时挂在嘴边的行为、样式、结构分离（Content-markup、Presentation-CSS、Behavior-JavaScript），这在代码的扩展性、可维护性、易迁移性方面都可以得到很大的提升
</li>
<li>
<strong><em>Literals，JSON，namespace</em></strong><br />
Literals指的是codding尽量字面量化，对象字面量、数组字面量、函数字面量、正则字面量等等，这些都比使用new来实例Object、Array、Function性能上更好，甚至也推荐使用变脸的形式来声明函数，避免直接使用function来声明一个函数。<br />
JSON提供一种更简洁、更直观的数据传输，在大小和解析方面都胜于XML。<br />
namespace是尽量将每一个APP封装在一个独立的命名空间下，避免跟其他的APP模块产生耦合，产生错误。“低耦合”是namespace的一个终极目标。
</li>
<li>
<em><strong>Self-executing functions</strong></em><br />
顾名思义，就是指自定义函数，它用的比较多的场合是在闭包中，提供给code一个纯净的上下文执行环境，而不会造成全局变量泛滥
</li>
<li>
<em><strong>Callbacks</strong></em><br />
回调函数，用过“鸡查询(jQuery)”的人都知道，在执行完一个函数之后，再调用回调函数进行下一步的操作，做到了“流畅的执行流”。
</li>
<li>
<em><strong>Borrowing methods</strong></em><br />
别看Borrowing这个单词是“借”的意思，感觉有点高深，其实就是利用了apply和call两个方法来借用其他类或者对象的方法来实现功能，比较多的场合是借用数组的一些方法，比如slice、join等等，比如：[].apply(arguments,[1,3])。这只是普通用的比较多的情况，但是它还可以用在这样的一个场合，类似于“继承”：我首先使用一个“基类”&#8212;即是一个包含通用的方法和属性的对象，之后其他的结构跟它类似的对象就可以通过apply或者call来“借用”这个“基类”的方法，说的可能有些枯燥，上点代码：<br />
[javascript]<br />
var Base={<br />
   name:&quot;&quot;,<br />
  &quot;getName&quot;:function(){<br />
      return this.name;<br />
   },<br />
   &quot;setName&quot;:function(name){<br />
       this.name=name;<br />
   }<br />
}<br />
//有了上面这个“骨架”之后，接下来就可以“借用”了<br />
//比如从服务器端获得了这样的一个JSON结构：<br />
var json={<br />
  &quot;test1&quot;:{ &quot;name&quot;:&quot;lilei&quot;,&quot;age&quot;:22},<br />
  &quot;test2&quot;:{ &quot;name&quot;:&quot;Sam&quot;,&quot;age&quot;:30},<br />
  &quot;test3&quot;:{ &quot;name&quot;:&quot;Susa&quot;,&quot;age&quot;:15}<br />
}<br />
//这样我们就可以这样来调用了:<br />
alert(Base.getName.call(json.test1));<br />
///////////////<br />
////////这只是个简单的例子，实用性并不高，提供的是一种设计思路，在某种场合或许就可以利用它<br />
[/javascript]
</li>
<li>
<em><strong>Functions returning function</strong>s</em><br />
在函数中再返回函数，这也是比较普通的了，为特定的场合所使用
</li>
<li>
<em><strong>Functions overwriting themselves</strong></em><br />
函数重写它自己，这点或许很多人都知道怎么回事，但是怎么去利用它，还比较模糊。它的一个非常适用的场合就是处理浏览器兼容性的判断，也就是所谓的“Lazy Definition”。它就是在第一次执行的时候就根据不同的条件进行判断，来重写自身函数，这样在第二次之后的调用中就可以直接调用，而无需再判断兼容性等等，比如：<br />
[javascript]<br />
var addEvent=function(el,type,fn){<br />
  addEvent=el.addEventListener ? function(el,type,fn){<br />
    el.addEventListener(type,fn,false);<br />
  }:function(el,type,fn){<br />
    el.attachEvent(&quot;on&quot;+type,fn);<br />
  };<br />
  return addEvent(el,type,fn);<br />
}<br />
[/javascript]
</li>
<li>
<em><strong>Function properties</strong></em><br />
这个就是给函数添加属性，通常使用这个无非是为了临时储存数据或者在这个函数的命名空间下在执行期间一直储存数据。比如cache的实现等。其实这里的Function可以延伸到DOM节点等任何可以设置属性的对象上。不知道大家有没有看过John Resig写的那两个addEvent和removeEvent方法，就是在DOM中临时储存数据来实现在IE下正确的removeEvent。
</li>
<li>
<em><strong>Configuration object</strong></em><br />
看过或者使用过YUI的，都知道它其中的对象、类、方法中都充斥着config参数，这里说的Configuration object多多少少就是这种应用，不过一种比较好的说法是“在参数列表中，如果参数数目多，那么将必须的参数独立起来，其他的可选参数都放到一个字面量对象里，即是Config参数”，这是有一定合理性的，一来代码看起来比较直观，明确区分了必须的参数和可选的参数，同时使得可选的参数无需按照顺序罗列出来。
</li>
<li>
<em><strong>Constructor return values</strong></em><br />
在构造函数中返回值。这里就有一点误区了：如果返回的值是对象，那么new实例化的时候，实例对象就是该返回的对象，如果是普通的数值（字符串、数字、布尔值等），就忽略该返回的值，按照正常的方式实例化。
</li>
<li>
<em><strong>Forgeting new</strong></em><br />
把new给“忘记”了吧。这里的“忘记”并不是说不去使用new，或者忽略它的存在，它在很多场合下还是得用（比如继承、一些带变量的正则对象等），这里的Forgeting的意思也是从继承等的角度去说的，尽量避免去使用new来实例化对象，道格拉斯曾经提出一种“伪函数化”的继承方式，例如：<br />
[javascript]<br />
var Base = function(name){<br />
  var that = {};<br />
  that.name=name;<br />
  return that;<br />
}<br />
var subClass=function(name,age){<br />
  var that = Base(name);<br />
  that.age=age;<br />
  return that;<br />
}<br />
//例如上面的例子，“继承”的方式就是利用了一个字面量作为载体，进行添加、删除、修改属性和方法等等，这样就可以给不同的子类扩展不同的方法和属性。<br />
[/javascript]
</li>
<li>
<em><strong>Chaining</strong></em><br />
链式调用，“鸡查询”库可谓是开创了先河，它的简易性和便利性使得它的用户群猛彪，使得Prototype、ExtJs、YUI等不得不也借鉴它的方法调用的方式。
</li>
<li>
<em><strong>Inheritance</strong></em><br />
继承。对，这里说的就是继承，面向对象思想中的其中之一，其实在一般的程序中，很少用到继承的方式来实现功能，但是如果从代码的扩展性、维护性等方面考究，以及从库、框架的角度来架构的时候，可能就需要继承这个技巧来实现整个代码的编写了。
</li>
<li>
<em><strong>Mixins</strong></em><br />
这个词不好理解，YUI中的augment函数或许有些人看过它的源码，基本的应用场合是扩展对象，例如：<br />
[javascript]<br />
/* Augment function, improved. */<br />
function augment(receivingClass, givingClass) {<br />
   if(arguments[2]) { // Only give certain methods.<br />
      for(var i = 2, len = arguments.length; i &lt; len; i++) {<br />
         receivingClass.prototype[arguments[i]] = givingClass.prototype[arguments[i]];<br />
      }<br />
   }<br />
   else { // Give all methods.<br />
      for(methodName in givingClass.prototype) {<br />
         if(!receivingClass.prototype[methodName]) {<br />
            receivingClass.prototype[methodName] = givingClass.prototype[methodName];<br />
         }<br />
      }<br />
   }<br />
}<br />
[/javascript]<br />
之前我也写过一片博文《<a href="http://www.ilovejs.net/archives/114">享元类ShareClass</a>》，原理跟这个差不多。
</li>
<li>
<em><strong>Private variables</strong></em><br />
私有变量。“保持全局环境变量的干净”，这个被说的很多了。JavaScript可以模拟出私有成员、特权函数（即是静态方法），而实现这个仅仅需要一个闭包函数作为上下文执行环境，来于闭包外部的执行环境区分开来。静态方法仅仅需要给该对象或者构造函数添加方法，这样就使得该方法具有独享性。
</li>
<li>
<em><strong>Dynamic script tags</strong></em><br />
动态添加script标签。这个主要是用于异步动态加载外部的js文件，使得js的加载和执行不会阻塞后续资源的加载。这里罗列了七种加载js的方式：<a href="http://www.ilovejs.net/lab/loadjs/">http://www.ilovejs.net/lab/loadjs/</a>。不过有一点值得说明的是：浏览器解析过的script标签，浏览器不会重新去解析，即使你通过text属性修改了script标签内的代码，或者修改了script标签的src属性，浏览器也不会去重新解析它。
</li>
<li>
<em><strong>Modules</strong></em><br />
模块，也叫做组件。模块化开发已经广泛为前端界的人所知晓了，它并不是一个很新的东西，而是一种代码设计的思维，从代码的可维护性、独立性、松散耦合方面来设计代码。这个就跟面向对象的思想一样，都是一种设计方式，来适用于不同的场合。
</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1165/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>更加DIY的selector查询DOM</title>
		<link>http://www.ilovejs.net/archives/1160</link>
		<comments>http://www.ilovejs.net/archives/1160#comments</comments>
		<pubDate>Wed, 11 Aug 2010 09:27:14 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[DOM查询]]></category>
		<category><![CDATA[query]]></category>
		<category><![CDATA[querySelectorAll]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1160</guid>
		<description><![CDATA[在上一篇文章中（谈谈松散耦合、颗粒度）提到的将javascript库或者框架更加向开发人员开放，DIY功能，尽量保持核心代码的精简和稳定，只开放接口，让开发人员根据特定的需求去DIY功能，而不是内定一整套方法集，供开发人员去使用。对此我例举了我写的query2.js为例子，这里就特别拿它出来说说。 query2中查询方式也是从左到右，这个是比较普通也容易实现的方式，有人说从右到左进行查询的话，效率会比较高，查询的复杂度较低。我想这就要开具体的selector了，如果是这样的“.test p”，那么从右到左的话复杂度就更高一些了，可能还得递归到document.body节点查询父元素的className是否等于test。所以双方面都有利有弊。 但是从左到右的查询方式还有一个比较苦恼的问题，就是“去重”（这是昨天跟瓶子吃饭的时候他提及到的问题），比如： [html] &#60;div&#62; &#60;div&#62; &#60;p&#62;Hello world&#60;/p&#62; &#60;/div&#62; &#60;/div&#62; [/html] 这时候如果使用“div p”来查询p标签元素的时候，如果不去重，就会导致使用getElementsByTagName查询到两个p元素，如果是在查询结果后给p标签添加事件，那么问题就大了。所以再进行查询的时候，必须得去重。 query2加入的去重的功能，同时还支持querySelectorAll（注意：对于不符合CSS指定的selector，querySelectorAll会报错），它最大的功能，就是可以DIY属于自己的selector，可以根据自己的需求来指定selector，具体示例可以查看谈谈松散耦合、颗粒度中给出的代码例子。源码展示如下： [javascript] ;(function(g){ var D = &#8230; <a href="http://www.ilovejs.net/archives/1160" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
在上一篇文章中（<a  href="http://www.ilovejs.net/archives/1129">谈谈松散耦合、颗粒度</a>）提到的将javascript库或者框架更加向开发人员开放，DIY功能，尽量保持核心代码的精简和稳定，只开放接口，让开发人员根据特定的需求去DIY功能，而不是内定一整套方法集，供开发人员去使用。对此我例举了我写的query2.js为例子，这里就特别拿它出来说说。
</p>
<p>
query2中查询方式也是从左到右，这个是比较普通也容易实现的方式，有人说从右到左进行查询的话，效率会比较高，查询的复杂度较低。我想这就要开具体的selector了，如果是这样的“.test p”，那么从右到左的话复杂度就更高一些了，可能还得递归到document.body节点查询父元素的className是否等于test。所以双方面都有利有弊。
</p>
<p>
但是从左到右的查询方式还有一个比较苦恼的问题，就是“去重”（这是昨天跟瓶子吃饭的时候他提及到的问题），比如：
</p>
<p>[html]<br />
&lt;div&gt;<br />
  &lt;div&gt;<br />
    &lt;p&gt;Hello world&lt;/p&gt;<br />
  &lt;/div&gt;<br />
&lt;/div&gt;<br />
[/html]</p>
<p>
这时候如果使用“div p”来查询p标签元素的时候，如果不去重，就会导致使用getElementsByTagName查询到两个p元素，如果是在查询结果后给p标签添加事件，那么问题就大了。所以再进行查询的时候，必须得去重。
</p>
<p>
query2加入的去重的功能，同时还支持querySelectorAll（注意：对于不符合CSS指定的selector，querySelectorAll会报错），它最大的功能，就是可以DIY属于自己的selector，可以根据自己的需求来指定selector，具体示例可以查看<a  href="http://www.ilovejs.net/archives/1129">谈谈松散耦合、颗粒度</a>中给出的代码例子。源码展示如下：
</p>
<p><span id="more-1160"></span><br />
[javascript]<br />
;(function(g){<br />
	var D = document,fqueryAll=true;<br />
	var _tag = function(tag,p){<br />
		 return p.getElementsByTagName(tag || &quot;*&quot;);<br />
	}<br />
	var contain=function(a,b){<br />
		 return a.contains ? a!=b &amp;&amp; a.contains(b) : (a.compareDocumentPosition(b)==20);<br />
	};<br />
  var _queryMethod = {<br />
		&quot;#&quot;:function(q,p){<br />
       var bits = q.split(&quot;#&quot;),<br />
	         tagName = bits[0],<br />
	         id = bits[1],<br />
	         element = document.getElementById(id);<br />
       return tagName &amp;&amp; element.tagName.toLowerCase() != tagName ? [] : [element];<br />
    },<br />
		&quot;.&quot;:function(q,p){<br />
			var bits = q.split(&quot;.&quot;),<br />
				  tagName = bits[0],<br />
				  cn=bits[1],<br />
				  elems = null,<br />
				  returnEl = [],<br />
				  index = 0,<br />
				  reg = new RegExp(&quot;\\b&quot;+cn+&quot;\\b&quot;);<br />
		  for(var i=0,l = p.length;i&lt;l;i++){<br />
				elems = _tag(tagName,p[i]);<br />
				var tmp = null;<br />
				for(var j =0,m = elems.length;j&lt;m;j++){<br />
					if(!/\S/.test((tmp = elems[j]).nodeValue)) continue;<br />
					if(reg.test(tmp.className)){<br />
						returnEl[index++] = tmp;<br />
					}<br />
				}<br />
			}<br />
			return returnEl;<br />
		},<br />
		&quot;_tag_&quot;:function(q,p){<br />
			var found,returnEl = [],index=0;<br />
			for(var i=0,l=p.length;i&lt;l;i++){<br />
				found = _tag(q,p[i]);<br />
				for(var j =0,m=found.length;j&lt;m;j++){<br />
					returnEl[index++] = found[j];<br />
				}<br />
			}<br />
			return returnEl;<br />
		},<br />
    &quot;]&quot;:function(q,p){<br />
			q.match(/^(.*)\[(\w+)([=~\|\^\$\*]?)=?&quot;?([^\]&quot;]*)&quot;?\]$/);<br />
			var returnEl = [],<br />
				  index=fIndex=0,<br />
				  op=RegExp.$3,<br />
				  tag=RegExp.$1,<br />
				  attr=RegExp.$2,<br />
				  attrvalue=RegExp.$4,<br />
			    found = query(tag,p);</p>
<p>			var checkFn = {<br />
				&#8216;=&#8217;:function(e) { return (e.getAttribute(attr) == attrValue); },<br />
		    &#8216;~&#8217;:function(e) { return (e.getAttribute(attr).match(new RegExp(&#8216;\\b&#8217;+attrValue+&#8217;\\b&#8217;))); },<br />
		    &#8216;|&#8217;:function(e) { return (e.getAttribute(attr).match(new RegExp(&#8216;^&#8217;+attrValue+&#8217;-?&#8217;))); },<br />
		    &#8216;^&#8217;:function(e) { return (e.getAttribute(attr).indexOf(attrValue) == 0); },<br />
		    &#8216;$&#8217;:function(e) { return (e.getAttribute(attr).lastIndexOf(attrValue) == e.getAttribute(attr).length &#8211; attrValue.length); },<br />
		    &#8216;*&#8217;:function(e) { return (e.getAttribute(attr).indexOf(attrValue) &gt; -1); }<br />
			}[op] || function(e) { return e.getAttribute(attr);};</p>
<p>			for(var i=0,l=found.length;i&lt;l;i++){<br />
				if(checkFn(found[i])){<br />
					returnEl[fIndex++] = found[i];<br />
				}<br />
			}<br />
			return returnEl;<br />
		}<br />
  }<br />
	//去重<br />
	var pureMutil = function(els){<br />
		var returnEl=[],index=0,tmp=els[0];<br />
		for(var i=1,l=els.length;i&lt;l;i++){<br />
			if(!contain(tmp,els[i])){<br />
				returnEl[index++]=tmp;<br />
				if(i==l-1) {returnEl[index++]=els[l-1];break;}<br />
			}else if(i==l-1){<br />
				returnEl[index++]=els[i];<br />
				break;<br />
			}<br />
			tmp=els[i];<br />
		}<br />
		return returnEl;<br />
	}</p>
<p>	g.query = function(q,p){<br />
		var elems = p || [D],reg=new RegExp(g.query.config.reg),tmp;<br />
		if(fqueryAll &amp;&amp; D.querySelectorAll){<br />
			try{<br />
				return D.querySelectorAll(q);<br />
			}catch(e){fqueryAll=false;}<br />
		}<br />
		var tokens = q.split(&#8216; &#8216;),token,m;<br />
		for(var i=0,l=tokens.length;i&lt;l;i++){<br />
			token = tokens[i];<br />
			m=token.match(reg);<br />
			tmp = _queryMethod[(m&amp;&amp;m[0]) || &quot;_tag_&quot;](token,elems);<br />
			if(l==1) {elems=tmp;break;}<br />
			elems = (i&lt;l-1)? pureMutil(tmp) :tmp;<br />
		}<br />
		return elems;<br />
	}<br />
	g.query.config={<br />
		reg:&quot;(\\])|(\\.)|(#)&quot;,<br />
		addSelector:function(mark,fn){<br />
			if(!mark || !fn){return;}<br />
			_queryMethod[mark]=fn;<br />
			mark = mark.replace(/(\.|\||\[|\]|\^|\\|\$|\?|\*|\+|\{|\}|\(|\))/g,&quot;\\\\$1&quot;);<br />
			this.reg += this.reg.indexOf(mark)!=-1? &quot;&quot; : &quot;|(&quot;+mark+&quot;)&quot;;<br />
		},<br />
		queryMethod:_queryMethod<br />
	}<br />
})(this);<br />
[/javascript]</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1160/feed</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>网站再优化</title>
		<link>http://www.ilovejs.net/archives/1156</link>
		<comments>http://www.ilovejs.net/archives/1156#comments</comments>
		<pubDate>Tue, 10 Aug 2010 16:44:56 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[性能优化]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[浏览器]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1156</guid>
		<description><![CDATA[今天闲来无事，就用Firebug查看首页的HTTP瀑布图，测试页面加载时间，发现在外联的css和js上时间开销还是挺大的，虽然css和js都进行了gzip压缩，但是解析延迟在某些时候还是比较厉害，不是css解析延迟就是js解析延迟，在读取缓存的时候，也有一定的读取的时间开销。 鉴于这种情况，那么干脆就将首页的css和js都嵌入到页面中吧，把css放到head、js放到body闭合标签之前，反正这两个文件在gzip压缩的条件下也总共才三四K而已，而子页面里还是使用外联css和js的方式。 经过这样倒弄，首页加载速度平均有100ms的提升，欣喜若狂。更好笑的是yslow、page speed测试都得了满分，哈哈…… 让首页嵌入css和js，而子页面外联的方式，主要是出于这样的一个目的：用户第一次浏览到首页的时候，页面可以尽快的呈现，而到了子页面，就加载css和js，这样的用户体验就有了一个类似于“稳步退化”的感觉，使得用户不会在起先的时候就有个不良感觉，而之后的访问，子页面就可以充分的利用缓存，因为子页面可能包含图片、flash等等，缓解HTTP的并发数。 还有，之前在浏览器下可能会有短暂的无样式与渲染样式之前切换的闪白，目前也得到了比较好的缓解。]]></description>
			<content:encoded><![CDATA[<p>
今天闲来无事，就用Firebug查看首页的HTTP瀑布图，测试页面加载时间，发现在外联的css和js上时间开销还是挺大的，虽然css和js都进行了gzip压缩，但是解析延迟在某些时候还是比较厉害，不是css解析延迟就是js解析延迟，在读取缓存的时候，也有一定的读取的时间开销。
</p>
<p>
鉴于这种情况，那么干脆就将首页的css和js都嵌入到页面中吧，把css放到head、js放到body闭合标签之前，反正这两个文件在gzip压缩的条件下也总共才三四K而已，而子页面里还是使用外联css和js的方式。
</p>
<p>
经过这样倒弄，首页加载速度平均有100ms的提升，欣喜若狂。更好笑的是yslow、page speed测试都得了满分，哈哈……
</p>
<p>
让首页嵌入css和js，而子页面外联的方式，主要是出于这样的一个目的：用户第一次浏览到首页的时候，页面可以尽快的呈现，而到了子页面，就加载css和js，这样的用户体验就有了一个类似于“稳步退化”的感觉，使得用户不会在起先的时候就有个不良感觉，而之后的访问，子页面就可以充分的利用缓存，因为子页面可能包含图片、flash等等，缓解HTTP的并发数。
</p>
<p>
还有，之前在浏览器下可能会有短暂的无样式与渲染样式之前切换的闪白，目前也得到了比较好的缓解。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1156/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>谈谈松散耦合、颗粒度</title>
		<link>http://www.ilovejs.net/archives/1129</link>
		<comments>http://www.ilovejs.net/archives/1129#comments</comments>
		<pubDate>Mon, 09 Aug 2010 18:07:06 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[性能优化]]></category>
		<category><![CDATA[query]]></category>
		<category><![CDATA[松散耦合]]></category>
		<category><![CDATA[颗粒度]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1129</guid>
		<description><![CDATA[“松散耦合”、“颗粒度”是相对于javascript库或者javascript框架来说的，它涉及的概念和包含的知识是很多的，而其中之一，就是说javascript库或者框架从整理来看是容易拆分，也容易自定义的组合，来实现特定需求的功能。之前有很多说法说YUI的编写方法才更接近于javascript的本质，虽然上手的门槛很高，但是对于一个真正的javascript程序员来说，反而更值得；而jQuery似乎另类了，改变了普通的编写javascript的编写方式，虽然说它封装的很好，“用最少的代码实现复杂的功能”，但是它的可读性就很差了，虽然门槛很低，毫无javascript基础的程序员在看了它的API文档之后都能够利用它写出很多丰富的效果。但是，作为程序员，这样下去行吗？ jQuery是毒药 &#8212;&#8212; 很多人都这么说。本人也举得，从一个程序员的成长来看，jQuery是弊大于利。我们更应该做的是学习它的原理和架构，而不是拿来用而已。 一个很经常会发生的问题：我只需要用到一个javascript库中的几个方法，却需要加载整个库的体积，而整个库封装的又十分复杂，拆分起来十分繁琐，怎么办？自己写呗…… 一个javascript库的本意虽然说是为了提高开发效率、解决浏览器的兼容性问题、统一开发规范以及解决安全隐患等等。但是在设计javascript库的时候，我们是不是应该多留多点空间给使用者去DIY它的具体的功能，让使用者多点接触到javascript的本质，以及非常容易的缩减库的体积呢？就从这几点出发，YUI3是比较符合“松散耦合”、“颗粒度”的原则的，虽然说jQuery可以通过fn方法来扩展，但都是基于它整个已经封装好的库来说的。但是YUI3也有它的缺点：学习成本高、整体体积庞大、可能一步小心在use方法里多加载几个文件，或者使用”*”，那么需要异步加载的js文件也是很多的、以及它内部组件之间的依赖关系也是比较复杂的。 为了说明我的想法，首先从我编写的query鸡查询函数（目前还没完善，先拿来做例子）开始说起，我的想法是：只在query里实现最基本的selector查询，比如ID、class、tag、属性，之后用户可以自定义selector添加到查询函数当中，来实现自己特定的查询需求，从这点出发，改写了之前所写的query代码（之前的query.js），目前它只集合了ID、class、tag、属性选择器（或者也可以干脆连这些使用者都可以重新定义自己的功能函数，自己来实现，DIY很爽~），其他的自定义选择器都可以自己DIY，并且编写它的实现方式（留给使用者更多的编写底层代码的空间，爱怎么实现就怎么实现，方法是多样的），比如：给selector添加“:first”和“:l”来实现CSS3中的:first-child和:last-child的功能： [javascript] //q:表示当前的selector，比如“div p:first”，就是div和p:first，使用split通过空格切分的单个selector //p:表示是上一级查询的结果，是数组类型的。 query.config.addSelector(&#34;:first&#34;,function(q,p){ var tagName = q.split(&#34;:first&#34;)[0], returnEl = [], index=0, &#8230; <a href="http://www.ilovejs.net/archives/1129" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
“松散耦合”、“颗粒度”是相对于javascript库或者javascript框架来说的，它涉及的概念和包含的知识是很多的，而其中之一，就是说javascript库或者框架从整理来看是容易拆分，也容易自定义的组合，来实现特定需求的功能。之前有很多说法说YUI的编写方法才更接近于javascript的本质，虽然上手的门槛很高，但是对于一个真正的javascript程序员来说，反而更值得；而jQuery似乎另类了，改变了普通的编写javascript的编写方式，虽然说它封装的很好，“用最少的代码实现复杂的功能”，但是它的可读性就很差了，虽然门槛很低，毫无javascript基础的程序员在看了它的API文档之后都能够利用它写出很多丰富的效果。但是，作为程序员，这样下去行吗？
</p>
<p>
<em>jQuery是毒药</em> &#8212;&#8212; 很多人都这么说。本人也举得，从一个程序员的成长来看，jQuery是弊大于利。我们更应该做的是学习它的原理和架构，而不是拿来用而已。
</p>
<p>
一个很经常会发生的问题：我只需要用到一个javascript库中的几个方法，却需要加载整个库的体积，而整个库封装的又十分复杂，拆分起来十分繁琐，怎么办？自己写呗……
</p>
<p>
一个javascript库的本意虽然说是为了提高开发效率、解决浏览器的兼容性问题、统一开发规范以及解决安全隐患等等。但是在设计javascript库的时候，我们是不是应该多留多点空间给使用者去DIY它的具体的功能，让使用者多点接触到javascript的本质，以及非常容易的缩减库的体积呢？就从这几点出发，YUI3是比较符合“松散耦合”、“颗粒度”的原则的，虽然说jQuery可以通过fn方法来扩展，但都是基于它整个已经封装好的库来说的。但是YUI3也有它的缺点：学习成本高、整体体积庞大、可能一步小心在use方法里多加载几个文件，或者使用”*”，那么需要异步加载的js文件也是很多的、以及它内部组件之间的依赖关系也是比较复杂的。
</p>
<p>
为了说明我的想法，首先从我编写的query鸡查询函数（目前还没完善，先拿来做例子）开始说起，我的想法是：只在query里实现最基本的selector查询，比如ID、class、tag、属性，之后用户可以自定义selector添加到查询函数当中，来实现自己特定的查询需求，从这点出发，改写了之前所写的query代码（之前的<a  href="http://www.ilovejs.net/lab/query/query.js">query.js</a>），目前它只集合了ID、class、tag、属性选择器（或者也可以干脆连这些使用者都可以重新定义自己的功能函数，自己来实现，DIY很爽~），其他的自定义选择器都可以自己DIY，并且编写它的实现方式（留给使用者更多的编写底层代码的空间，爱怎么实现就怎么实现，方法是多样的），比如：给selector添加“:first”和“:l”来实现CSS3中的:first-child和:last-child的功能：
</p>
<p>[javascript]<br />
//q:表示当前的selector，比如“div p:first”，就是div和p:first，使用split通过空格切分的单个selector<br />
//p:表示是上一级查询的结果，是数组类型的。<br />
query.config.addSelector(&quot;:first&quot;,function(q,p){<br />
  var tagName = q.split(&quot;:first&quot;)[0],<br />
	  returnEl = [],<br />
	  index=0,<br />
	  tmp=null;<br />
  for(var i=0,l=p.length;i&lt;l;i++){<br />
	(tmp=query(tagName,[p[i]])) &amp;&amp; (returnEl[index++]=tmp[0]);<br />
  }<br />
  return returnEl;<br />
});<br />
///////////////////////////////////////////////////////////<br />
query.config.addSelector(&quot;:l&quot;,function(q,p){<br />
  var tagName = q.split(&quot;:l&quot;)[0],<br />
	  returnEl = [],<br />
	  index=0,<br />
	  tmp=null;<br />
  for(var i=0,l=p.length;i&lt;l;i++){<br />
	(tmp=query(tagName,[p[i]])) &amp;&amp; (returnEl[index++]=tmp[tmp.length-1]);<br />
  }<br />
  return returnEl;<br />
});<br />
[/javascript]</p>
<p>
通过这样的方式，使得core核心代码尽可能的小，可扩展性强，同时也提供给使用者更多的编码空间，了解javascript这门语言的核心知识。目前经过压缩过后的<a  href="/lab/query/query2-min.js">query2-min.j</a>s和未压缩的<a  href="/lab/query/query2.js">query2.js</a>提供浏览。并附带实例：《<a  href="/lab/query/query2.html">点点看呗</a>》
</p>
<p>
扯谈完毕，欢迎拍砖~</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1129/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>在IE中模拟Worker</title>
		<link>http://www.ilovejs.net/archives/1118</link>
		<comments>http://www.ilovejs.net/archives/1118#comments</comments>
		<pubDate>Sat, 07 Aug 2010 13:50:29 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[性能优化]]></category>
		<category><![CDATA[Worker]]></category>
		<category><![CDATA[多线程]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1118</guid>
		<description><![CDATA[2010-8-8 update:在IE8下的eval是不支持下面两种的用法的，很杯具，都会提示“对象不支持此属性或方法”的错误。 [javascript] //第一： eval(&#34;onmessage=function(str){alert(str);}&#34;); onmessage(&#34;shllo&#34;); //第二： var s = document.createElement(&#34;script&#34;),h=document.getElementsByTagName(&#34;head&#34;)[0]; s.text=&#34;onmessage=function(str){alert(str);}&#34;; h.appendChild(s); onmessage(&#34;hello&#34;); [/javascript] 说到这个，还发现一点很容易造成失误的地方：在浏览器解析过的script中的代码，浏览器不会重新对该script标签内的行内脚本、外联脚本执行，就算是重新给script标签定义行内脚本或者修改它的src来链接到其他的javascript脚本，浏览器都不会重新解析。 &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;- 提IE8 eval的兼容性分界线 &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211; &#8230; <a href="http://www.ilovejs.net/archives/1118" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
<strong>2010-8-8 update:</strong>在IE8下的eval是不支持下面两种的用法的，很杯具，都会提示“对象不支持此属性或方法”的错误。
</p>
<p>[javascript]<br />
//第一：<br />
eval(&quot;onmessage=function(str){alert(str);}&quot;);<br />
onmessage(&quot;shllo&quot;);<br />
//第二：<br />
var s = document.createElement(&quot;script&quot;),h=document.getElementsByTagName(&quot;head&quot;)[0];<br />
s.text=&quot;onmessage=function(str){alert(str);}&quot;;<br />
h.appendChild(s);</p>
<p>onmessage(&quot;hello&quot;);<br />
[/javascript]</p>
<p><p>
说到这个，还发现一点很容易造成失误的地方：在浏览器解析过的script中的代码，浏览器不会重新对该script标签内的行内脚本、外联脚本执行，就算是重新给script标签定义行内脚本或者修改它的src来链接到其他的javascript脚本，浏览器都不会重新解析。
</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;- 提IE8 eval的兼容性分界线 &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;
</p>
<p>
从上一篇文章《<a  href="http://www.ilovejs.net/archives/1079">Web Worker浅析</a>》中，我们了解到Worker的思维是跟Ajax类似的，包括它也不支持跨域调用javascript文件，这说明底层的数据交互还是跟Ajax的模式类似（也有可能就是使用了Ajax的方式）。但是由于IE8及以下版本都不支持Worker，所以IE就不能充分利用Worker的优点来优化浏览器执行javascript代码的性能了。但是既然Worker跟Ajax类似，那么就让IE使用Ajax的方式来实现吧，这也不是不行的。
</p>
<p>
在IE中实现Worker机制，一个比较棘手的问题是postMessage、onmessage在主页面和Worker之间的调用问题，从代码上看，主页面是通过Worker类的实例化对象来调用postMessage、onmessage，而Worker里是直接声明和调用。所以在IE里，就可以模拟Worker的操作方式了。下面是我在IE下实现的方式：
</p>
<ol>
<li>在IE下重新定义Worker类，并且带有一个postMessage方法，这样就的话不会跟支持Worker的浏览器相冲突</li>
<li>使用Ajax的方式来加载外联的javascript文件，并通过eval执行返回的代码</li>
<li>通过一个全局的字面量对象，来实现两个文件之间的数据传输</li>
<li>不能改变标准的Worker类的编写方式，这个是一定要做到的</li>
</ol>
<p>从上面的几点思路出发，编写了下面的实现代码：<br />
[javascript]<br />
(function(g){<br />
   if(!document.all) return;</p>
<p>   var xhr=function(){<br />
     var x = null;<br />
     try{<br />
	   x = new ActiveXObject(&quot;Msxml2.XMLHTTP&quot;);<br />
	 }catch(e){<br />
       x = new ActiveXObject(&quot;Microsoft.XMLHTTP&quot;);<br />
	 }<br />
	 return x;<br />
   }</p>
<p>   g.postMessage = function(data){<br />
     g._evt_.data = data;<br />
   }</p>
<p>   var Worker = function(url){<br />
     this.url = url;<br />
   }</p>
<p>   Worker.prototype={<br />
     postMessage:function(data){<br />
       g._evt_={};<br />
	   g._evt_.data=data;<br />
	   var x=xhr(),t=this;<br />
	   x.open(&quot;GET&quot;,this.url,true);<br />
	   x.onreadystatechange=function(){<br />
	     if(x.readyState === 4 &amp;&amp; (x.status === 304 || x.status === 200)){<br />
                   //直接使用eval(x.responseText)在IE8下会提示错误，很奇怪，可能跟eval函数有关了<br />
                   //为此不得不使用这种不太牢固的方法<br />
		   eval(x.responseText.replace(&quot;onmessage&quot;,&quot;var onmessage&quot;));<br />
		   onmessage(g._evt_); //执行Worker中定义的onmessage方法<br />
		   t.onmessage(g._evt_); //执行主页面中的onmessage方法<br />
		   g._evt_ = null;<br />
		 }<br />
	   }<br />
	   x.send();<br />
	 }<br />
   }<br />
   g.Worker = Worker;<br />
})(this);<br />
[/javascript]<br />
在使用上有一点得注意，虽然在代码上没改变，但是在主页面中postMessage和onmessage的顺序得保持：先写onmessage、接着写postMessage方法，主要是为了在IE下能兼容。比如：<br />
[javascript]<br />
var worker = new Worker(&quot;js.js&quot;);</p>
<p>worker.onmessage = function(evt){<br />
  alert(evt.data);<br />
}<br />
 //注意postMessage方法一定要在onmessage后面声明，否则会导致代码只会有一次有效。<br />
worker.postMessage(&quot;supersha&quot;);<br />
[/javascript]</p>
<p>
到目前为止，测试还算良好，《<a  href="http://www.ilovejs.net/lab/ieworker/">测试页面</a>》，在各个浏览器下都能够跑起来。
</p>
<p>
目前这个只是个简单的实现方案，代码上还是比较简单的，有待进一步的完善……</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1118/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>overflow:hidden带来的问题</title>
		<link>http://www.ilovejs.net/archives/1105</link>
		<comments>http://www.ilovejs.net/archives/1105#comments</comments>
		<pubDate>Thu, 05 Aug 2010 16:32:38 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[动画]]></category>
		<category><![CDATA[浏览器]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1105</guid>
		<description><![CDATA[即时更新：由@drunber提供的解决办法：设置父元素的padding或者border、float、position:absolute也可以解决问题，经测试验证通过。但是有一点需要说明的是：上下padding和border是必须要有数值的，设置为0无效。 但是对于动画来说，overflow:hidden是必须要设置的，否则里面的文本不会被遮盖。 &#8212;&#8212;&#8212;===========&#8212;&#8211; 即时更新分界线 &#8212;&#8212;===========&#8212;&#8212;&#8212;&#8211; 最近接到个需求，在搜索结果中添加下拉动画，高度和透明度都需要渐变。在测试过程中，遇到这样的一个问题：在一个div容器中包含了几个p标签，而且全在默认样式的情况，这样通过offsetHeight，clientWidth，scrollHeight等等获得div的高度，之后动态设置div的overflow样式属性为hidden，这样上面所获得的高度不准确了，《点击测试吧》，这样的后果就是动画被和谐了。 从这里的overflow:hidden对div的高度的差异可以看出：容器包含内容的解析原理。正常默认情况下，比如div包含一个p标签，这样div的宽高是会忽略p标签默认的margin值；但是一旦给div设置了overflow:hidden之后，div的实际宽高就需要加上p的margin值了。不过值得庆幸的是，在给div设置了overflow:hidden之后，通过offsetHeight等来获取div的宽高，是准确的。 从上面的分析中对于开头遇到的问题，就可以有三种方法来解决了：第一、在动态设置overflow:hidden之后来获取容器的高度，《点点测试吧》；第二、将p标签的margin清0处理，《再点点呗》；第三、干脆就不要使用p标签，改用没有默认margin的div吧，很勉强的方法，《最后点击测试下》。 Tip: 经过测试发现，设置overflow属性为hidden、auto都存在上面所说的情况。]]></description>
			<content:encoded><![CDATA[<p>
<em>即时更新：</em>由<em>@drunber</em>提供的解决办法：设置父元素的padding或者border、float、position:absolute也可以解决问题，经测试验证通过。但是有一点需要说明的是：上下padding和border是必须要有数值的，设置为0无效。
</p>
<p>
但是对于动画来说，overflow:hidden是必须要设置的，否则里面的文本不会被遮盖。
</p>
<p>
&#8212;&#8212;&#8212;===========&#8212;&#8211; 即时更新分界线 &#8212;&#8212;===========&#8212;&#8212;&#8212;&#8211;
</p>
<p>
最近接到个需求，在搜索结果中添加下拉动画，高度和透明度都需要渐变。在测试过程中，遇到这样的一个问题：在一个div容器中包含了几个p标签，而且全在默认样式的情况，这样通过offsetHeight，clientWidth，scrollHeight等等获得div的高度，之后动态设置div的overflow样式属性为hidden，这样上面所获得的高度不准确了，《<a  href="/lab/donghua/donghua.html">点击测试吧</a>》，这样的后果就是动画被和谐了。
</p>
<p>
从这里的overflow:hidden对div的高度的差异可以看出：容器包含内容的解析原理。正常默认情况下，比如div包含一个p标签，这样div的宽高是会忽略p标签默认的margin值；但是一旦给div设置了overflow:hidden之后，div的实际宽高就需要加上p的margin值了。不过值得庆幸的是，在给div设置了overflow:hidden之后，通过offsetHeight等来获取div的宽高，是准确的。
</p>
<p>
从上面的分析中对于开头遇到的问题，就可以有三种方法来解决了：第一、在动态设置overflow:hidden之后来获取容器的高度，《<a  href="/lab/donghua/donghua2.html">点点测试吧</a>》；第二、将p标签的margin清0处理，《<a  href="/lab/donghua/donghua3.html">再点点呗</a>》；第三、干脆就不要使用p标签，改用没有默认margin的div吧，很勉强的方法，《<a  href="/lab/donghua/donghua4.html">最后点击测试下</a>》。
</p>
<p>
<strong>Tip:</strong> 经过测试发现，设置overflow属性为hidden、auto都存在上面所说的情况。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1105/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>前端模板编程方式</title>
		<link>http://www.ilovejs.net/archives/1100</link>
		<comments>http://www.ilovejs.net/archives/1100#comments</comments>
		<pubDate>Tue, 03 Aug 2010 08:06:14 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[性能优化]]></category>
		<category><![CDATA[模板编程]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1100</guid>
		<description><![CDATA[今天接触到一种使用javascript来实现的前端模板编写技巧，不需要后端的匹配替换，直接在浏览器端就可以完成。Not Using jQuery JavaScript Templates? You’re Really Missing Out。觉得思路不错，特此分享。 在浏览器端实现模板编程的难点之一，就是怎么编写HTML模板。这个在那篇文章中使用了script标签，这个觉得非常太神奇了，最神奇的是给script的type设置为text/html之后，它就不会使用javascript引擎来解析那些代码，也不会在页面上将HTML显示出来，同时也不报错。这都被发现了，牛逼！ 知道了怎么保存模板之后，接下来的事情就是解析模板了，统一替换变量的声明方式，下面是我样例中使用的方式： [html] &#60;script id=&#34;test&#34; type=&#34;text/html&#34;&#62; &#60;li&#62;&#60;a href=&#34;${url}$&#34;&#62;${name}$&#60;/a&#62;&#60;/li&#62; &#60;/script&#62; [/html] 之后，就是通过javascript程序来解析了，我简单写了一个template函数来实现这个功能，《测试用例》： &#8230; <a href="http://www.ilovejs.net/archives/1100" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
今天接触到一种使用javascript来实现的前端模板编写技巧，不需要后端的匹配替换，直接在浏览器端就可以完成。<a  href="http://blog.reybango.com/2010/07/09/not-using-jquery-javascript-templates-youre-really-missing-out/">Not Using jQuery JavaScript Templates? You’re Really Missing Out</a>。觉得思路不错，特此分享。
</p>
<p>
在浏览器端实现模板编程的难点之一，就是怎么编写HTML模板。这个在那篇文章中使用了script标签，这个觉得非常太神奇了，最神奇的是给script的type设置为text/html之后，它就不会使用javascript引擎来解析那些代码，也不会在页面上将HTML显示出来，同时也不报错。这都被发现了，牛逼！
</p>
<p>
知道了怎么保存模板之后，接下来的事情就是解析模板了，统一替换变量的声明方式，下面是我样例中使用的方式：
</p>
<p>[html]<br />
&lt;script id=&quot;test&quot; type=&quot;text/html&quot;&gt;<br />
&lt;li&gt;&lt;a href=&quot;${url}$&quot;&gt;${name}$&lt;/a&gt;&lt;/li&gt;<br />
&lt;/script&gt;<br />
[/html]<br />
之后，就是通过javascript程序来解析了，我简单写了一个template函数来实现这个功能，《<a  href="/lab/template/">测试用例</a>》：<br />
[javascript]<br />
function template(data,sEl,dEl){<br />
  var html = sEl.nodeName &amp;&amp; sEl.innerHTML || sEl,s = tmp = &quot;&quot;;<br />
  data = data || [];<br />
  for(var i=0,l=data.length;i&lt;l;i++){<br />
    tmp = html;<br />
	for(var k in data[i]){<br />
	  tmp = tmp.replace(RegExp(&quot;\\$\\{&quot;+k+&quot;\\}\\$&quot;,&quot;gi&quot;),data[i][k]);<br />
	}<br />
	s += tmp;<br />
  }<br />
  (dEl = dEl.nodeName &amp;&amp; dEl || document.getElementById(dEl)).innerHTML = s;<br />
}<br />
[/javascript]</p>
<p>
通过上面的解析，在页面中就可以定制模板（特别是那些标题列表内容，即：ul，ol等），通过数据源，在页面中显示出来。当然了，这个在页面开始加载的时候如果就是用这个的话，无疑是多此一举，但是如果是通过动态获取数据（JSON，XML），并且需要将数据在页面中显示出来的时候，这种思路或许可以带上用场，减小代码编写量了，提高效率了。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1100/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>无聊哥的代码 &#8212; “鸡”查询</title>
		<link>http://www.ilovejs.net/archives/1085</link>
		<comments>http://www.ilovejs.net/archives/1085#comments</comments>
		<pubDate>Mon, 02 Aug 2010 16:35:45 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[DOM]]></category>
		<category><![CDATA[query]]></category>
		<category><![CDATA[querySelectorAll]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1085</guid>
		<description><![CDATA[刚上班，首先是文档哥，之后就是无聊哥了，真杯具。但是杯具下就好了，人不杯具。消遣的最好方式就是练练脑，写代码，query就是杯具下的产物。先出土个雏形，有时间还成无聊哥了再来扩展下。 query根据CSS规则来查询DOM，提供了基础的CSS选择符： tag,.class,#id,[attr],tag[attr],tag[attr=&#34;value&#34;]... 在测试跟jquery的查询速度比较的时候，再添加了对querySelectorAll（语法是：baseElement.querySelectorAll(selector)，这里的baseElement其实是可以为除了文本节点和空节点之外的任何的DOM节点的，别以为只是document而已）的支持。编写的代码中加入了本人认为不错的编写方式，如果你对阅读代码有兴趣，那就看看吧，欢迎提出更好的方式(如果这里显得难看了，就自己下载来看：query.js)： [javascript] ;(function(g){ var D = document, _tag = function(tag,p){ return p.getElementsByTagName(tag &#124;&#124; &#34;*&#34;); }; var _queryMethod &#8230; <a href="http://www.ilovejs.net/archives/1085" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
刚上班，首先是文档哥，之后就是无聊哥了，真杯具。但是杯具下就好了，人不杯具。消遣的最好方式就是练练脑，写代码，query就是杯具下的产物。先出土个雏形，有时间还成无聊哥了再来扩展下。
</p>
<p>
query根据CSS规则来查询DOM，提供了基础的CSS选择符：
</p>
<pre class="wp-code-highlight prettyprint">
tag,.class,#id,[attr],tag[attr],tag[attr=&quot;value&quot;]...
</pre>
<p>在测试跟jquery的查询速度比较的时候，再添加了对querySelectorAll（语法是：baseElement.querySelectorAll(selector)，这里的baseElement其实是可以为除了文本节点和空节点之外的任何的DOM节点的，别以为只是document而已）的支持。编写的代码中加入了本人认为不错的编写方式，如果你对阅读代码有兴趣，那就看看吧，欢迎提出更好的方式(如果这里显得难看了，就自己下载来看：<a  href="/lab/query/query.js">query.js</a>)：<br />
<span id="more-1085"></span><br />
[javascript]<br />
;(function(g){<br />
	var D = document,<br />
		  _tag = function(tag,p){<br />
		    return p.getElementsByTagName(tag || &quot;*&quot;);<br />
	    };<br />
  var _queryMethod = {<br />
		&quot;#&quot;:function(q){<br />
			var bits = q.split(&quot;#&quot;),<br />
				  tagName = bits[0],<br />
				  id = bits[1],<br />
				  element = D.getElementById(id);<br />
			return tagName &amp;&amp; element.tagName.toLowerCase() != tagName ? [] : [element];<br />
		},<br />
		&quot;.&quot;:function(q,p){<br />
			var bits = q.split(&quot;.&quot;),<br />
				  tagName = bits[0],<br />
				  cn=bits[1],<br />
				  elems = null,<br />
				  returnEl = [],<br />
				  index = 0;<br />
		  for(var i=0,l = p.length;i&lt;l;i++){<br />
				elems = _tag(tagName,p[i]);<br />
				var tmp = null;<br />
				for(var j =0,m = elems.length;j&lt;m;j++){<br />
					if(!/\S/.test((tmp = elems[j]).nodeValue)) continue;<br />
					if(new RegExp(&quot;\\b&quot;+cn+&quot;\\b&quot;).test(tmp.className)){<br />
						returnEl[index++] = tmp;<br />
					}<br />
				}<br />
			}<br />
			return returnEl;<br />
		},<br />
		&quot;tag&quot;:function(q,p){<br />
			var found,returnEl = [],index=0;<br />
			q = q;<br />
			for(var i=0,l=p.length;i&lt;l;i++){<br />
				found = _tag(q,p[i]);<br />
				for(var j =0,m=found.length;j&lt;m;j++){<br />
					returnEl[index++] = found[j];<br />
				}<br />
			}<br />
			return returnEl;<br />
		},<br />
		&quot;attr&quot;:function(operation,tag,attr,attrValue,p){<br />
			var found =[],returnEl = [],index=fIndex=0;</p>
<p>			for(var i=0,l=p.length;i&lt;l;i++){<br />
				var tmp = _tag(tag,p[i]);<br />
				for(var j=0,m=tmp.length;j&lt;m;j++){<br />
					found[index++]=tmp[j];<br />
				}<br />
			}</p>
<p>			//不错吧？ ^_^<br />
			var checkFn = {<br />
				&#8216;=&#8217;:function(e) { return (e.getAttribute(attr) == attrValue); },<br />
		    &#8216;~&#8217;:function(e) { return (e.getAttribute(attr).match(new RegExp(&#8216;\\b&#8217;+attrValue+&#8217;\\b&#8217;))); },<br />
		    &#8216;|&#8217;:function(e) { return (e.getAttribute(attr).match(new RegExp(&#8216;^&#8217;+attrValue+&#8217;-?&#8217;))); },<br />
		    &#8216;^&#8217;:function(e) { return (e.getAttribute(attr).indexOf(attrValue) == 0); },<br />
		    &#8216;$&#8217;:function(e) { return (e.getAttribute(attr).lastIndexOf(attrValue) == e.getAttribute(attr).length &#8211; attrValue.length); },<br />
		    &#8216;*&#8217;:function(e) { return (e.getAttribute(attr).indexOf(attrValue) &gt; -1); },<br />
		    &#8216;a&#8217;:function(e) { return e.getAttribute(attr);}<br />
			}[operation];</p>
<p>			for(var i=0,l=found.length;i&lt;l;i++){<br />
				if(checkFn(found[i])){<br />
					returnEl[fIndex++] = found[i];<br />
				}<br />
			}<br />
			return returnEl;<br />
		}<br />
  }</p>
<p>	//处理每一个token<br />
	var _querySelector = function(q,p){<br />
		var elements = /#/.test(q) ? _queryMethod[&quot;#&quot;](q) : /\./.test(q) ? _queryMethod[&quot;.&quot;](q,p) : [];<br />
		if(elements.length) return elements;<br />
		if(!elements.length &amp;&amp; q.match(/^(\w*)\[(\w+)([=~\|\^\$\*]?)=?&quot;?([^\]&quot;]*)&quot;?\]$/)){<br />
			return _queryMethod[&quot;attr&quot;](RegExp.$3 || &quot;a&quot;,RegExp.$1,RegExp.$2,RegExp.$4,p);<br />
	  }<br />
		if(!elements.length){<br />
			return _queryMethod[&quot;tag&quot;](q,p);<br />
		}<br />
		return elements;<br />
	}</p>
<p>	var _query = function(q){<br />
		if(document.querySelectorAll){return document.querySelectorAll(q);}<br />
		var tokens = q.split(&#8216; &#8216;),token,elems=[D];<br />
		for(var i=0,l=tokens.length;i&lt;l;i++){<br />
			elems=_querySelector( tokens[i],elems);<br />
		}<br />
		return elems;<br />
	}<br />
	g.query=_query || {};<br />
})(this);<br />
[/javascript]<br />
我很经得起批的……《<a  href="/lab/query/">测试示例</a>》</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1085/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>

