<?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>简单生活@NET &#187; javascript</title>
	<atom:link href="http://lee.kometo.com/archives/tag/javascript/feed" rel="self" type="application/rss+xml" />
	<link>http://lee.kometo.com</link>
	<description>正确的判断来自经验，但经验往往来自错误的判断</description>
	<lastBuildDate>Mon, 06 Feb 2012 02:26:17 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Javascript中的this详解</title>
		<link>http://lee.kometo.com/archives/483</link>
		<comments>http://lee.kometo.com/archives/483#comments</comments>
		<pubDate>Mon, 14 Dec 2009 09:29:19 +0000</pubDate>
		<dc:creator>Emeric lee</dc:creator>
				<category><![CDATA[WEB应用开发]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://lee.kometo.com/?p=483</guid>
		<description><![CDATA[*本文代码中使用的 function dump(v,title), 是一个自己写的输出变量描述的函数。 如果你准备在JavaScript中写类，那么你必需对关键字 this 的使用有深刻的理解： 这是JavaScript手册中对 this的简单解释： this:指当前对象。 对于 JScript 的客户版本，如果在其他所有对象的上下文之外使用 this，则它指的是 window 对象。 在全局环境下的 this 通常我们认为，Javascript 不在任何函数，不在任何类中，直接书写运行的代码的环境，称为直接运行环境，或者全局环境。实际上这个环境并不是一个真正意义上全局环境, 运行下面的代码： dump(this,&#39;Global This&#39;); 我们可以得到输出结果： ■ Global This: object &#8211; [object Window] [The window Object] 可以看到，在这个环境下，this 等于 浏览器的原生对象 window ,它是原生类 Window 的实例。 事实上，当我们在浏览器中运行JavaScript代码时，windows 是所有代码的根节点，所有的代码都是存储并挂接于这个节点的，当然多窗口的环境下会有多个window对象。 function Car(){ } dump(Car); dump(window.Car); 输出结果： ■ function function Car() {&#160; &#8230; [...]]]></description>
			<content:encoded><![CDATA[<p><em>*本文代码中使用的 function dump(v,title), 是一个自己写的输出变量描述的函数。</em></p>
<p>如果你准备在JavaScript中写类，那么你必需对关键字 this 的使用有深刻的理解：</p>
<p>这是JavaScript手册中对 this的简单解释：</p>
<blockquote>
<p><strong>this</strong>:指当前对象。</p>
<p>对于 JScript 的客户版本，如果在其他所有对象的上下文之外使用 <b>this</b>，则它指的是 <b>window</b> 对象。</p>
</blockquote>
<h3><span id="more-483"></span><strong>在全局环境下的 this<br />
	</strong></h3>
<p>通常我们认为，Javascript 不在任何函数，不在任何类中，直接书写运行的代码的环境，称为直接运行环境，或者全局环境。实际上这个环境并不是一个真正意义上全局环境,</p>
<p>运行下面的代码：</p>
<pre class="brush:jscript">dump(this,&#39;Global This&#39;);</pre>
<p>我们可以得到输出结果：</p>
<div>
<div style="color: blue;">
<blockquote>
<p><strong>■ <span style="color: red;">Global This:</span> object</strong> &#8211; [object Window]</p>
<div style="padding: 2px 3em; color: green;">[The window Object]</div>
</blockquote></div>
</div>
<p>可以看到，在这个环境下，this 等于 浏览器的原生对象 <strong>window </strong>,它是原生类 <strong>Window</strong> 的实例。</p>
<p>事实上，当我们在浏览器中运行JavaScript代码时，windows 是所有代码的根节点，所有的代码都是存储并挂接于这个节点的，当然多窗口的环境下会有多个window对象。</p>
<pre class="brush:jscript">function Car(){

}
dump(Car);
dump(window.Car);</pre>
<p>输出结果：</p>
<blockquote>
<div>
<div style="color: blue;"><strong>■ function</strong> <span style="color: green;">function Car() {&nbsp; &#8230;</span></div>
</p></div>
<div>
<div style="color: blue;"><strong>■ function</strong> <span style="color: green;">function Car() { &#8230;</span></div>
</p></div>
</blockquote>
<p>可以看到 Car 和 window.Car 是完全相同的东西</p>
<h3><strong>在类中使用 this<br />
	</strong></h3>
<p>现在我们来看看当使用类的时候，this会发生什么样的变化。下面是一段典型的类定义代码，我们来逐步分析：</p>
<pre class="brush:jscript">function Car(color,doors){
    //用构造模式定义属性
    this.color = color;
    this.doors = doors;
    this.dispThis = function(){
    	dump(this,&#39;this&#39;);
    };
    dump(this,&#39;this&#39;);
}

//原型方法
Car.prototype.dispThis2 = function(){
	dump(this,&#39;this&#39;);
};

//静态方法
Car.dispThis3 = function(){
	dump(this,&#39;this&#39;);
};

aCar = new Car(&#39;red&#39;,4);
aCar.dispThis();
aCar.dispThis2();
Car.dispThis3();
Car(&#39;red&#39;,4);
</pre>
<p>输出结果：</p>
<p>&nbsp;</p>
<blockquote>
<div>
<div style="color: blue;">
<p><strong>■ <span style="color: red;">this:</span> object</strong> &#8211; [object Object]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //构造函数 new Car()</p>
<div style="padding: 2px 3em; color: green;">
<div>&#8211; <strong>color</strong> <strong>■ string</strong> <span style="color: green;">red</span></div>
<div>&#8211; <strong>doors</strong> <strong>■ number</strong> <span style="color: green;">4</span></div>
<div>&#8211; <strong>dispThis</strong> <strong>■ function</strong> <span style="color: green;">function () { dump(this, &quot;this&quot;); }&#8230;</span></div>
<div>&#8211; <strong>dispThis2</strong> <strong>■ function</strong> <span style="color: green;">function () { dump(this, &quot;this&quot;); }&#8230;</span></div>
</p></div>
</p></div>
</p></div>
<div>
<div style="color: blue;">
<p><strong>■ <span style="color: red;">this:</span> object</strong> &#8211; [object Object]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //构造方法 aCar.dispThis();</p>
<div style="padding: 2px 3em; color: green;">
<div>&#8211; <strong>color</strong> <strong>■ string</strong> <span style="color: green;">red</span></div>
<div>&#8211; <strong>doors</strong> <strong>■ number</strong> <span style="color: green;">4</span></div>
<div>&#8211; <strong>dispThis</strong> <strong>■ function</strong> <span style="color: green;">function () { dump(this, &quot;this&quot;); }&#8230;</span></div>
<div>&#8211; <strong>dispThis2</strong> <strong>■ function</strong> <span style="color: green;">function () { dump(this, &quot;this&quot;); }&#8230;</span></div>
</p></div>
</p></div>
</p></div>
<div>
<div style="color: blue;">
<p><strong>■ <span style="color: red;">this:</span> object</strong> &#8211; [object Object]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //原型方法 aCar.dispThis2()</p>
<div style="padding: 2px 3em; color: green;">
<div>&#8211; <strong>color</strong> <strong>■ string</strong> <span style="color: green;">red</span></div>
<div>&#8211; <strong>doors</strong> <strong>■ number</strong> <span style="color: green;">4</span></div>
<div>&#8211; <strong>dispThis</strong> <strong>■ function</strong> <span style="color: green;">function () { dump(this, &quot;this&quot;); }&#8230;</span></div>
<div>&#8211; <strong>dispThis2</strong> <strong>■ function</strong> <span style="color: green;">function () { dump(this, &quot;this&quot;); }&#8230;</span></div>
</p></div>
</p></div>
</p></div>
<div>
<div style="color: blue;">&nbsp;</div>
<div style="color: blue;"><strong>■ <span style="color: red;">this:</span> function</strong> <span style="color: green;">function Car(color, doors) { this.co&#8230;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(0, 255, 255);">&nbsp;&nbsp;</span></span> //静态方法 Car.dispThis3()</div>
<div style="color: blue;">
<div>
<div style="color: blue;">
<p><strong>■ <span style="color: red;">this:</span> object</strong> &#8211; [object Window]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //直接运行构造函数 Car()</p>
<div style="padding: 2px 3em; color: green;">[The window Object]</div>
</p></div>
</p></div>
</p></div>
</p></div>
</blockquote>
<p>&nbsp;</p>
<p>可以看到在构造函数、构造方法、原型方法中的都可以获取到this对象，它们指向同一个实例对象<strong>aCar</strong>，该对象由 <strong>new Car() </strong>语句生成。</p>
<p>在<strong>Car</strong>的静态方法 <strong>Car.dispThis4</strong>（其实就是Car的一个直接的function属性）中，this 就是<strong>Car</strong> 本身，</p>
<p>当不使用new 关键字，而直接运行类的构造函数<strong>Car</strong>（其实现在它就是一个普通函数）时，在函数内部 this 就是当前运行环境的window对象</p>
<p>注意：比较一下 <strong>aCar.dispThis()</strong> 和 静态方法 <strong>Car.dispThis3()</strong> 输出结果就可以发现：<strong>Car</strong> 和 <strong>Car</strong> 生成的对象是2个完全不同的概念；<strong>Car</strong>是一个函数对象，继承与原生的 <strong>Function</strong> ；而<strong>Car</strong>的实例<strong>aCar</strong>则是一个单纯的对象，它继承与JavaScript原生的 <strong>Object </strong></p>
<p>比较一下：</p>
<p style="text-align: center;">&nbsp;</p>
<p>&nbsp;</p>
<table align="center" border="1" cellpadding="1" cellspacing="1" style="width: 400px;">
<tbody>
<tr>
<td bgcolor="#ff6600">&nbsp;</td>
<td bgcolor="#ff6600" style="text-align: center;">代码</td>
<td bgcolor="#ff6600" style="text-align: center;">结果</td>
</tr>
<tr>
<td>1</td>
<td>aCar.dispThis();</td>
<td>this = aCar</td>
</tr>
<tr>
<td>2</td>
<td>aCar.dispThis2();</td>
<td>this = aCar</td>
</tr>
<tr>
<td>3</td>
<td>Car.dispThis3();</td>
<td>this = Car</td>
</tr>
<tr>
<td>4</td>
<td>new Car();</td>
<td>this = aCar</td>
</tr>
<tr>
<td>5</td>
<td>Car();</td>
<td>this = window</td>
</tr>
</tbody>
</table>
<p>通过这个表格特别是1、2、3行，我们可以清晰的得到一个规律：<strong>this 其实就等于调用代码时的调用的节点</strong>，即：aCar. 和 Car. 。这个调用节点也就是参考文档中所提到的<strong>上下文环境</strong>。</p>
<p>那么如何解释4、5的结果呢？</p>
<p>new Car();使用了一个特殊关键字 new ，这个关键字的作用就是生成一个新的对象，并赋值给 this 。所以 this = aCar</p>
<p>Car();没有通过任何节点调用，实际上通过了默认节点window 来调用，通过上一节我们也可以看出 Car 实际上就是 window.Car 。所以 this = window</p>
<h3><strong>总结和结论：</strong></h3>
<p><u><strong>JavaScript中所有的东西都是对象，包括数字、字符、函数以及对象的属性，函数总是存在（挂接）于某个对象中（默认存在于window对象），并通过某个对象调用的。在函数中总是有一个可用的的 this 变量，脚本引擎对 this 的解析是动态的，运行时的；<u><strong>它指向函数被调用时所挂接的对象。</strong></u></strong></u></p>
<p>我们可以通过一系列函数对象来进一步明晰这个过程，这些函数对象我们有时也称之为类的静态方法，实际上类的静态方法本身也是一个类，也是一个对象，明白了这一点，你就可以深刻理解Javascript的对象机制了。</p>
<pre class="brush:jscript">function Car(){
	this.name = &#39;car&#39;;
	e(this);
};

Car.Wheel = function(){
	this.name = &#39;wheel&#39;;
	e(this);

};

Car.Wheel.Size = function(){
	this.name = &#39;wheel.size&#39;;
	e(this);
}

Car();
Car.Wheel();
Car.Wheel.Size();
</pre>
<p>输出结果</p>
<blockquote>
<div style="color: blue;"><strong>■ object</strong> &#8211; [object Window]</div>
<div style="color: blue;"><strong>■ function</strong> <span style="color: green;">function Car() { this.name = &quot;car&quot;; &#8230;</span></div>
<div style="color: blue;"><strong>■ function</strong> <span style="color: green;">function () { this.name = &quot;wheel&quot;; &#8230;</span></div>
</blockquote>
<p>&nbsp;</p>
<table align="center" border="1" cellpadding="1" cellspacing="1" style="width: 400px;">
<tbody>
<tr>
<td bgcolor="#ff6600">&nbsp;</td>
<td bgcolor="#ff6600" style="text-align: center;">代码</td>
<td bgcolor="#ff6600" style="text-align: center;">结果</td>
</tr>
<tr>
<td>1</td>
<td>Car();</td>
<td>this = window</td>
</tr>
<tr>
<td>2</td>
<td>Car.Wheel();</td>
<td>this = Car</td>
</tr>
<tr>
<td>3</td>
<td>Car.Wheel.Size();</td>
<td>this = Car.Wheel</td>
</tr>
</tbody>
</table>
<h3><strong>当 this 遇到事件</strong></h3>
<p>当我们在事件函数中使用到 this 时，this 有时会很不听话，经常会取值为意料之外的对象。先来看一段示例代码：</p>
<p>我们定义一个类的方法函数 Car.prototype.show();</p>
<pre class="brush:jscript">function Car(){
	this.name = &#39;Class Car&#39;;
}

Car.prototype.show = function(){
	echo(&#39;On Car.show&#39;);
	dump(this,&#39;this&#39;);
};

aCar = new Car;
</pre>
<p>然后使用两个按钮的分别用两种方式触发 aCar.show;</p>
<pre class="brush:jscript">&lt;input id=&quot;btn1&quot; type=&quot;button&quot; value=&quot;Press Me call car.show&quot;/&gt;
&lt;input id=&quot;btn2&quot; type=&quot;button&quot; value=&quot;Press Me call car.show #2&quot;/&gt;

&lt;script type=&#39;text/javascript&#39;&gt;
   document.getElementById(&quot;btn1&quot;).onclick = aCar.show;
  &nbsp;document.getElementById(&quot;btn2&quot;).onclick = function(){aCar.show();}
&lt;/script&gt;
</pre>
<p>&nbsp;</p>
<p>输出结果</p>
<blockquote>
<div>//btn1 click</div>
<div>
<div style="color: blue;">
<p><strong>■ <span style="color: red;">this:</span> object</strong> &#8211; [object HTMLInputElement]</p>
<div style="padding: 2px 3em; color: green;">
<div>&#8211; <strong>tagName</strong> <strong>■ string</strong> <span style="color: green;">INPUT</span></div>
<div>&#8211; <strong>value</strong> <strong>■ string</strong> <span style="color: green;">Press Me call car.show</span></div>
<div>&#8211; <strong>id</strong> <strong>■ string</strong> <span style="color: green;">btn1</span></div>
<div>&#8211; <strong>className </strong> <strong>■ string</strong></div>
<div>&#8230;&#8230;.</div>
</p></div>
</p></div>
</p></div>
<div>//btn2 click</div>
<div>
<div style="color: blue;">
<p><strong>■ <span style="color: red;">this:</span> object</strong> &#8211; [object Object]</p>
<div style="padding: 2px 3em; color: green;">
<div>&#8211; <strong>name</strong> <strong>■ string</strong> <span style="color: green;">Class Car</span></div>
<div>&#8211; <strong>show</strong> <strong>■ function</strong> <span style="color: green;">function () { echo(&quot;On Car.show&quot;); &#8230;</span></div>
</p></div>
</p></div>
</p></div>
</blockquote>
<p>&nbsp;</p>
<p>我们看到<strong>btn1</strong>的<strong>click</strong>事件中 <strong>this </strong>的输出结果是 <strong>Input</strong>元素，</p>
<p><strong>btn2</strong>的<strong>Click</strong>事件中，<strong>this </strong>的输出结果是 <strong>aCar</strong>。</p>
<p>为什么会出现这一结果呢？</p>
<p>造成不同的主要原因是事件的绑定方式的不同，我们来看看事件的绑定过程：</p>
<p><strong>btn1</strong>使用<strong> document.getElementById(&quot;btn1&quot;).onclick = aCar.show&nbsp; </strong>这条语句进行了事件绑定。<br />
	我们把 btn1.click 指向（引用）了 aCar.show，当事件触发时 btn1.click 被调用（回调），也就是调用了 aCar.show&nbsp; 的代码；看起来一切正常，唯一需要注意的是： aCar.show&nbsp; 的内部代码不是以节点名称 aCar 来调用的，而是以节点 btn1 来调用的，也就是说此时 show()&nbsp; 的运行时节点是 btn1，那么 <strong>this </strong>也就成为了 <strong>btn1</strong>。</p>
<p><strong>btn2 </strong>使用&nbsp;<strong>document.getElementById(&quot;btn1&quot;).onclick = function(){aCar.show();} </strong>。<br />
	和btn1唯一的区别就是它使用了一个匿名函数把 aCar.show();包裹起来了。就是这样简单一个包裹引起根本性的变化，当事件触发时 btn1.click 被调用（回调），运行代码并不直接是 aCar.show ，而是通过匿名函数又再次调用 aCar.show ；此时调用的节点是 aCar ,所以 this = aCar 。</p>
<p>有些文章用事件函数的复制和引用来解释btn1和btn2结果的不同，这种解释实际是错误的，流于表象的，虽然很多文章还做了很多图来解释&#8230; JavaScript 的所有赋值语句都应该理解为引用，这又是另外一个话题，不扯远了&#8230;</p>
<p>我们来进一步比较不同事件函数绑定方式所带来的 this 的变化：</p>
<pre style="margin-right: -982px;">function Car(){
	this.name = &#39;Class Car&#39;;
}

Car.prototype.show = function(){
	dump(this,&#39;this&#39;);
};

aCar = new Car;

element.onclick = aCar.show;                       // this = element
element.addEventListener(&#39;click&#39;,aCar.show, false) // this = element

element.onclick = function () {aCar.show();}      // this = aCare
lement.attachEvent(&#39;onclick&#39;,aCar.show)           // this = aCare
&lt;element onclick=&quot;aCar.show();&quot;&gt;                  // this = aCare

element.onclick = function () {this.style.color = &#39;#cc0000&#39;;}     //this = element
&lt;element onclick=&quot;this.style.color = &#39;#cc0000&#39;;&quot;&gt;                 //this = element
</pre>
<p><strong><br />
	</strong></p>
<p><strong>总结：</strong><u><strong><u><strong>this 指向函数被调用时所挂接的对象。</strong></u></strong></u><strong>当事件函数被调用时，this 总是等于事件所在的节点，因此我们应该使用匿名函数作为事件函数，并在匿名函数中二次调用可能需要的其它函数。以此来避免可能的 this 混乱。<br />
	</strong></p>
<p>现在我们来看一段示范代码，这是一段典型的既能获取函数本身所在节点，又能获取触发对象的代码模式</p>
<pre style="margin-right: -982px;">function Car(){
	this.name = &#39;Class Car&#39;;
}

Car.prototype.doSomethin = function(obj){
  dump(this,&#39;this&#39;);  //this = aCar
  dump(obj,&#39;obj&#39;);    //obj = element
};

aCar = new Car();

&lt;element onclick=&quot;aCar.doSomething(this)&quot;&gt;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //方法1
element.onclick = function() {aCar.doSomething(this)}     //方法2
</pre>
<p><strong>在类中进行事件绑定操作<br />
	</strong></p>
<p>当我们在类代码中进行事件绑定操作时，对this的使用会遇到新的困难，我们知道所有的事件函数中 this 都必然等于事件函数所在的对象（即上例中的btn1)，那么我们如何在一个类中书写一段匿名事件函数，并在匿名事件函数中调用当前类的对象呢？</p>
<p>看代码：</p>
<pre style="margin-right: -982px;">&lt;input id=&quot;btn1&quot; type=&quot;button&quot; value=&quot;Press Me call car.show&quot;/&gt;

&lt;script type=&#39;text/javascript&#39;&gt;&lt;!--

function Car(){
	this.name = &#39;Class Car&#39;;
}
Car.prototype.showThis = function(obj){
	dump(this,&#39;this&#39;);
	dump(obj,&#39;obj&#39;);
};
Car.prototype.bind = function(){
	document.getElementById(&quot;btn1&quot;).onclick = function(){ this.showThis(this); };
};

aCar = new Car;
aCar.bind();

--&gt;&lt;/script&gt;
</pre>
<p>如果你看到这里对 this 已经有了深刻的理解，那么就会发现这段代码实际使用的话会出错的，问题就出在这一行代码：</p>
<p style="margin-left: 40px;"><strong>document.getElementById(&quot;btn1&quot;).onclick = function(){this.showThis(this);};<br />
	</strong></p>
<p>这行代码的本身是在aCar.bind中运行，然后这行代码又写了一个匿名函数：<strong>function(){this.showThis(this);} 。</strong>匿名函数中我们希望调用当前对象 aCar 的方法 showThis ,同时又想把事件触发对象btn1 传递给 showThis。我们用了2个 this ，这里的 this 到底应该等于什么呢？两个 this 都应该等于 btn1 ,因为这个匿名函数将会以节点 btn1.click 来运行的。this.showThis 将会无法调用到我们希望的目标 aCar.showThis ；</p>
<p>那么如何改写这段代码，来正确的调用aCar.showThis 呢？似乎目前只有这个方法，使用一个临时变量来传递 this ：</p>
<p style="margin-left: 40px;"><strong>var </strong><span style="color: rgb(255, 0, 0);">_this</span> = this;</p>
<p style="margin-left: 40px;"><strong><strong>document.getElementById(&quot;btn1&quot;).onclick = function(obj){<span style="color: rgb(255, 0, 0);">_this</span>.showThis(obj);};</strong></strong></p>
<p>其实这样代码看起来有点让人难以理解，如果想更深入的解释这段代码，就需要进一步解释JavaScript的编译和解释运行机制，我对此也没有深入的研究，但是可以推测出的原因是：JavaScript的脚本引擎对变量的编译和解释是根据代码书写环境（书写节点）来进行的，而对this 似乎总是根据运行环境（运行节点）来赋值的。</p>
<h3><strong>回调函数和 this 使用的总结</strong></h3>
<p><span style="color: rgb(0, 100, 0);"><strong>关于 this 的使用似乎很让人头晕，特别是当 this 和事件和类混在一起使用的时候，如果你需要一个简单的方法来处理这个，我们可以归纳出几条规则</strong></span></p>
<ol>
<li><span style="color: rgb(0, 100, 0);"><strong>事件处理函数又可以称为回调函数(CallBack Function)，回调函数不仅仅用于界面事件（Click,Moueover等等）的处理，很多异步处理需要大量的回调函数。</strong></span></li>
<li><span style="color: rgb(0, 100, 0);"><strong>总是使用匿名函数作为回调函数，并在匿名函数中再调用其它命名函数，使用 event = function(){ somefunction(); }&nbsp; 的方式，不要使用 event = somefunction 的方式</strong></span></li>
<li><span style="color: rgb(0, 100, 0);"><strong>命名并传递默认参数，同时也可以把回调函数中的 this 传递给其它被调用函数。如：event = function(params){ somefunction(this,params); }</strong></span></li>
<li><span style="color: rgb(0, 100, 0);"><strong>如果在类中书写匿名回调函数，并且需要在函数中调用当前类的当前对象，使用一个临时变量来引用 function(){_this.showThis();};</strong></span></li>
</ol>
<p><strong>最后来看看常见的Jquery的事件绑定方式：</strong></p>
<pre style="margin-right: -982px;">&lt;input id=&quot;btn1&quot; type=&quot;button&quot; value=&quot;Press Me call car.show&quot;/&gt;
&lt;input id=&quot;btn2&quot; type=&quot;button&quot; value=&quot;Press Me call car.show #2&quot;/&gt;

&lt;script type=&#39;text/javascript&#39;&gt;&lt;!--

function Car(){
	this.name = &#39;Class Car&#39;;
}
Car.prototype.show = function(){
	echo(&#39;On Car.show&#39;);
	dump(this,&#39;this&#39;);
};
aCar = new Car;

$(&quot;#btn1&quot;).click(function(){aCar.show()});  //通过匿名函数2次调用 this = aCar
$(&quot;#btn2&quot;).click(aCar.show);                // this = btn2

--&gt;&lt;/script&gt;
</pre>
<p>输出结果</p>
<blockquote>
<div>On Car.show //这个是引用方式 this = aCar</div>
<div>
<div style="color: blue;">
<p><strong>■ <span style="color: red;">this:</span> object</strong> &#8211; [object Object]</p>
<div style="padding: 2px 3em; color: green;">
<div>&#8211; <strong>name</strong> <strong>■ string</strong> <span style="color: green;">Class Car</span></div>
<div>&#8211; <strong>show</strong> <strong>■ function</strong> <span style="color: green;">function () { echo(&quot;On Car.show&quot;); &#8230;</span></div>
</p></div>
</p></div>
</p></div>
<div>On Car.show //这个是复制方式 this = btn2</div>
<div>
<div style="color: blue;">
<p><strong>■ <span style="color: red;">this:</span> object</strong> &#8211; [object HTMLInputElement]&nbsp;</p>
<div style="padding: 2px 3em; color: green;">
<div>&#8211; <strong>tagName</strong> <strong>■ string</strong> <span style="color: green;">INPUT</span></div>
<div>&#8211; <strong>value</strong> <strong>■ string</strong> <span style="color: green;">Press Me call car.show #2</span></div>
<div>&#8211; <strong>id</strong> <strong>■ string</strong> <span style="color: green;">btn2</span></div>
<div>&#8211; <strong>className </strong> <strong>■ string</strong></div>
<div>&#8230;&#8230;.</div>
</p></div>
</p></div>
</p></div>
</blockquote>
]]></content:encoded>
			<wfw:commentRss>http://lee.kometo.com/archives/483/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Javascirpt IE中的HTMLElement</title>
		<link>http://lee.kometo.com/archives/487</link>
		<comments>http://lee.kometo.com/archives/487#comments</comments>
		<pubDate>Mon, 14 Dec 2009 03:08:53 +0000</pubDate>
		<dc:creator>Emeric lee</dc:creator>
				<category><![CDATA[WEB应用开发]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://lee.kometo.com/?p=487</guid>
		<description><![CDATA[在DOM标准中，每个HTML元素都是继承自HTMLElement。这是DOM的继承关系树： 这里的Node,HTMLElement,HTMLAnchorElement其实就是HTML元素对象的类声明，我们可以通过修改这些类的原型来修改所有相关的HTML元素特性。 但是，HTMLElement和Node在IE中是虽然存在的，但是IE屏蔽了它，我们是无法访问到它的。 所有的Node实例有个标准属性 nodeType,有时它可以帮助我们判断一个NODE的属性 &#160; nodeType values chart 列表 Returned integer Node type Constant 1 ELEMENT_NODE 2 ATTRIBUTE_NODE 3 TEXT_NODE 4 CDATA_SECTION_NODE 5 ENTITY_REFERENCE_NODE 6 ENTITY_NODE 7 PROCESSING_INSTRUCTION_NODE 8 COMMENT_NODE 9 DOCUMENT_NODE 10 DOCUMENT_TYPE_NODE 11 DOCUMENT_FRAGMENT_NODE 12` NOTATION_NODE 比如判断一个对象是否为 HTMLElement的实例： Oobj instanceof HTMLElement; //这行代码在IE中会报错的 Oobj .nodeType == Node.ELEMENT_NODE; //这行代码在IE中会报错的 Oobj .nodeType == 1; //Node.ELEMENT_NODE=1 [...]]]></description>
			<content:encoded><![CDATA[<p>在DOM标准中，每个HTML元素都是继承自HTMLElement。这是DOM的继承关系树：</p>
<p style="text-align: center;"><a href="http://lee.kometo.com/wp-content/uploads/2009/12/200981518213488.jpg"><img alt="200981518213488" class="aligncenter size-full wp-image-488" height="293" src="http://lee.kometo.com/wp-content/uploads/2009/12/200981518213488.jpg" title="200981518213488" width="308" /></a></p>
<p><span id="more-487"></span></p>
<p>这里的Node,HTMLElement,HTMLAnchorElement其实就是HTML元素对象的类声明，我们可以通过修改这些类的原型来修改所有相关的HTML元素特性。</p>
<p>但是，HTMLElement和Node在IE中是虽然存在的，但是IE屏蔽了它，我们是无法访问到它的。</p>
<p>所有的Node实例有个标准属性 nodeType,有时它可以帮助我们判断一个NODE的属性</p>
<p>&nbsp;</p>
<h3 jquery1260758960156="2">nodeType values chart 列表</h3>
<table align="center" border="1" cellpadding="2" cellspacing="0" style="width: 200px;" width="100%">
<tbody>
<tr>
<th class="captions" valign="top" width="20%">Returned integer</th>
<th class="captions" width="80%">Node type Constant</th>
</tr>
<tr>
<td height="27" valign="top" width="20%">1</td>
<td height="27" width="80%">ELEMENT_NODE</td>
</tr>
<tr>
<td valign="top" width="20%">2</td>
<td width="80%">ATTRIBUTE_NODE</td>
</tr>
<tr>
<td valign="top" width="20%">3</td>
<td width="80%">TEXT_NODE</td>
</tr>
<tr>
<td valign="top" width="20%">4</td>
<td width="80%">CDATA_SECTION_NODE</td>
</tr>
<tr>
<td valign="top" width="20%">5</td>
<td width="80%">ENTITY_REFERENCE_NODE</td>
</tr>
<tr>
<td valign="top" width="20%">6</td>
<td width="80%">ENTITY_NODE</td>
</tr>
<tr>
<td valign="top" width="20%">7</td>
<td width="80%">PROCESSING_INSTRUCTION_NODE</td>
</tr>
<tr>
<td valign="top" width="20%">8</td>
<td width="80%">COMMENT_NODE</td>
</tr>
<tr>
<td valign="top" width="20%">9</td>
<td width="80%">DOCUMENT_NODE</td>
</tr>
<tr>
<td valign="top" width="20%">10</td>
<td width="80%">DOCUMENT_TYPE_NODE</td>
</tr>
<tr>
<td valign="top" width="20%">11</td>
<td width="80%">DOCUMENT_FRAGMENT_NODE</td>
</tr>
<tr>
<td valign="top" width="20%">12`</td>
<td width="80%">NOTATION_NODE</td>
</tr>
</tbody>
</table>
<p>比如判断一个对象是否为 HTMLElement的实例：</p>
<pre>Oobj instanceof HTMLElement;         //这行代码在IE中会报错的
Oobj .nodeType == Node.ELEMENT_NODE; //这行代码在IE中会报错的
Oobj .nodeType == 1;                 //Node.ELEMENT_NODE=1 在IE中只能直接使用数字

//一段完整判断函数
function isElement(Oobj ){
    return !!(Oobj &amp;&amp; Oobj.nodeType == 1);
} </pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>参考：</p>
<p>DOM对象参考手册 http://www.navioo.com/DOMReference/HTML/reference/api/htmldom2.index.php</p>
<p>这个站关于JavaScript的参考资料很好，很强大 http://www.navioo.com</p>
]]></content:encoded>
			<wfw:commentRss>http://lee.kometo.com/archives/487/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Javascript-类的基本定义方式</title>
		<link>http://lee.kometo.com/archives/439</link>
		<comments>http://lee.kometo.com/archives/439#comments</comments>
		<pubDate>Sat, 12 Dec 2009 11:28:11 +0000</pubDate>
		<dc:creator>Emeric lee</dc:creator>
				<category><![CDATA[WEB应用开发]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://lee.kometo.com/?p=439</guid>
		<description><![CDATA[经典模式 直接生成对象实例，并操作实例 //定义 var aCar = new Object(); aCar.color = &#34;red&#34;; aCar.doors = 4; aCar.showColor = function() {} //调用 aCar.showColor(); 工厂模式 其实就把上面的代码用过函数封装一下 //定义 function createCar(color,doors){ var aCar = new Object(); aCar.color = color; aCar.doors = doors; aCar.showColor = function() {alert(this.color);}; return aCar; } //调用 bCar = createCar(&#39;red&#39;,4); bCar.showColor(); 混合工厂模式 函数名直接用类名，然后用了关键字new，其实这样写仅仅是好看一些，和上面的工厂方法没有本质区别。 //定义 function car(color,doors){ var aCar [...]]]></description>
			<content:encoded><![CDATA[<p><strong>经典模式</strong></p>
<p>直接生成对象实例，并操作实例</p>
<pre class="brush:jscript">//定义
var aCar = new Object();
aCar.color = &quot;red&quot;;
aCar.doors = 4;
aCar.showColor = function() {}
//调用
aCar.showColor();
</pre>
<p><span id="more-439"></span></p>
<p><strong>工厂模式<br />
	</strong></p>
<p>其实就把上面的代码用过函数封装一下</p>
<pre class="brush:jscript">//定义
function createCar(color,doors){
  var aCar = new Object();
  aCar.color = color;
  aCar.doors = doors;
  aCar.showColor = function() {alert(this.color);};
  return aCar;
}
//调用
bCar = createCar(&#39;red&#39;,4);
bCar.showColor();
</pre>
<p><strong>混合工厂模式<br />
	</strong></p>
<p>函数名直接用类名，然后用了关键字new，其实这样写仅仅是好看一些，和上面的工厂方法没有本质区别。</p>
<pre class="brush:jscript">//定义
function car(color,doors){
  var aCar = new Object();
  aCar.color = color;
  aCar.doors = doors;
  aCar.showColor = function() {alert(this.color);};
  return aCar;
}
//调用
bCar = new car(&#39;red&#39;,4);
bCar.showColor();
</pre>
<p><strong>构造模式<br />
	</strong></p>
<pre class="brush:jscript">//定义
function car(color,doors){
  this.color = color;
  this.doors = doors;
  this.showColor = function() {alert(this.color);};
}
//调用
bCar = new car(&#39;red&#39;,4);
bCar.showColor();
</pre>
<p>&nbsp;</p>
<p>和上面相比，少了2句：<span style="color: rgb(0, 128, 0);"><strong>var aCar = new Object() </strong></span>和 <strong><span style="color: rgb(0, 128, 0);">return aCar </span></strong>。实际上关键字 <strong><span style="color: rgb(0, 128, 0);">new </span></strong>默认执行了一个操作：<strong><span style="color: rgb(0, 128, 0);">this = new Object() </span></strong>，而this会作为构造函数的默认返回值。</p>
<p>&nbsp;</p>
<p><strong>原型模式<br />
	</strong></p>
<pre class="brush:jscript">//定义
function car(){}
car.prototype.color = &#39;red&#39;;
car.prototype.doors = 4;
car.prototype.showColor = function() {alert(this.color);};

//调用
bCar = new car();
bCar.showColor();
</pre>
<p>&nbsp;</p>
<p><strong>动态原型模式<br />
	</strong></p>
<p>定义并判断类的静态属性_<strong>initialized</strong>，在构造函数内部动态定义修改类原型。</p>
<p>&nbsp;</p>
<pre class="brush:jscript">/定义
function car(color,doors) {
    this.color = color;
    this.doors = doors;
    if (typeof car._initialized == &quot;undefined&quot;) {
        car.prototype.showColor = function() {
            alert(this.color);
        };
    }
    car._initialized = true;
}
//调用
aCar = new car(&#39;red&#39;,4);
aCar.showColor();
</pre>
<p><strong>总结：</strong></p>
<p>这些是JavaScript类定义的几种基本模式，实际每种模式下定义出的属性和类都是有区别的，经典模式和工厂模式因为不符合OOP的语法习惯，基本没有人用了。我们通常使用构造模式和原型模式的混合定义类</p>
<p><strong>目前最流行的也是最实用的类定义结构如下：<br />
	</strong></p>
<pre class="brush:jscript">//用构造模式定义类的构造器和属性
function car(color,doors){
	//用构造模式定义属性
	this.color = color;
	this.doors = doors;
}

//用原型模式定义方法
car.prototype.showColor = function(){
	alert(this.color);
};

//这是静态属性
car.type = &#39;vehicle&#39;;

aCar = new car(&#39;red&#39;,4);
aCar.showColor();
</pre>
<p>1.使用构造模式定义类的构造函数和非函数属性</p>
<p>2.使用原型模式定义类的函数属性（方法）</p>
<p>3.可以通过ClassName.name的方式定义静态属性</p>
<p>4.函数（方法）在本质上也是一种属性，有关各种属性定义方式的区别可以参看后面的参考章节。</p>
<p>参看章节：</p>
<blockquote>
<p>http://blog.csdn.net/avon520/archive/2009/01/17/3819751.aspx</p>
<p><a class="title" href="http://lee.kometo.com/archives/469" rel="bookmark">Javascript类- 几种属性的定义方式及区别</a></p>
<p><a class="title" href="http://lee.kometo.com/archives/471" rel="bookmark">Javascript类-构造方法和原型方法的区别</a></p>
</blockquote>
<p><span style="color: rgb(255, 0, 0);">&nbsp;<br />
	</span></p>
]]></content:encoded>
			<wfw:commentRss>http://lee.kometo.com/archives/439/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Javascript类-构造方法和原型方法的区别</title>
		<link>http://lee.kometo.com/archives/471</link>
		<comments>http://lee.kometo.com/archives/471#comments</comments>
		<pubDate>Sat, 12 Dec 2009 11:23:20 +0000</pubDate>
		<dc:creator>Emeric lee</dc:creator>
				<category><![CDATA[WEB应用开发]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://lee.kometo.com/?p=471</guid>
		<description><![CDATA[对Javascript来说，方法在本质上也是一种属性。 构 造方法 和构造属性一样，它是分别存储于每个实例之中的，相互之间是完全独立。 原型方法 和原型属性一样，他是存储于原型中的，每个实例中存储的实际上一 个指向原型的指针。 所有对原型方法的修改会影响到所有实例，而构造方法实际上只能通过实例来访问和修改，也只会影响到相应的实例。 先写结论：方法通常应该使用原型模式定义，并且在必要时通过原型来动态重定义，避免使用构造模式定义方法。 看看示例代码吧： 我们首先构造一个简单的类car,定义2个方法，分别是构造方式定义的constructFunction 和 原型方式定义的 prototypeFunction function echo(str){document.write(&#39;&#60;div&#62;&#39;+str+&#39;&#60;div&#62;&#39;);} function car(){ this.constructFunction = function(){ echo(&#39;This is constructFunction&#39;); }; } car.prototype.prototypeFunction = function(){ echo(&#39;This is prototypeFunction&#39;); }; aCar = new car(); bCar = new car(); aCar.constructFunction(); aCar.prototypeFunction(); bCar.constructFunction(); bCar.prototypeFunction(); 输出结果： This is constructFunction This is prototypeFunction This is constructFunction [...]]]></description>
			<content:encoded><![CDATA[<p><strong>对Javascript来说，方法在本质上也是一种属性。</strong></p>
<p><strong>构 造方法</strong> 和构造属性一样，它是分别存储于每个实例之中的，相互之间是完全独立。</p>
<p><strong>原型方法</strong> 和原型属性一样，他是存储于原型中的，每个实例中存储的实际上一 个指向原型的指针。</p>
<p>所有对原型方法的修改会影响到所有实例，而构造方法实际上只能通过实例来访问和修改，也只会影响到相应的实例。</p>
<p><strong>先写结论：方法通常应该使用原型模式定义，并且在必要时通过原型来动态重定义，避免使用构造模式定义方法。</strong></p>
<p><span id="more-471"></span></p>
<p><strong>看看示例代码吧：</strong> <strong> </strong> 我们首先构造一个简单的类car,定义2个方法，分别是构造方式定义的constructFunction 和 原型方式定义的 prototypeFunction</p>
<pre class="brush:jscript">function echo(str){document.write(&#39;&lt;div&gt;&#39;+str+&#39;&lt;div&gt;&#39;);}

function car(){
   this.constructFunction = function(){
       echo(&#39;This is constructFunction&#39;);
   };
}

car.prototype.prototypeFunction = function(){
    echo(&#39;This is prototypeFunction&#39;);
};

aCar = new car();
bCar = new car();

aCar.constructFunction();
aCar.prototypeFunction();
bCar.constructFunction();
bCar.prototypeFunction();
</pre>
<p>输出结果：</p>
<blockquote>
<div>This is constructFunction</div>
<div>This is prototypeFunction</div>
<div>This is constructFunction</div>
<div>This is prototypeFunction</div>
</blockquote>
<p><strong>原型方法可以随时动态定义和修改</strong>，修改的方法当然是通过类的原型访问，通过重新定义原型方法可以影响到类的所有实例：</p>
<pre class="brush:jscript" lang="javascript">aCar = new car();
bCar = new car();

car.prototype.prototypeFunction = function(){
	echo(&#39;This a new prototypeFunction&#39;);
};

aCar.prototypeFunction();
bCar.prototypeFunction();</pre>
<div><span style="font-size: small;">输出结果为：</span></div>
<div>
<blockquote>
<div><span style="font-size: small;">This a new prototypeFunction</span></div>
<div><span style="font-size: small;">This a new prototypeFunction</span></div>
</blockquote>
</div>
<p>可以看到，即使在实例已经创建以后，对原型的修改也可以反映到影响到所有实例上来。</p>
<p><strong>构造方法是无法通过原型来访问的，只能通过实例访问，也只能通过实例来重定义。下面代码尝试修改实例：aCar的方法constructFunction</strong></p>
<pre class="brush:jscript" lang="javascript">aCar = new car();
bCar = new car();
cCar = new car();

// car.constructFunction() 尝试通过类或者类的原型访问构造定义的方法是无效的，会报错
// car.prototype..constructFunction() 尝试通过类或者类的原型访问构造定义的方法是无效的，会报错

aCar.constructFunction = function(){
    echo(&#39;This a new constructFunction&#39;);
}

aCar.constructFunction();
bCar.constructFunction();
cCar.constructFunction();</pre>
<p>输出结果：</p>
<blockquote>
<div>
<div>
<div>This a new constructFunction</div>
<div>This is constructFunction</div>
<div>This is constructFunction</div>
</p></div>
</p></div>
</blockquote>
<p>对实例aCar的构造方法和影响到了aCar而没有影响到其它实例</p>
<p><strong>事实上，原型方法也是可以通过实例直接修改的，如果直接修改实例的原型方法会出现什么情况呢？</strong></p>
<p><strong><span style="font-weight: normal;">本 段开头已经指出：&ldquo;每个实例中原形方法存储的实际上一个指向原型的指针&rdquo;，如果你尝试修改实例的原型方法，就改变这个指针，使其指向新定义的方法函数；而 原型中的方法定义并没有受到影响。同时，指针既然转向，那么该实例的这个原型方法也就脱离了原型的定义，而成为一个独立方法。</span></strong> <strong><span style="font-weight: normal;">通过下面的代码可以清晰的明白这种过程：</span></strong></p>
<pre class="brush:jscript" lang="javascript">aCar = new car();
bCar = new car();
cCar = new car();

//修改aCar的原型方法 prototypeFunction
aCar.prototypeFunction = function(){
    echo(&#39;This a new prototypeFunction&#39;);
}
//检查修改结果
aCar.prototypeFunction();
bCar.prototypeFunction();
cCar.prototypeFunction();

//修改原型方法 prototypeFunction&nbsp;，就会发现奥妙之处了
car.prototype.prototypeFunction = function(){
    echo(&#39;This a new prototypeFunction modified by prototype&#39;);
}
//检查修改结果
aCar.prototypeFunction();
bCar.prototypeFunction();
cCar.prototypeFunction();</pre>
<div>输出结果：</div>
<div>
<blockquote>
<div>
<div>//第一段的输出结果</div>
<div>This a new prototypeFunction &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //在修改aCar的原型方法prototypeFunction时，仅aCar受到了影响</div>
<div>This is prototypeFunction</div>
<div>This is prototypeFunction</div>
<div>//第二段的输出结果</div>
<div>//我们重新定义了car的原型方法prototypeFunction，但是aCar没有受到影响，aCar的方法prototypeFunction已经脱离了原型的影响。</div>
<div>This a new prototypeFunction</div>
<div>This a new prototypeFunction modified by prototype</div>
<div>This a new prototypeFunction modified by prototype</div>
</p></div>
</blockquote>
</div>
<p><span style="color: rgb(255, 0, 0);"><strong>注意:直接修改实例的原型方法虽然是可行的,但是会带来代码上的混淆和混乱,要尽可能避免使用这种方式.</strong></span></p>
]]></content:encoded>
			<wfw:commentRss>http://lee.kometo.com/archives/471/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Javascript类- 几种属性的定义方式及区别</title>
		<link>http://lee.kometo.com/archives/469</link>
		<comments>http://lee.kometo.com/archives/469#comments</comments>
		<pubDate>Sat, 12 Dec 2009 11:20:53 +0000</pubDate>
		<dc:creator>Emeric lee</dc:creator>
				<category><![CDATA[WEB应用开发]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://lee.kometo.com/?p=469</guid>
		<description><![CDATA[几种属性： 先看代码，这段代码中出现了类定义中可能使用到5种属性或者变量 function car(param1,param2){ //构造变量 var varProperty = &#39;This is a var Perperty&#39;; //构造属性 this.constructProperty = &#39;This is a construct Property&#39; } //原形属性 car.prototype.prototypeProperty = &#39;This is a prototype property&#39;; //静态属性 car.staticProperty = &#39;This is a static property&#39;; 构造变量 使用VAR声明和定义，它的作用域仅限于构造方法内部，包括在构造器内部定义的所有方法（构造方法）。直接通过变量名访问：varProperty。有些文章也把叫做私有属性，从作用域上看，它是私有的，但它不是属性，类的原型是无法访问它的。 构造参数 就是上述代码中的 param1,param2,它与构造变量有相同的作用域和方法方式 function car(param1,param2){ //构造变量 var varProperty = &#39;This is a var Perperty&#39;; echo(varProperty); [...]]]></description>
			<content:encoded><![CDATA[<h3>几种属性：</h3>
<p>先看代码，这段代码中出现了类定义中可能使用到5种属性或者变量</p>
<pre class="brush:jscript">function car(param1,param2){
    //构造变量
    var varProperty = &#39;This is a var Perperty&#39;;
    //构造属性
    this.constructProperty = &#39;This is a construct Property&#39;
}

//原形属性
car.prototype.prototypeProperty = &#39;This is a prototype property&#39;;

//静态属性
car.staticProperty = &#39;This is a static property&#39;;
</pre>
<h3><span id="more-469"></span></h3>
<p><strong>构造变量</strong> 使用VAR声明和定义，它的作用域仅限于构造方法内部，包括在构造器内部定义的所有方法（构造方法）。直接通过变量名访问：varProperty。有些文章也把叫做私有属性，从作用域上看，它是私有的，但它不是属性，类的原型是无法访问它的。</p>
<p><strong>构造参数</strong> 就是上述代码中的 param1,param2,它与构造变量有相同的作用域和方法方式</p>
<pre class="brush:jscript">function car(param1,param2){
    //构造变量
    var varProperty = &#39;This is a var Perperty&#39;;

    echo(varProperty);
    echo(param1);

    this.someMethod = function(){
        echo(varProperty);
        echo(param1);
     };
}</pre>
<p><strong><br />
	</strong></p>
<p><strong>构造属性</strong> 构造属性在类的构造器中通过this.定义，它是公开的(public)，可以通过类的实例(this.)直接访问和修改它</p>
<p><strong>原型属性</strong> 在类的原型中定义，它也是公开，具有和构造属性相同的作用域，它不仅可以通过实例访问，也可以随时通过原型来访问（(ClassName.propertype.)</p>
<p>它和构造属性是有区别的：<span style="background-color: rgb(255, 255, 0);">原型属性可以通过原型直接访问，它存储于类的原型中的，各个实例是通过指针共享访问它</span><strong>。</strong>具体下面单独分析</p>
<pre class="brush:jscript">function car(){

    //构造属性
    this.constructProperty = &#39;This is a construct Property&#39;

    this.someMethod = function(){
        echo(this.constructProperty); //这样可以
        echo(this.ptototypeProperty); //这一可以
     };
}

//原形属性
car.prototype.prototypeProperty = &#39;This is a prototype property&#39;;

echo(car.constructProperty);  //这样是不能访问构造属性的
echo(car.ptototypeProperty);  //这样是不能访问原型属性的

//必须通过实例来访问
aCar = new car();
echo(aCar.constructProperty);  //这样可以
echo(aCar.ptototypeProperty);  //这样可以

echo(car.prototypeProperty)    //原型属性可以通过原型直接访问
</pre>
<p>&nbsp;</p>
<p><strong>静态属性 </strong>直接通过ClassName.的方式定义，它具有和常规OOP语言中的静态属性类似的特性，但注意，它只能通过ClassName访问，不能通过实例访问，在类的中也不能通过this访问</p>
<pre class="brush:jscript">function car(param1,param2){
    echo(this.staticProperty);//这样是不能访问到静态属性的。
    echo(car.staticProperty);//这样可以访问到静态属性的。
}

//静态属性
car.staticProperty = &#39;This is a static property&#39;;

aCar = new car();
echo(aCar.staticPerperty); //这样是不能访问到静态属性的。
echo(car.staticProperty); //这样可以访问到静态属性的。</pre>
<h3>构造属性和原型属性的区别：</h3>
<p>上面已经说了构造属性和原型属性的定义方式，和访问方法，它们的主要区别在于：<span style="background-color: rgb(255, 255, 0);">原型属性可以通过原型直接访问，它存储于类的原型中的，各个实例是通过指针共享访问它</span><strong>。也就是说对于每个构造属性，每个实例都有一个自己存储副本；而对于每个原形属性，每个实例实际上是共享同一个存储副本，实例中存储的仅仅是一个指向原型属性的指针。</strong></p>
<p><strong>看代码吧：</strong></p>
<pre class="brush:jscript">function car(){
    //构造属性
    this.constructProperty = new Array (&#39;tom&#39;,&#39;jerry&#39;);
}

//原形属性
car.prototype.prototypeProperty = new Array (&#39;tom&#39;,&#39;jerry&#39;);

aCar = new car();
bCar = new car();
cCar = new car();

//修改aCar的构造属性
aCar.constructProperty.push(&#39;Emeric&#39;);
echo(aCar.constructProperty);
echo(bCar.constructProperty);
echo(bCar.constructProperty);

//修改aCar的原型属性
aCar.prototypeProperty.push(&#39;Emeric&#39;);
echo(aCar.prototypeProperty);
echo(bCar.prototypeProperty);
echo(bCar.prototypeProperty);
</pre>
<p>输出结果：</p>
<blockquote>
<div>//改变aCar的构造属性，仅仅影响到的aCar单一实例</div>
<div>tom,jerry,Emeric</div>
<div>tom,jerry</div>
<div>tom,jerry</div>
<div>//改变aCar的原型属性，影响到了所有实例</div>
<div>tom,jerry,Emeric</div>
<div>tom,jerry,Emeric</div>
<div>tom,jerry,Emeric</div>
</blockquote>
<p>这里我们为什么在示例代码中使用数组，而没有使用其它简单变量呢？来看另一段代码：这段代码的和上面的唯一区别是使用了字符串作为属性，</p>
<pre class="brush:jscript">function car(){
    //构造属性
    this.constructProperty = &#39;This is a construct Property&#39;
}

//原形属性
car.prototype.prototypeProperty = &#39;This is a prototype property&#39;;

aCar = new car();
bCar = new car();
cCar = new car();

aCar.constructProperty = &#39;New string&#39;;
echo(aCar.constructProperty);
echo(bCar.constructProperty);
echo(bCar.constructProperty);

aCar.prototypeProperty = &#39;New string&#39;;
echo(aCar.prototypeProperty);
echo(bCar.prototypeProperty);
echo(bCar.prototypeProperty);
</pre>
<p>输出结果如下，对aCar的两种属性的修改都没有影响到其它实例，正如上面所说，javascript在实例中使用指针来指向原型属性，当使用<span style="color: rgb(0, 100, 0);"> <strong>aCar.prototypeProperty = &#39;New string&#39;</strong> </span>进行直接赋值时，javascript进行的操作是修改实例的指针（<span style="color: rgb(0, 100, 0);"><strong>aCar.prototypeProperty ）</strong></span>，使其指向新的存储副本<span style="color: rgb(0, 100, 0);"><strong> &#39;New string&#39;</strong> </span>，这一过程往往会掩盖了原型属性的共享特性。</p>
<p>&nbsp;</p>
<blockquote>
<div>New string</div>
<div>This is a construct Property</div>
<div>This is a construct Property</div>
<div>New string</div>
<div>This is a prototype property</div>
<div>This is a prototype property</div>
</blockquote>
<p>再看一段补充代码，这是接着上面的代码运行的，我们通过原型来直接修改了原型属性：</p>
<pre class="brush:jscript">car.prototype.prototypeProperty = &#39;Another New String!&#39;;
echo(aCar.prototypeProperty);
echo(bCar.prototypeProperty);
echo(bCar.prototypeProperty);
</pre>
<p>输出结果如下，会发现，这一修改仅仅影响到了bCar和cCar。</p>
<p>原因其实就是因为上面<span style="color: rgb(0, 100, 0);"> <strong>aCar.prototypeProperty = &#39;New string&#39;</strong> </span> 的，它改变了<span style="color: rgb(0, 100, 0);"> <strong>aCar.prototypeProperty </strong></span>的指向，而不再指向 原型，因而他也就脱离了原型的控制。</p>
<blockquote>
<div>New string</div>
<div>Another New String!</div>
<div>Another New String!</div>
</blockquote>
<p>由于原型属性的共享特性和可能发生的实例指针脱离原型的现象，<strong><span style="color: rgb(255, 0, 0);">我们应该仅仅对需要共享的属性使用原型定义，一般的属性应该尽量使用构造来定义；</span></strong><strong><span style="color: rgb(255, 0, 0);">在修改原型属性时应该尽可能通过原型(car.prototype.)来访问修改，而不要通过实例(aCar.)来修改；。</span></strong>以此来避免可能发生的属性混乱问题。</p>
]]></content:encoded>
			<wfw:commentRss>http://lee.kometo.com/archives/469/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

