來自 Nine Javascript Gotchas , 以下是JavaScript容易犯錯(cuò)的九個(gè)陷阱。雖然不是什么很高深的技術(shù)問題,但注意一下,會(huì)使您的編程輕松些,即所謂make life easier. 筆者對(duì)某些陷阱會(huì)混雜一些評(píng)點(diǎn)。
1. 最后一個(gè)逗號(hào)
如這段代碼,注意最后一個(gè)逗號(hào),按語言學(xué)角度來說應(yīng)該是不錯(cuò)的(python的類似數(shù)據(jù)類型辭典dictionary就允許如此)。IE會(huì)報(bào)語法錯(cuò)誤,但語焉不詳,你只能用人眼從幾千行代碼中掃描。
<script>
var theObj = {
city : “Boston”,
state : “MA”,
}
</script>
2. this的引用會(huì)改變
如這段代碼:
<input type=”button” value=”Gotcha!” id=”MyButton” >
<script>
var MyObject = function () {
this.alertMessage = “Javascript rules”;
this.ClickHandler = function() {
alert(this.alertMessage );
}
}();
document.getElementById(”theText”).onclick = MyObject.ClickHandler
</script>
并不如你所愿,答案并不是”JavaScript rules”。在執(zhí)行MyObject.ClickHandler時(shí),代碼中紅色這行,this的引用實(shí)際上指向的是document.getElementById(“theText”)的引用??梢赃@么解決:
<input type=”button” value=”Gotcha!” id=”theText” >
<script>
var MyObject = function () {
var self = this;
this.alertMessage = “Javascript rules”;
this.OnClick = function() {
alert(self.value);
}
}();
document.getElementById(”theText”).onclick = MyObject.OnClick
</script>
實(shí)質(zhì)上,這就是JavaScript作用域的問題。如果你看過,你會(huì)發(fā)現(xiàn)解決方案不止一種。
3. 標(biāo)識(shí)盜賊
在JavaScript中不要使用跟HTML的id一樣的變量名。如下代碼:
<input type=”button” id=”TheButton”>
<script>
TheButton = get(“TheButton”);
</script>
IE會(huì)報(bào)對(duì)象未定義的錯(cuò)誤。我只能說:IE sucks.
4. 字符串只替換第一個(gè)匹配
如下代碼:
<script>
var fileName = “This is a title”.replace(” “,”_”);
</script>
而實(shí)際上,結(jié)果是”This_is a title“. 在JavaScript中,String.replace的第一個(gè)參數(shù)應(yīng)該是正則表達(dá)式。所以,正確的做法是這樣:
var fileName = “This is a title”.replace(/ /g,”_”);
5. mouseout意味著mousein
事實(shí)上,這是由于事件冒泡導(dǎo)致的。IE中有mouseenter和mouseleave,但不是標(biāo)準(zhǔn)的。作者在此建議大家使用庫比如YUI來解決問題。
6. parseInt是基于進(jìn)制體系的
這個(gè)是常識(shí),可是很多人給忽略了parseInt還有第二個(gè)參數(shù),用以指明進(jìn)制。比如,parseInt(“09”),如果你認(rèn)為答案是9,那就錯(cuò)了。因?yàn)?,在此,字符串?開頭,parseInt以八進(jìn)制來處理它,在八進(jìn)制中,09是非法,返回false,布爾值false轉(zhuǎn)化成數(shù)值就是0. 因此,正確的做法是parseInt(“09”, 10).
7. for…in…會(huì)遍歷所有的東西
有一段這樣的代碼:
var arr = [5,10,15]
var total = 1;
for ( var x in arr) {
total = total * arr[x];
}
運(yùn)行得好好的,不是嗎?但是有一天它不干了,給我返回的值變成了NaN, 暈。我只不過引入了一個(gè)庫而已啊。原來是這個(gè)庫改寫了Array的prototype,這樣,我們的arr平白無過多出了一個(gè)屬性(方法),而for…in…會(huì)把它給遍歷出來。所以這樣做才是比較安全的:
for ( var x = 0; x < arr.length; x++) {
total = total * arr[x];
}
其實(shí),這也是污染基本類的prototype會(huì)帶來危害的一個(gè)例證。
8. 事件處理器的陷阱
這其實(shí)只會(huì)存在使用作為對(duì)象屬性的事件處理器才會(huì)存在的問題。比如window.onclick = MyOnClickMethod這樣的代碼,這會(huì)復(fù)寫掉之前的window.onclick事件,還可能導(dǎo)致IE的內(nèi)容泄露(sucks again)。在IE還沒有支持DOM 2的事件注冊(cè)之前,作者建議使用庫來解決問題,比如使用YUI:
YAHOO.util.Event.addListener(window, “click”, MyOnClickMethod);
這應(yīng)該也屬于常識(shí)問題,但新手可能容易犯錯(cuò)。
9. Focus Pocus
新建一個(gè)input文本元素,然后把焦點(diǎn)挪到它上面,按理說,這樣的代碼應(yīng)該很自然:
var newInput = document.createElement(“input”);
document.body.appendChild(newInput);
newInput.focus();
newInput.select();
但是IE會(huì)報(bào)錯(cuò)(sucks again and again)。理由可能是當(dāng)你執(zhí)行fouce()的時(shí)候,元素尚未可用。因此,我們可以延遲執(zhí)行:
var newInput = document.createElement(“input”);
newInput.id = “TheNewInput”;
document.body.appendChild(newInput);
setTimeout(function(){ //這里我使用閉包改寫過,若有興趣可以對(duì)比原文
document.getElementById(‘TheNewInput’).focus();
document.getElementById(‘TheNewInput’).select();}, 10);
在實(shí)踐中,JavaScript的陷阱還有很多很多,大多是由于解析器的實(shí)現(xiàn)不到位而引起。這些東西一般都不會(huì)在教科書中出現(xiàn),只能靠開發(fā)者之間的經(jīng)驗(yàn)分享。謝天謝地,我們生活在網(wǎng)絡(luò)時(shí)代,很多碰到的問題,一般都可以在Google中找到答案。
]]>常用的網(wǎng)頁特效收集起來做一個(gè)“大全”。
1.讓文字不停地滾動(dòng)
?。糓ARQUEE>滾動(dòng)文字</MARQUEE>
2.記錄并顯示網(wǎng)頁的最后修改時(shí)間
?。約cript language=Javascript>
document.write(“最后更新時(shí)間: ” + document.lastModified + “”)
</script>
3.關(guān)閉當(dāng)前窗口
?。糰 href=”/”onClick=”javascript:window.close();return false;”>關(guān)閉窗口</a>
4.5秒后關(guān)閉當(dāng)前頁
?。約cript language=”Javascript”>
?。?–
setTimeout(‘window.close();’,5000);
–>
?。?script>
5.2秒后載入指定網(wǎng)頁
<head>
?。糾eta http-equiv=”refresh” content=”2;URL=http://你的網(wǎng)址”>
</head>
6.添加到收藏夾
?。約cript Language=”Javascript”>
function bookmarkit()
{
window.external.addFavorite(‘http://你的網(wǎng)址’,’你的網(wǎng)站名稱’)
}
if (document.all)document.write(‘<a href=”#” onClick=”bookmarkit()”>加入收藏夾</a>’)
</script>
7.讓超鏈接不顯示下劃線
?。約tyle type=”text/css”>
<!-
a:link{text-decoration:none}
a:hover{text-decoration:none}
a:visited{text-decoration:none}
->
</style>
8.禁止鼠標(biāo)右鍵的動(dòng)作
?。約cript Language = “Javascript”>
function click() { if (event.button==2||event.button==3)
{
alert(‘禁止鼠標(biāo)右鍵’);
}
document.onmousedown=click // –>
</script>
9.設(shè)置該頁為首頁
?。糱ody bgcolor=”#FFFFFF” text=”#000000″>
?。?– 網(wǎng)址:http://你的網(wǎng)址–>
?。糰 class=”chlnk” style=”cursor:hand” HREF
onClick=”this.style.behavior=’url(#default#homepage)’;
this.setHomePage(‘你的網(wǎng)站名稱);”><font color=”000000″ size=”2″ face=”宋體”>設(shè)為首頁</font></a>
?。?body>
10.節(jié)日倒計(jì)時(shí)
?。約cript Language=”Javascript”>
var timedate= new Date(“December 25,2003”);
var times=”圣誕節(jié)”;
var now = new Date();
var date = timedate.getTime() – now.getTime();
var time = Math.floor(date / (1000 * 60 * 60 * 24));
if (time >= 0)
document.write(“現(xiàn)在離”+times+”還有: “+time +”天”)</script>
11.單擊按鈕打印出當(dāng)前頁
?。約cript Language=”Javascript”>
?。?– Begin
if (window.print) {
document.write(‘<form>’
+ ‘<input type=button name=print value=”打印本頁” ‘
+ ‘onClick=”javascript:window.print()”></form>’);
}
// End –>
?。?script>
12.單擊按鈕‘另存為’當(dāng)前頁
?。糹nput type=”button” name=”Button” value=”保存本頁”
onClick=”document.all.button.ExecWB(4,1)”>
<o(jì)bject id=”button”
width=0
height=0
classid=”CLSID:8856F961-340A-11D0-A96B-00C04FD705A2″>
?。糴mbed width=”0″ height=”0″></embed>
</object>
13.顯示系統(tǒng)當(dāng)前日期
?。約cript language=Javascript>
today=new Date();
function date(){
this.length=date.arguments.length
for(var i=0;i<this.length;i++)
this[i+1]=date.arguments }
var d=new date(“星期日”,”星期一”,”星期二”,”星期三”,”星期四”,”星期五”,”星期六”);
document.write(
”<font color=##000000 style=’font-size:9pt;font-family: 宋體’> “,
today.getYear(),”年”,today.getMonth()+1,”月”,today.getDate(),”日”,
d[today.getDay()+1],”</font>” );
?。?script>
14.不同時(shí)間段顯示不同問候語
?。約cript Language=”Javascript”>
?。?–
var text=””; day = new Date( ); time = day.getHours( );
if (( time>=0) && (time < 7 ))
text=”夜貓子,要注意身體哦! ”
if (( time >= 7 ) && (time < 12))
text=”今天天氣……哈哈哈,不去玩嗎?”
if (( time >= 12) && (time < 14))
text=”午休時(shí)間哦,朋友一定是不習(xí)慣午睡的吧?!”
if (( time >=14) && (time < 18))
text=”下午茶的時(shí)間到了,休息一下吧! ”
if ((time >= 18) && (time <= 22))
text=”您又來了,可別和MM聊太久哦!”
if ((time >= 22) && (time < 24))
text=”很晚了哦,注意休息呀!”
document.write(text)
//—>
?。?script>
15.水中倒影效果
?。糹mg id=”reflect” src=”你自己的圖片文件名” width=”175″ height=”59″>
<script language=”Javascript”>
function f1()
{
setInterval(“mP.filters.wave.phase+=10”,100);
}
if (document.all)
{
document.write(‘<img id=mP src=”‘+document.all.reflect.src+'”
style=”filter:wave(strength=3,freq=3,phase=0,lightstrength=30) blur() flipv()”>’)
window.onload=f1
}
?。?script>
16.慢慢變大的窗口
<script Language=”Javascript”>
?。?–
var Windowsheight=100
var Windowswidth=100
var numx=5
function openwindow(thelocation){
temploc=thelocation
if
(!(window.resizeTo&&document.all)&&!(window.resizeTo&&document.getElementById))
{
window.open(thelocation)
return
}
windowsize=window.open(“”,””,”scrollbars”)
windowsize.moveTo(0,0)
windowsize.resizeTo(100,100)
tenumxt()
}
function tenumxt(){
if (Windowsheight>=screen.availHeight-3)
numx=0
windowsize.resizeBy(5,numx)
Windowsheight+=5
Windowswidth+=5
if (Windowswidth>=screen.width-5)
{
windowsize.location=temploc
Windowsheight=100
Windowswidth=100
numx=5
return
}
setTimeout(“tenumxt()”,50)
}
//–>
?。?script>
?。紁><a href=”javascript:openwindow(http://www.createwh.com)”>進(jìn)入</a>
17.改變IE地址欄的IE圖標(biāo)
我們要先做一個(gè)16*16的icon(圖標(biāo)文件),保存為index.ico。把這個(gè)圖標(biāo)文件上傳到根目錄下并在首頁<head></head>之間加上如下代碼:
]]>javascript: 改變和控制顯示的圖片大?。ū3直壤瑫r(shí)可限制高寬),
<IMG src=”images/forumnew.gif” style=”border:1px #ff0000 solid” name=ntimg onResize=”javascript: for(i=0;i<123 && (this.width>100||this.height>100);i++){ this.width-= this.width/10 } /*alert(this.width)*/” _onLoad=”alert(‘換圖片了,不過是動(dòng)畫GIF,你就慘了,關(guān)不掉了’)”>
onResize顯示改變后的圖片大小,原來是34
<a href=# onClick=”document.all.ntimg.width +=100 “>xxxx加大xxxx</a>
<a href=# onClick=”document.all.ntimg.src = ‘images/input.gif’ “>yyyyyy換圖yyyyyy</a>
<a href=# onClick=”alert( document.all.ntimg.width + ‘ & ‘ + document.all.ntimg.height ) “>yyyyyyy圖大小yyyyyy</a>
面向?qū)ο缶幊陶Z言中,對(duì)于this關(guān)鍵字我們是非常熟悉的。比如C++、C#和Java等都提供了這個(gè)關(guān)鍵字,雖然在開始學(xué)習(xí)的時(shí)候覺得比較難,但只要理解了,用起來是非常方便和意義確定的。ja;vascript也提供了這個(gè)this關(guān)鍵字,不過用起來就比經(jīng)典OO語言中要”混亂”的多了。
下面就來看看,在ja;vascript中各種this的使用方法有什么混亂之處?
1、在HTML元素事件屬性中inline方式使用this關(guān)鍵字:
<div onclick=”
// 可以在里面使用this
“>division element</div>
我們一般比較常用對(duì)的方法是在此使用:javascirpt: EventHandler(this),這樣的形式。不過這里其實(shí)可以寫任何合法的ja;vascript語句,要是高興在此定義個(gè)類也可以(不過將會(huì)是個(gè)內(nèi)部類)。這里的原理是腳本引擎生成了一個(gè)div實(shí)例對(duì)象的匿名成員方法,而onclick指向這個(gè)方法。
2、用DOM方式在事件處理函數(shù)中使用this關(guān)鍵字:
>
這時(shí)的EventHandler()方法中的this關(guān)鍵字,指示的對(duì)象是IE的window對(duì)象。這是因?yàn)镋ventHandler只是一個(gè)普通的函數(shù),對(duì)于attachEvent后,腳本引擎對(duì)它的調(diào)用和div對(duì)象本身沒有任何的關(guān)系。同時(shí)你可以再看看EventHandler的caller屬性,它是等于null的。如果我們要在這個(gè)方法中獲得div對(duì)象引用,應(yīng)該使用:this.event.srcElement。
3、用DHTML方式在事件處理函數(shù)中使用this關(guān)鍵字:
>
這里的this關(guān)鍵字指示的內(nèi)容是div元素對(duì)象實(shí)例,在腳本中使用DHTML方式直接為div.onclick賦值一個(gè)EventHandler的方法,等于為div對(duì)象實(shí)例添加一個(gè)成員方法。這種方式和第一種方法的區(qū)別是,第一種方法是使用HTML方式,而這里是DHTML方式,后者腳本解析引擎不會(huì)再生成匿名方法。
4、類定義中使用this關(guān)鍵字:
function JSClass()
{
var myName = ‘jsclass’;
this.m_Name = ‘JSClass’;
}
JSClass.prototype.ToString = function()
{
alert(myName + ‘, ‘ + this.m_Name);
};
var jc = new JSClass();
jc.ToString();
這是ja;vascript模擬內(nèi)定義中對(duì)this的使用,這個(gè)和其它的OO語言中的情況非常的相識(shí)。但是這里要求成員屬性和方法必須使用this關(guān)鍵字來引用,運(yùn)行上面的程序會(huì)被告知myName未定義。
5、為腳本引擎內(nèi)部對(duì)象添加原形方法中的this關(guān)鍵字:
Function.prototype.GetName = function()
{
var fnName = this.toString();
fnName = fnName.substr(0, fnName.indexOf(‘(‘));
fnName = fnName.replace(/^function/, ”);
return fnName.replace(/(^\s+)|(\s+$)/g, ”);
}
function foo(){}
alert(foo.GetName());
這里的this指代的是被添加原形的類的實(shí)例,和4中類定義有些相似,沒有什么太特別的地方。
6、結(jié)合2&4,說一個(gè)比較迷惑的this關(guān)鍵字使用:
function JSClass()
{
this.m_Text = ‘division element’;
this.m_Element = document.createElement(‘DIV’);
this.m_Element.innerHTML = this.m_Text;
this.m_Element.attachEvent(‘onclick’, this.ToString);
}
JSClass.prototype.Render = function()
{
document.body.appendChild(this.m_Element);
} 
JSClass.prototype.ToString = function()
{
alert(this.m_Text);
};
var jc = new JSClass();
jc.Render();
jc.ToString();
我就說說結(jié)果,頁面運(yùn)行后會(huì)顯示:”division element”,確定后點(diǎn)擊文字”division element”,將會(huì)顯示:”undefined”。
7、CSS的expression表達(dá)式中使用this關(guān)鍵字:
>
division element</div>
</td>
</tr>
</table>
這里的this看作和1中的一樣就可以了,它也使指代div元素對(duì)象實(shí)例本身。
8、函數(shù)中的內(nèi)部函數(shù)中使用this關(guān)鍵字:
function OuterFoo()
{
this.Name = ‘Outer Name’;
function InnerFoo()
{
var Name = ‘Inner Name’;
alert(Name + ‘, ‘ + this.Name);
}
return InnerFoo;
}
OuterFoo()();
運(yùn)行結(jié)果顯示是:”Inner Name, Outer Name”
。按我們?cè)?中的講解,這里的結(jié)果如果是”Inner Name, undefined”似乎更合理些吧?但是正確的結(jié)果確實(shí)是前者,這是由于ja;vascript變量作用域的問題決定的,詳細(xì)了解推薦參看”原來JScript中的關(guān)鍵字’var’還是有文章的“一文及回復(fù)。
說了這么多ja;vascript中this的用法,其實(shí)this最根本的特性還是和OO語言中的定義相吻合的。之所以有這么多看似混亂的使用方式,是因?yàn)閖a;vascript語言(解釋器和語言本身的內(nèi)容)本身在實(shí)現(xiàn)上是遵循OO的(Object-based),連它的所有數(shù)據(jù)類型都是對(duì)象,也有Object這樣一個(gè)super Object。但是這個(gè)語言在運(yùn)行上(runtime),就沒有遵循完備的OO特點(diǎn),所以就出現(xiàn)了this的指代混亂。