來自 Nine Javascript Gotchas , 以下是JavaScript容易犯錯的九個陷阱。雖然不是什么很高深的技術問題,但注意一下,會使您的編程輕松些,即所謂make life easier. 筆者對某些陷阱會混雜一些評點。
1. 最后一個逗號
如這段代碼,注意最后一個逗號,按語言學角度來說應該是不錯的(python的類似數據類型辭典dictionary就允許如此)。IE會報語法錯誤,但語焉不詳,你只能用人眼從幾千行代碼中掃描。
<script>
var theObj = {
city : “Boston”,
state : “MA”,
}
</script>
2. this的引用會改變
如這段代碼:
<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”。在執行MyObject.ClickHandler時,代碼中紅色這行,this的引用實際上指向的是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>
實質上,這就是JavaScript作用域的問題。如果你看過,你會發現解決方案不止一種。
3. 標識盜賊
在JavaScript中不要使用跟HTML的id一樣的變量名。如下代碼:
<input type=”button” id=”TheButton”>
<script>
TheButton = get(“TheButton”);
</script>
IE會報對象未定義的錯誤。我只能說:IE sucks.
4. 字符串只替換第一個匹配
如下代碼:
<script>
var fileName = “This is a title”.replace(” “,”_”);
</script>
而實際上,結果是”This_is a title“. 在JavaScript中,String.replace的第一個參數應該是正則表達式。所以,正確的做法是這樣:
var fileName = “This is a title”.replace(/ /g,”_”);
5. mouseout意味著mousein
事實上,這是由于事件冒泡導致的。IE中有mouseenter和mouseleave,但不是標準的。作者在此建議大家使用庫比如YUI來解決問題。
6. parseInt是基于進制體系的
這個是常識,可是很多人給忽略了parseInt還有第二個參數,用以指明進制。比如,parseInt(“09”),如果你認為答案是9,那就錯了。因為,在此,字符串以0開頭,parseInt以八進制來處理它,在八進制中,09是非法,返回false,布爾值false轉化成數值就是0. 因此,正確的做法是parseInt(“09”, 10).
7. for…in…會遍歷所有的東西
有一段這樣的代碼:
var arr = [5,10,15]
var total = 1;
for ( var x in arr) {
total = total * arr[x];
}
運行得好好的,不是嗎?但是有一天它不干了,給我返回的值變成了NaN, 暈。我只不過引入了一個庫而已啊。原來是這個庫改寫了Array的prototype,這樣,我們的arr平白無過多出了一個屬性(方法),而for…in…會把它給遍歷出來。所以這樣做才是比較安全的:
for ( var x = 0; x < arr.length; x++) {
total = total * arr[x];
}
其實,這也是污染基本類的prototype會帶來危害的一個例證。
8. 事件處理器的陷阱
這其實只會存在使用作為對象屬性的事件處理器才會存在的問題。比如window.onclick = MyOnClickMethod這樣的代碼,這會復寫掉之前的window.onclick事件,還可能導致IE的內容泄露(sucks again)。在IE還沒有支持DOM 2的事件注冊之前,作者建議使用庫來解決問題,比如使用YUI:
YAHOO.util.Event.addListener(window, “click”, MyOnClickMethod);
這應該也屬于常識問題,但新手可能容易犯錯。
9. Focus Pocus
新建一個input文本元素,然后把焦點挪到它上面,按理說,這樣的代碼應該很自然:
var newInput = document.createElement(“input”);
document.body.appendChild(newInput);
newInput.focus();
newInput.select();
但是IE會報錯(sucks again and again)。理由可能是當你執行fouce()的時候,元素尚未可用。因此,我們可以延遲執行:
var newInput = document.createElement(“input”);
newInput.id = “TheNewInput”;
document.body.appendChild(newInput);
setTimeout(function(){ //這里我使用閉包改寫過,若有興趣可以對比原文
document.getElementById(‘TheNewInput’).focus();
document.getElementById(‘TheNewInput’).select();}, 10);
在實踐中,JavaScript的陷阱還有很多很多,大多是由于解析器的實現不到位而引起。這些東西一般都不會在教科書中出現,只能靠開發者之間的經驗分享。謝天謝地,我們生活在網絡時代,很多碰到的問題,一般都可以在Google中找到答案。
]]>常用的網頁特效收集起來做一個“大全”。
1.讓文字不停地滾動
<MARQUEE>滾動文字</MARQUEE>
2.記錄并顯示網頁的最后修改時間
<script language=Javascript>
document.write(“最后更新時間: ” + document.lastModified + “”)
</script>
3.關閉當前窗口
<a href=”/”onClick=”javascript:window.close();return false;”>關閉窗口</a>
4.5秒后關閉當前頁
<script language=”Javascript”>
<!–
setTimeout(‘window.close();’,5000);
–>
</script>
5.2秒后載入指定網頁
<head>
<meta http-equiv=”refresh” content=”2;URL=http://你的網址”>
</head>
6.添加到收藏夾
<script Language=”Javascript”>
function bookmarkit()
{
window.external.addFavorite(‘http://你的網址’,’你的網站名稱’)
}
if (document.all)document.write(‘<a href=”#” onClick=”bookmarkit()”>加入收藏夾</a>’)
</script>
7.讓超鏈接不顯示下劃線
<style type=”text/css”>
<!-
a:link{text-decoration:none}
a:hover{text-decoration:none}
a:visited{text-decoration:none}
->
</style>
8.禁止鼠標右鍵的動作
<script Language = “Javascript”>
function click() { if (event.button==2||event.button==3)
{
alert(‘禁止鼠標右鍵’);
}
document.onmousedown=click // –>
</script>
9.設置該頁為首頁
<body bgcolor=”#FFFFFF” text=”#000000″>
<!– 網址:http://你的網址–>
<a class=”chlnk” style=”cursor:hand” HREF
onClick=”this.style.behavior=’url(#default#homepage)’;
this.setHomePage(‘你的網站名稱);”><font color=”000000″ size=”2″ face=”宋體”>設為首頁</font></a>
</body>
10.節日倒計時
<script Language=”Javascript”>
var timedate= new Date(“December 25,2003”);
var times=”圣誕節”;
var now = new Date();
var date = timedate.getTime() – now.getTime();
var time = Math.floor(date / (1000 * 60 * 60 * 24));
if (time >= 0)
document.write(“現在離”+times+”還有: “+time +”天”)</script>
11.單擊按鈕打印出當前頁
<script Language=”Javascript”>
<!– Begin
if (window.print) {
document.write(‘<form>’
+ ‘<input type=button name=print value=”打印本頁” ‘
+ ‘onClick=”javascript:window.print()”></form>’);
}
// End –>
</script>
12.單擊按鈕‘另存為’當前頁
<input type=”button” name=”Button” value=”保存本頁”
onClick=”document.all.button.ExecWB(4,1)”>
<object id=”button”
width=0
height=0
classid=”CLSID:8856F961-340A-11D0-A96B-00C04FD705A2″>
<embed width=”0″ height=”0″></embed>
</object>
13.顯示系統當前日期
<script 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.不同時間段顯示不同問候語
<script 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=”午休時間哦,朋友一定是不習慣午睡的吧?!”
if (( time >=14) && (time < 18))
text=”下午茶的時間到了,休息一下吧! ”
if ((time >= 18) && (time <= 22))
text=”您又來了,可別和MM聊太久哦!”
if ((time >= 22) && (time < 24))
text=”很晚了哦,注意休息呀!”
document.write(text)
//—>
</script>
15.水中倒影效果
<img 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>
<p><a href=”javascript:openwindow(http://www.mxio.cn)”>進入</a>
17.改變IE地址欄的IE圖標
我們要先做一個16*16的icon(圖標文件),保存為index.ico。把這個圖標文件上傳到根目錄下并在首頁<head></head>之間加上如下代碼:
]]>javascript: 改變和控制顯示的圖片大小(保持比例,同時可限制高寬),
<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(‘換圖片了,不過是動畫GIF,你就慘了,關不掉了’)”>
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>
面向對象編程語言中,對于this關鍵字我們是非常熟悉的。比如C++、C#和Java等都提供了這個關鍵字,雖然在開始學習的時候覺得比較難,但只要理解了,用起來是非常方便和意義確定的。ja;vascript也提供了這個this關鍵字,不過用起來就比經典OO語言中要”混亂”的多了。
下面就來看看,在ja;vascript中各種this的使用方法有什么混亂之處?
1、在HTML元素事件屬性中inline方式使用this關鍵字:
<div onclick=”
// 可以在里面使用this
“>division element</div>
我們一般比較常用對的方法是在此使用:javascirpt: EventHandler(this),這樣的形式。不過這里其實可以寫任何合法的ja;vascript語句,要是高興在此定義個類也可以(不過將會是個內部類)。這里的原理是腳本引擎生成了一個div實例對象的匿名成員方法,而onclick指向這個方法。
2、用DOM方式在事件處理函數中使用this關鍵字:
>
這時的EventHandler()方法中的this關鍵字,指示的對象是IE的window對象。這是因為EventHandler只是一個普通的函數,對于attachEvent后,腳本引擎對它的調用和div對象本身沒有任何的關系。同時你可以再看看EventHandler的caller屬性,它是等于null的。如果我們要在這個方法中獲得div對象引用,應該使用:this.event.srcElement。
3、用DHTML方式在事件處理函數中使用this關鍵字:
>
這里的this關鍵字指示的內容是div元素對象實例,在腳本中使用DHTML方式直接為div.onclick賦值一個EventHandler的方法,等于為div對象實例添加一個成員方法。這種方式和第一種方法的區別是,第一種方法是使用HTML方式,而這里是DHTML方式,后者腳本解析引擎不會再生成匿名方法。
4、類定義中使用this關鍵字:
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模擬內定義中對this的使用,這個和其它的OO語言中的情況非常的相識。但是這里要求成員屬性和方法必須使用this關鍵字來引用,運行上面的程序會被告知myName未定義。
5、為腳本引擎內部對象添加原形方法中的this關鍵字:
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指代的是被添加原形的類的實例,和4中類定義有些相似,沒有什么太特別的地方。
6、結合2&4,說一個比較迷惑的this關鍵字使用:
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();
我就說說結果,頁面運行后會顯示:”division element”,確定后點擊文字”division element”,將會顯示:”undefined”。
7、CSS的expression表達式中使用this關鍵字:
>
division element</div>
</td>
</tr>
</table>
這里的this看作和1中的一樣就可以了,它也使指代div元素對象實例本身。
8、函數中的內部函數中使用this關鍵字:
function OuterFoo()
{
this.Name = ‘Outer Name’;
function InnerFoo()
{
var Name = ‘Inner Name’;
alert(Name + ‘, ‘ + this.Name);
}
return InnerFoo;
}
OuterFoo()();
運行結果顯示是:”Inner Name, Outer Name”
。按我們在2中的講解,這里的結果如果是”Inner Name, undefined”似乎更合理些吧?但是正確的結果確實是前者,這是由于ja;vascript變量作用域的問題決定的,詳細了解推薦參看”原來JScript中的關鍵字’var’還是有文章的“一文及回復。
說了這么多ja;vascript中this的用法,其實this最根本的特性還是和OO語言中的定義相吻合的。之所以有這么多看似混亂的使用方式,是因為ja;vascript語言(解釋器和語言本身的內容)本身在實現上是遵循OO的(Object-based),連它的所有數據類型都是對象,也有Object這樣一個super Object。但是這個語言在運行上(runtime),就沒有遵循完備的OO特點,所以就出現了this的指代混亂。