This page looks plain and unstyled because you're using a non-standard compliant browser. To see it in its best form, please visit upgrade to a browser that supports web standards. It's free and painless.

Fillano's Learning Notes 會員登入 會員註冊

考慮以下網頁程式:

<div id="test14"></div>
<div id="test14-1"></div>
<script>
var c = document.createElement("img");
c.src = "bg/char1.gif";
var d = document.getElementById("test14");
d.style.border = "solid 1px black";
d.style.width = "200px";
d.style.height = "200px";
var e = document.getElementById("test14-1");
e.style.border = "solid 1px black";
e.style.width = "200px";
e.style.height = "200px";
d.appendChild(c);
e.appendChild(c);
alert(d.hasChildNodes());
</script>

alert會顯示false,看起來在e.appendChild時,原來appendChild給d的c就被從d的subnodes中移除了。

其實也沒甚麼,$不是javascript關鍵字,所以可以拿來當作變數名稱。

所以

var $ = eval;
$("alert('it works.')");

效果跟

eval("alert('it works.')");

是一樣的。看到別人這樣用,試了一下,果然可以。:)

自用筆記:

會引發許功蓋問題的big5編碼繁體中文字。

ASCII(5C) == "\"

A45C么 AE5C娉 B85C稞 C25C擺 A55C功
AF5C珮 B95C鈾 C35C黠 A65C吒 B05C豹
BA5C暝 C45C孀 A75C吭 B15C崤 BB5C蓋
C55C髏 A85C沔 B25C淚 BC5C墦 C65C躡
A95C坼 B35C許 BD5C穀 AA5C歿 B45C廄
BE5C閱 AB5C俞 B55C琵 BF5C璞 AC5C枯
B65C跚 C05C餐 AD5C苒 B75C愧 C15C縷

問題的來源,還是在自己不夠熟悉Javascript的prototype base inheritance。有一些想法還是自以為是地來自class base的觀念。結果讓instance共用了constructor的屬性,產生了非預期的結果...

最初是因為要做一個不間斷的跑馬燈,所以為跑馬燈設計了一個訊息物件:

function messages () {
this.msgQueue = new Array;
}

messages.prototype.addMsg = function (strMsg) {
this.msgQueue.push(strMsg);
}

(我有簡化過)

然後透過不同的方法來繼承(因為會有不同的實作):

function dynamicMsg () {
this.status = 0;
......
}
dynamicMsg.prototype = new messages;
//問題從這裡開始發生......

為了在頁面上產生兩個跑馬燈,所以用兩個變數:

var msg1 = new dynamicMsg;
msg1.addMsg("test1");
msg1.addMsg("test2");
var msg2 = new dynamicMsg;
msg2.addMsg("test3");
msg2.addMsg("test4");

結果問題就出現了,原本以為這樣msg1.msgQueue陣列裡面會有兩個元素"test1"跟"test2"而msg2.msgQueue會有兩個元素"test3"跟"test4"。沒想到,結果是msg1.msgQueue跟msg2.msgQueue陣列同樣都有四個元素,就是"test1"、"test2"、"test3"、"test4"!

這下子搞得我天下大亂,怎麼會發生這種事呢?我當然可以把msgQueue屬性跟addMsg方法放到dynamicMsg物件中來避開這個問題,但是我還是希望瞭解一下發生了什麼事情。

先在程式設計師論壇上問了一下,有人建議我參考過去的文章,用function物件的call方法來建構API。我試了一下,果然改一下就可以了,但是需要把原來用prototype的方式改成call的方式。

function dynamicMsg () {
messages.call(this); this.status = 0;
......
}

到底發生了甚麼問題呢?我後來做了一個測試:

function mother () {
this.fname = new Array;
}
mother.prototype.setfname = function (str) {
this.fname.push(str);
}
function son (title) {
this.title = title;
}
son.prototype = new mother;
var son1 = new son("workbee");
son1.setfname("test");
var son2 = new son("manager");
alert(son.prototype.fname);
alert(son1.fname);
alert(son2.fname);

結果,透過三次alert顯示出來的結果都是"test"!看起來,在透過new產生新的物件實體時,並不會改變前面利用prototype來assign給新物件實體的內容,所以son1.fname跟son2.fname同樣參考到了son.prototype.fname。真是殘念阿....

利用prototype來產生inheritance chain的方法是我在Core Javascript Guide裡面學到的,但是我沒有想到prototype base跟class base有甚麼不同,就把他拿來用了。

回頭看了一下ECMA-262,發現mother,son,son1,son2都是物件的identifier,並不是mother、son是宣告,而son1、son2是物件實體。而且son、mother這兩個函數物件也就是consturctor,在產生物件時會呼叫constructor,但是在constructor之外用prototype建立起來的參考不會改變。問題就在這裡發生了。

看起來,要熟悉Javascript,還需要把這些東西搞清楚才行。