<?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/category/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>HTML快捷编写方式</title>
		<link>http://www.ilovejs.net/archives/1551</link>
		<comments>http://www.ilovejs.net/archives/1551#comments</comments>
		<pubDate>Thu, 08 Dec 2011 06:51:06 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[(X)HTML]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[HTML]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1551</guid>
		<description><![CDATA[礼拜一点小想法，写了个半成品，只供试玩，有心思再来优化解析方式，让它支持更多的语法。 试用地址：http://www.ilovejs.net/lab/makeHTML.html]]></description>
			<content:encoded><![CDATA[<p>礼拜一点小想法，写了个半成品，只供试玩，有心思再来优化解析方式，让它支持更多的语法。<br />
试用地址：<a href="http://www.ilovejs.net/lab/makeHTML.html" target="_blank">http://www.ilovejs.net/lab/makeHTML.html</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1551/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<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>权衡之变</title>
		<link>http://www.ilovejs.net/archives/1511</link>
		<comments>http://www.ilovejs.net/archives/1511#comments</comments>
		<pubDate>Sun, 20 Mar 2011 09:05:57 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[代码设计]]></category>
		<category><![CDATA[性能优化]]></category>
		<category><![CDATA[模块化]]></category>
		<category><![CDATA[重构]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1511</guid>
		<description><![CDATA[《重构&#8211;改善既有代码的设计》这本书是去年买的了，利用晚上空闲时间看了大部分的内容，包括一些重构的技巧、良好代码的特点、代码可读性和提高语义化等。这本书改变了很多我之前所持有的观念，包括代码性能、模块化设计、结构样式逻辑分离等的思维。下面粗略的罗列几点目前自己从这本书中所理解到的其中一些知识： 重构本来就不是一件应该特别拨出时间做的事情，重构应该随时随地进行。 第一次做某件事情时只管去做；第二次做类似的事情会产生反感，但无论如何还是可以去做；第三次再做类似的事，你就应该重构。 &#8212;&#8212;“事不过三，三则重构。” 只要将相对独立的代码从大型函数中提炼出来，就可以大大提高代码的可读性。 不单只让函数能够功能单一的执行，同时也需要让一个类也只需要明确的做一件事情，或者只是对各个功能的集合（代理、命名空间）。 在该函数最常引用的类中建立一个有着类似行为的新函数，将旧函数变成一个单纯的委托函数，或者将旧函数完全移除。根据这个函数与哪个对象的交流比较多，决定将函数移动的位置。 抽象函数可以是多重的，将可复用的代码尽量的抽象它，在抽象后的函数中，又需要对函数进行进一步的思考，是否功能还可以更加的细化，让功能函数为更多的其他函数、对象、类所复用。距离组织一个库来说：core大部分只提供核心类（核心对象）的扩展、继承机制、底层内置功能的扩充、封装机制、兼容性判断机制、对象版本管理机制等，这就算是一个core最细化的抽象。 一个类应该是一个清楚的抽象，处理一些明确的责任。 “封装”意味着每个对象都应该尽可能少了解系统的其他部分，如此一来，一旦发生变化，需要了解这一变化的对象和函数就会比较少，这会使变化比较容易进行。 有几个原因造成我喜欢简短而命名良好的函数：首先，如果每个函数的粒度都很小，那么函数被复用的机会就更大；其次，这会使高层函数读起来就像一系列注释；再次，如果函数都是细粒度，那么函数的覆写也会更容易些。 在函数的命名上，长度不是问题，关键在于函数名称和函数本体之间的语义距离。 创造一个新函数，根据这个函数的意图来对它命名（以它“做什么”来命名，而不是以它“怎么做”命名），但是如果你想不出一个更有意义的名称，那就别动。 如果在提炼的函数中需要一些原来旧函数中的局部变量数据，那么就将这些局部变量数据通过参数的形式传递过去。 当一个函数有参数的时候，在函数体里就尽量不要去修改参数的值，不管是通过值还是引用传递进来的，除非有另外特定的目的。 将函数细粒化为一个个功能单一的函数，再调用这些函数，这必然造成了性能上更多的耗费，但是这跟后期的维护、以及代码的可读性等等相比，或许还是值得这么做的。 永远不要认为你写的代码只是自己看的而已，要想到新来的人接手你的这些代码的时候，他们看你的代码，是否能够很愉快的接受并理清整个思路。不要把这个维护代码的痛苦留给接手你的人。不管你是通过更多的注释还是重构代码的方式来解决代码的可维护性的问题，都要想到这一点。 在分解一个函数的时候，我的思路是：需求是什么 &#8211;> 需求的功能有哪些 &#8230; <a href="http://www.ilovejs.net/archives/1511" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
《<a href="http://product.dangdang.com/product.aspx?product_id=20801315">重构&#8211;改善既有代码的设计</a>》这本书是去年买的了，利用晚上空闲时间看了大部分的内容，包括一些重构的技巧、良好代码的特点、代码可读性和提高语义化等。这本书改变了很多我之前所持有的观念，包括代码性能、模块化设计、结构样式逻辑分离等的思维。下面粗略的罗列几点目前自己从这本书中所理解到的其中一些知识：
</p>
<blockquote><p>重构本来就不是一件应该特别拨出时间做的事情，重构应该随时随地进行。<br />
第一次做某件事情时只管去做；第二次做类似的事情会产生反感，但无论如何还是可以去做；第三次再做类似的事，你就应该重构。 &#8212;&#8212;“事不过三，三则重构。”
</p></blockquote>
<p><span id="more-1511"></span></p>
<ol>
<li>只要将相对独立的代码从大型函数中提炼出来，就可以大大提高代码的可读性。</li>
<li>不单只让函数能够功能单一的执行，同时也需要让一个类也只需要明确的做一件事情，或者只是对各个功能的集合（代理、命名空间）。</li>
<li>在该函数最常引用的类中建立一个有着类似行为的新函数，将旧函数变成一个单纯的委托函数，或者将旧函数完全移除。根据这个函数与哪个对象的交流比较多，决定将函数移动的位置。</li>
<li>抽象函数可以是多重的，将可复用的代码尽量的抽象它，在抽象后的函数中，又需要对函数进行进一步的思考，是否功能还可以更加的细化，让功能函数为更多的其他函数、对象、类所复用。距离组织一个库来说：core大部分只提供核心类（核心对象）的扩展、继承机制、底层内置功能的扩充、封装机制、兼容性判断机制、对象版本管理机制等，这就算是一个core最细化的抽象。</li>
<li>一个类应该是一个清楚的抽象，处理一些明确的责任。</li>
<li>“封装”意味着每个对象都应该尽可能少了解系统的其他部分，如此一来，一旦发生变化，需要了解这一变化的对象和函数就会比较少，这会使变化比较容易进行。</li>
<li>有几个原因造成我喜欢简短而命名良好的函数：首先，如果每个函数的粒度都很小，那么函数被复用的机会就更大；其次，这会使高层函数读起来就像一系列注释；再次，如果函数都是细粒度，那么函数的覆写也会更容易些。<br />
在函数的命名上，长度不是问题，关键在于函数名称和函数本体之间的语义距离。<br />
创造一个新函数，根据这个函数的意图来对它命名（以它“做什么”来命名，而不是以它“怎么做”命名），但是如果你想不出一个更有意义的名称，那就别动。<br />
如果在提炼的函数中需要一些原来旧函数中的局部变量数据，那么就将这些局部变量数据通过参数的形式传递过去。
</li>
<li>当一个函数有参数的时候，在函数体里就尽量不要去修改参数的值，不管是通过值还是引用传递进来的，除非有另外特定的目的。</li>
<li>将函数细粒化为一个个功能单一的函数，再调用这些函数，这必然造成了性能上更多的耗费，但是这跟后期的维护、以及代码的可读性等等相比，或许还是值得这么做的。</li>
<li>永远不要认为你写的代码只是自己看的而已，要想到新来的人接手你的这些代码的时候，他们看你的代码，是否能够很愉快的接受并理清整个思路。不要把这个维护代码的痛苦留给接手你的人。不管你是通过更多的注释还是重构代码的方式来解决代码的可维护性的问题，都要想到这一点。</li>
<li>在分解一个函数的时候，我的思路是：需求是什么 &#8211;> 需求的功能有哪些 &#8211;> 团队开发方式是如何的 &#8211;> 在当前功能点下，罗列函数层级的功能点，并根据这些功能点进行整合，即是高内聚，低耦合。之后逐一组建函数。<br />
明白需求是什么，这个是做开发的最先需要了解清楚的，这点无可厚非；在这个需求下面，需要实现一些什么功能，这个是需要根据需求来分析出来的，之后的就是根据自己团队的代码开发模式，并逐步将需求的功能点，细化到代码层级的功能点，将功能抽象出来，提高代码的可复用度。
</li>
</ol>
<p>
自己之前所遵守的高性能、微小代码量、满脑子模块化、保持结构样式逻辑高度分离等的思维，再次进行了权衡的颠覆。对于代码，性能重要，但是人也能很容易的看懂这也重要。一个项目，到底是开发新功能的需求大，还是维护、优化项目的需求更多，这个就需要在高速开发和提高代码的可读性和较少维护成本进行权衡。
</p>
<p>
使用工具进行页面拼装的方式，固然可以提高开发效率，这对于一些促销页面开发、或者是有PM、运营所自定义页面来说，确实有必要。但是这些都是辅助页面，核心产品才是主要关注点，核心产品一般不会轻易的推倒重来，而是不断的进行优化、功能升级、新功能上线等。为此，对于开发者来说，除了代码能够给电脑读，还能很好的给其他开发者读懂，这个有必要。在性能和代码量上或许可以做个权衡，也或者可以从其他方面进行优化来弥补这方面的损失。
</p>
<p>
模块化，有时候真的很少用到，除非是大站点，从整体架构考虑，提高功能的聚合度和整体统一。在一些细小项目、功能开发中，用到更多的还是借助于统一的库，进行二次的功能开发，封装为适合该项目、功能的功能函数集。就如上面《重构》书中所述，当这个功能为几个项目、功能所使用的时候，那么就有必要抽象出来，作为一个模块。但是，对于模块，从现阶段来说，它已经不是跟以前一样，只是一个js文件，它所要负责是它的功能范围内的HTML、CSS、JS，对于页面来说，我无需关心这个模块有啥，我只需要调用这个模块的接口，加载这个模块，那么我的页面中就有了这个模块最基本的功能，再复杂点，就是提供给模块进行扩展的接口，在模块的基础上，进行自定义结构、样式、逻辑。
</p>
<p>
所以，对于模块化，要区分好Moudle，Utilities，功能函数的差别。Util只是对功能逻辑的封装，加载这个js文件，就可以直接使用它所提供的逻辑方法，它并不涉及到样式、结构，只是一个逻辑。功能函数更多的是存在于页面中的，如果使用度够高，那么就会成为Util的一部分。功能函数更多的是在已有的库的基础上进行的二次封装、抽象，提供给其他的功能直接调用。将页面中都会用到的功能进行抽取，作为一个独立的功能函数，通过参数来体现功能的差异。
</p>
<p>
在结构、样式、逻辑上，这个并没有完全的分离的界限，很多时候都需要看功能的具体需求，不能完全要求分离结构和逻辑，就使得在逻辑方面需要做很多的动态创建结构的工作。这就需要权衡：如何使用正确的HTML标签，标签能否提供一些辅助的信息，来简化逻辑的操作和代码量。适合在标签上能做的事情，就让标签来提供。“各司其职”的折中是互相辅助。
</p>
<p>
想得有点多了，需要慢慢学习和实践~~</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1511/feed</wfw:commentRss>
		<slash:comments>2</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>在Ipod Safari下开发有一点点感</title>
		<link>http://www.ilovejs.net/archives/1459</link>
		<comments>http://www.ilovejs.net/archives/1459#comments</comments>
		<pubDate>Sun, 16 Jan 2011 14:10:33 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Ipod Safari]]></category>
		<category><![CDATA[UIX widget system]]></category>
		<category><![CDATA[事件]]></category>
		<category><![CDATA[收藏夹]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1459</guid>
		<description><![CDATA[最近突然脑子一热，Read It Later好、Instapaper也好，保存的网页都是在别人的服务器上，使用别人的工具来浏览，总感觉受牵制，干脆自己倒腾一个这样的工具，把数据提交到自己的网站空间里，之后使用Ipod Touch来看，这个更有保障，功能其实也就需要一个保存网页的URL并且在空闲的时候浏览，简单的一个收藏夹。并且可以顺便尝试使用Youtube的UIX事件机制。 下面是简单的一个UIX事件绑定方式： [javascript] // UIX system var UIX = UIX &#124;&#124; { &#34;registry&#34;:{}, &#34;register&#34;:function(type,uixes){ if(!this.registry[type]){ this.registry[type]={}; } &#8230; <a href="http://www.ilovejs.net/archives/1459" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
最近突然脑子一热，Read It Later好、Instapaper也好，保存的网页都是在别人的服务器上，使用别人的工具来浏览，总感觉受牵制，干脆自己倒腾一个这样的工具，把数据提交到自己的网站空间里，之后使用Ipod Touch来看，这个更有保障，功能其实也就需要一个保存网页的URL并且在空闲的时候浏览，简单的一个收藏夹。并且可以顺便尝试使用Youtube的UIX事件机制。
</p>
<p><span id="more-1459"></span></p>
<p>
下面是简单的一个UIX事件绑定方式：
</p>
<p>[javascript]<br />
// UIX system<br />
var UIX = UIX || {<br />
  &quot;registry&quot;:{},<br />
  &quot;register&quot;:function(type,uixes){<br />
    if(!this.registry[type]){<br />
	  this.registry[type]={};<br />
	}<br />
	for(var uix in uixes){<br />
	  if(uixes.hasOwnProperty(uix)){<br />
	    this.registry[type][uix] = uixes[uix];<br />
	  }<br />
	}<br />
  },<br />
  &quot;handleEvent&quot;: function(evt){<br />
    if(evt.type in this.registry){<br />
	  var actions = this.registry[evt.type];<br />
	  for(var uix in actions){<br />
	    el = evt.target || evt.srcElement;<br />
        if(el.getAttribute(&quot;data-uix&quot;) == uix){<br />
	      actions[uix].call(el,evt);<br />
        }<br />
	  }<br />
	}<br />
  }<br />
};<br />
//End uix system<br />
[/javascript]</p>
<p>
如上代码所示，原理是将事件都绑定到document上，目标元素就使用自定义字段data-uix作为一类相似事件行为的标识，但是涉及到document以及具体的DOM元素的事件处理逻辑，所以就需要进行两个事件绑定的过程：第一个是将uix的事件接口绑定到document上，之后声明每一类的自定义data-uix事件处理程序，这个并不是绑定的方式，而是以data-uix为标识的映射函数
</p>
<p>[javascript]<br />
// UIX system 派上用场了<br />
//document绑定事件<br />
addEvent(document,&quot;click&quot;,function(e){<br />
  UIX.handleEvent(e || window.event);<br />
});<br />
UIX.register(&quot;click&quot;,{<br />
  &quot;mask_read&quot;:function(){  //data-uix为mask_read的一类click事件。<br />
    var index = this.getAttribute(&quot;data-index&quot;);<br />
    var url = this.getAttribute(&quot;data-href&quot;);<br />
    location.href = &quot;mask_read.php?index=&quot;+index+&quot;&amp;url=&quot; + encodeURIComponent(url);<br />
	return true;<br />
  },<br />
  &quot;read_button&quot;:function(){ //data-uix为read_button的一类click事件。<br />
    getData.request(this.getAttribute(&quot;data-read&quot;));<br />
  }<br />
});<br />
[/javascript]</p>
<p>
使用这样的微UIX事件绑定机制，可以根据事件类型来区分该事件类型下的每一类绑定该事件的元素集合，并且使用委托的方式。
</p>
<p>
UIX介绍完了，现在接下来说一下在Ipod Safari下开发这个所遇到的一些问题。首先说一下功能需求：提供已经阅读和未阅读的类型，那么区别这个已读跟未读的状态；页面需要基于Ajax请求，来加载URL列表。就这两个需求。
</p>
<ul>
<li>
在区别已读跟未读状态的时候，既要不阻碍点击URL的title进入到收藏的网址的网站，而且又能够在自己的数据库里标记这条URL已经阅读过，那么就需要在click事件的时候，发送一个请求给服务端，更新数据库的标识。通常的这个做法都是通过动态的New一个Image实例，声明src的方式，但是使用这个方式的时候，FF浏览器下好使，但是Chrome、Safari、Ipod Safari不好使了，无效。因为src指向的是一个php的页面，有朋友测试妨碍西安src如果不指向一个图片的时候，请求无效。所以这种方式使用Image实例指向php页面的方式就不行了（之后测试了使用script标签指向php文件的方式，也不行）。只有使用比较搓的备选方案了，使用中间跳转页的方式，但是这样又会遇到这个样的一个问题：浏览器回退的时候会跳到这个中间页，如果才能够把这个中间页不在浏览器的history里保存呢？方案是有的，使用location.replace做跳转，replace接受一个url的字符串参数，表示跳转到该url下，而不把当前URL记录到history中。
</li>
<li>
第二个需求中，又会遇到怎样的问题呢？异步请求的更新问题，问题还是纠结在浏览器回退的时候，网址夹页面中已经点击过的URL应该清除掉，因为它已经阅读过了。FF、Chrome浏览器下点击回退按钮的时候，会自动重新发送Ajax请求去加载数据，而Safari、Opera、Ipod Safari却没有，那么这就又纳闷了。经过跟朋友讨论过之后，使用：window.onunload=window.onbeforeunload=function(){};<br />
就好使了，Safari、Opera、Ipod Safari都会自动重新发送请求，更新页面。大致的意思就是声明了这个onunload、onbeforeunload之后，浏览器不会cache页面的内容。
</li>
</ul>
<p>
本来以为做这个会很简单，Ipod Safari下总会遇到各种各样跟浏览器不同的行为，特别在事件方面，支持的程度不同之外，触发、执行的方式都有可能不同，或者因为其他的影响而有莫名其妙的失效的情况。
</p>
<p>
由于个人网址夹是open、并且是个人使用的，所以就不在此提供测试地址了。YY一下</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1459/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Perl编译程序升级</title>
		<link>http://www.ilovejs.net/archives/1390</link>
		<comments>http://www.ilovejs.net/archives/1390#comments</comments>
		<pubDate>Sun, 02 Jan 2011 08:28:18 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[性能优化]]></category>
		<category><![CDATA[前端开发工具]]></category>
		<category><![CDATA[编译工具]]></category>
		<category><![CDATA[自动化]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1390</guid>
		<description><![CDATA[经过几个晚上的一点点升级，将之前搞的perl编译脚本进行了重构，并添加了一些功能，包括文件嵌套编译、添加对html文件的简单压缩、添加Google Compiler的压缩模式、修改了文件输出的方式等等。（具体的教程，可以查看：自动化工具提高工作效率中的描述） 在perl文件的头部，添加了几个配置项： $yui_compressor_path：YUI compressor 的jar文件的路径（建议是本地的绝对路径） $google_compiler_path：Google Compiler的jar文件的路径（建议是本地的绝对路径） $compress_type：所使用的压缩方式，值可以为：yui/gc。 $compilation_level：Google Compiler压缩的级别，值可以为：SIMPLE_OPTIMIZATIONS/ADVANCED_OPTIMIZATIONS/WHITESPACE_ONLY $output_dir：编译后的文件的输出目录（建议是跟当前需要编译的文件同一目录下） 建议是在每一个开发目录下配置一个build.pl文件，那么就可以对在当前的目录下进行开发，最后build编译。如今编译的文件都会保存在当前目录下的output文件夹里，文件名不变，可以直接使用编译好的文件进行测试、发布。 如下图所示的嵌套包含示意图，理论上可以无限级的嵌套，压缩： 可以对当前级声明compress:true进行压缩，嵌套之后，在output文件夹中会有中间产物页面产生，但是对于最终页面是没影响的。这样，就可以将几个页面中通用的部分抽取出来，统一管理。 最新的build程序：build_1_0_3_linux.rar，build_1_0_3_win.rar。]]></description>
			<content:encoded><![CDATA[<p>
经过几个晚上的一点点升级，将之前搞的perl编译脚本进行了重构，并添加了一些功能，包括文件嵌套编译、添加对html文件的简单压缩、添加Google Compiler的压缩模式、修改了文件输出的方式等等。（具体的教程，可以查看：<a  href="http://www.ilovejs.net/archives/1348">自动化工具提高工作效率</a>中的描述）
</p>
<p>
在perl文件的头部，添加了几个配置项：<br />
$yui_compressor_path：YUI compressor 的jar文件的路径（建议是本地的绝对路径）<br />
$google_compiler_path：Google Compiler的jar文件的路径（建议是本地的绝对路径）<br />
$compress_type：所使用的压缩方式，值可以为：yui/gc。<br />
$compilation_level：Google Compiler压缩的级别，值可以为：SIMPLE_OPTIMIZATIONS/ADVANCED_OPTIMIZATIONS/WHITESPACE_ONLY<br />
$output_dir：编译后的文件的输出目录（建议是跟当前需要编译的文件同一目录下）
</p>
<p>
建议是在每一个开发目录下配置一个build.pl文件，那么就可以对在当前的目录下进行开发，最后build编译。如今编译的文件都会保存在当前目录下的output文件夹里，文件名不变，可以直接使用编译好的文件进行测试、发布。
</p>
<p>
如下图所示的嵌套包含示意图，理论上可以无限级的嵌套，压缩：
</p>
<p>
<img src="http://www.ilovejs.net/wp-content/uploads/2011/01/perl1.png" alt="" title="文件嵌套" width="520" height="290" class="alignnone size-full wp-image-1397" />
</p>
<p>
可以对当前级声明compress:true进行压缩，嵌套之后，在output文件夹中会有中间产物页面产生，但是对于最终页面是没影响的。这样，<strong>就可以将几个页面中通用的部分抽取出来，统一管理</strong>。
</p>
<p>
最新的build程序：<a  href="/download/build_1_0_3_linux.rar">build_1_0_3_linux.rar</a>，<a  href="/download/build_1_0_3_win.rar">build_1_0_3_win.rar</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1390/feed</wfw:commentRss>
		<slash:comments>0</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>Fetch resources on-demand</title>
		<link>http://www.ilovejs.net/archives/1258</link>
		<comments>http://www.ilovejs.net/archives/1258#comments</comments>
		<pubDate>Mon, 11 Oct 2010 17:01:17 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Ajax]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[性能优化]]></category>
		<category><![CDATA[按需加载]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1258</guid>
		<description><![CDATA[Fetch resources on-demand，中文意思大概就是按需加载资源，而这里的资源不只是CSS、JS文件，Image、swf、Content等都可以利用这种方式。特别是当前Yahoo的首页：http://www.yahoo.com，几乎页面的每一个模块都体现了按需加载的技巧：左边的导航（用户可以定制、点击异步请求更多资源）、中间的新闻、图片tab、右栏的第三方资源等等。 按需加载表面理解起来很简单，但是怎么个按需法呢？我所理解的按需，包括两个方面：一个是按用户的需要；另一个是网站本身的需要。按需加载主要解决的问题就是加快页面的初始化以及在页面初始化的时候最大化减少HTTP请求，因为有些模块比如：图片导航tab、多级菜单、内容导航等等，这些在初始化页面的时候有很多内容都是处于隐藏状态，用户是看不到的，那么这些内容对不同的用户来说有不同的需求，那么这些就可以从页面的初始化中剥离出来，按用户的需求通过异步通信来加载内容和资源。对于网站本身的需要来加载后续资源，比如Google首页对于结果页的一些js、image等资源的pre-fetch的方式，通过分析用户可能会产生的行为，为后续的页面提前加载内容，加快后续页面的初始化速度，从缓存中读取页面所需要的资源。 接下来分析一下淘宝首页（http://www.taobao.com）的一些按需加载的技巧。首先对于中间栏的这个部分的实现： 看这个模块的源码之后发现，除了初始化第一个tab内容之后，后面隐藏的几个tab的资源是没有加载的，它是将这些资源的HTML设置到一个隐藏的textarea控件的值里面，在点击了左右的导航按钮之后，就读出这个textarea的内容并解析到tab中，当然这也同时是加载图片等资源。我想，这样做的一个好处就是上面说的按需加载，加快页面的初始化速度；还有另外一个作用是减少页面初始化的DOM节点数。将这个添加更多DOM节点推迟到按照用户的需要去点击导航按钮。这个在加快页面的初始化方面也是很不错的技巧。 再来分析一下Yahoo首页的其中一个模块的实现方式，也是比较类似的： 如上图，在下部的导航中，初始化的时候会默认加载一个tab看到的导航的图片和问题，而其他隐藏的每一个导航tab，在页面初始化的时候HTML的结构均使用四个span标签代替，之后在点击左右导航按钮的时候，进行异步请求资源，并替换掉每一个相应的span标签。它在初始化页面的时候使用span标签，只是为了保持一个高度上的“空架子”，在之后的按需请求中往这个架子中替换内容，这样其中的一个原因可能是为了不至于在替换标签的时候在高度上的过度出现闪烁。 按需加载的思维在很多网站中都有体现，利用Ajax技术，异步请求内容，将隐藏的内容、资源的加载跟页面的初始化剥离开来，加快页面的初始化。]]></description>
			<content:encoded><![CDATA[<p>
Fetch resources on-demand，中文意思大概就是按需加载资源，而这里的资源不只是CSS、JS文件，Image、swf、Content等都可以利用这种方式。特别是当前Yahoo的首页：<a  href="http://www.yahoo.com">http://www.yahoo.com</a>，几乎页面的每一个模块都体现了按需加载的技巧：左边的导航（用户可以定制、点击异步请求更多资源）、中间的新闻、图片tab、右栏的第三方资源等等。
</p>
<p>
按需加载表面理解起来很简单，但是怎么个按需法呢？我所理解的按需，包括两个方面：一个是按用户的需要；另一个是网站本身的需要。按需加载主要解决的问题就是加快页面的初始化以及在页面初始化的时候最大化减少HTTP请求，因为有些模块比如：图片导航tab、多级菜单、内容导航等等，这些在初始化页面的时候有很多内容都是处于隐藏状态，用户是看不到的，那么这些内容对不同的用户来说有不同的需求，那么这些就可以从页面的初始化中剥离出来，按用户的需求通过异步通信来加载内容和资源。对于网站本身的需要来加载后续资源，比如Google首页对于结果页的一些js、image等资源的pre-fetch的方式，通过分析用户可能会产生的行为，为后续的页面提前加载内容，加快后续页面的初始化速度，从缓存中读取页面所需要的资源。
</p>
<p><span id="more-1258"></span></p>
<p>
接下来分析一下淘宝首页（<a  href="http://www.taobao.com">http://www.taobao.com</a>）的一些按需加载的技巧。首先对于中间栏的这个部分的实现：
</p>
<p>
<img src="http://www.ilovejs.net/wp-content/uploads/2010/10/taobao.jpg" alt="" title="taobao" width="478" height="143" class="alignnone size-full wp-image-1259" />
</p>
<p>
看这个模块的源码之后发现，除了初始化第一个tab内容之后，后面隐藏的几个tab的资源是没有加载的，它是将这些资源的HTML设置到一个隐藏的textarea控件的值里面，在点击了左右的导航按钮之后，就读出这个textarea的内容并解析到tab中，当然这也同时是加载图片等资源。我想，这样做的一个好处就是上面说的按需加载，加快页面的初始化速度；还有另外一个作用是减少页面初始化的DOM节点数。将这个添加更多DOM节点推迟到按照用户的需要去点击导航按钮。这个在加快页面的初始化方面也是很不错的技巧。
</p>
<p>
再来分析一下Yahoo首页的其中一个模块的实现方式，也是比较类似的：
</p>
<p>
<img src="http://www.ilovejs.net/wp-content/uploads/2010/10/yahoo1.jpg" alt="" title="yahoo" width="403" height="440" class="alignnone size-full wp-image-1261" />
</p>
<p>
如上图，在下部的导航中，初始化的时候会默认加载一个tab看到的导航的图片和问题，而其他隐藏的每一个导航tab，在页面初始化的时候HTML的结构均使用四个span标签代替，之后在点击左右导航按钮的时候，进行异步请求资源，并替换掉每一个相应的span标签。它在初始化页面的时候使用span标签，只是为了保持一个高度上的“空架子”，在之后的按需请求中往这个架子中替换内容，这样其中的一个原因可能是为了不至于在替换标签的时候在高度上的过度出现闪烁。
</p>
<p>
按需加载的思维在很多网站中都有体现，利用Ajax技术，异步请求内容，将隐藏的内容、资源的加载跟页面的初始化剥离开来，加快页面的初始化。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1258/feed</wfw:commentRss>
		<slash:comments>1</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/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>
	</channel>
</rss>

