跳過導覽列

O3noBLOG

A Happy(?)Designer ~~

SCRIPT

貳月 12

jQuery() in 1.4

jQuery 1.4有個改變應該很少有人注意到,我也是最近剛好有需求才發現,就是直接執行 jQuery 不傳任何參數:

jQuery();

結果會傳回一個空的 jQuery set,不過這在 1.4 以前的版本會傳回document,這樣的修改我覺得是比較好的,因為以前完全沒辦法產生空的 jQuery set,如果要自己做 jQuery set 會比較方便,除了把要的 DOM 節點抓好放陣列丟給 jQuery 外還多了個建立空的 jQuery set 後一個一個把要的節點丟進去的方法,另一個優點是這樣確保 jQuery function 傳回來的物件是同樣的類型。

壹月 25

JavaScript 的一些效率問題

前幾天在測試each和 for 迴圈的效率時,意外的一直得到 each 效率比較好的奇怪現象,搞了兩天才找到原因。

each 這種方法效率會比 for 迴圈還要低主要是因為它是把要做的事情用 function 傳進去,多了一個 function call 和一層 function scope,要對變數作存取時會多了到不同層 scope 尋找的差,所以理論上它會比 for 迴圈還要慢。除此之外,DOM 本身就很慢了,當然DOM NodeList的操作和存取也不會快到哪去,所以像Sizzle引擎就會把 DOM NodeList 轉成陣列再傳回來,而我測試 each 和 for 兩者的效率時,也就是這個部分產生了非預想的結果,根據測試結果 Google V8 和 Firefox 3.6 的 Tracemonkey 這兩個會編譯 JS 的引擎,第二次對同樣內容的 DOM collection 轉陣列的動作時會比第一次還要快,而且大約是兩倍快,測試的基準是第一次用getElementsByTagName抓 <span> ,第二次用 jQuery,內部也是一樣用 getElementsByTagName ,並且小修改過 DOM 結構後再做一樣的事情也是會比第一次還快,並且,不管是用slice還是 for 迴圈一個元素一個元素推到陣列裡面都沒差很多,一開始因為測試都是對同樣的標籤作處理,結果先測的方法就佔了劣勢,就像是美食漫畫一樣,先上菜的都會輸一樣,不過我對編譯器的怎樣做最佳化的方法不熟,所以這兩個引擎是怎麼辦到的就不清楚了。

除了這點之外,還有一些不算小發現的小發現,第一個就是 Firefox 3.6 還是好慢,詳細數據我忘了,不過和 V8、Safari 比起來差距還是不小,然後就是 IE 超.級.慢!!第二是 each 真的比較慢,不過在現在 JS 引擎普遍暴力的情況下差距其實不明顯(不過 NodeList 和陣列的差距還是有)。第三是前面已經講過的 Sizzle 回傳的是陣列而不是 NodeList ,雖然實際上想要自己組合 NodeList 似乎也是不可能的。最後是 jQeury 可以用$("span")[0]這種寫法來直接存取 DOM 節點,不過它並不是陣列,要轉成純陣列可以用$("span").get(),只是測試過後發現沒有比較快,因為還要重新轉一次陣列,這裡損失的時間也不會比直接存取來的少。

拾貳 29

var foo = foo || {};

foo = foo || {};

這樣的寫法大家一定不陌生,如果 ab 有值的話就繼續用,不然就讓他成為空物件。通常會用到的地方有兩種,函式設定參數預設值,或是跨檔案的公用函式庫,這種時候會把變數放在 global scope 下,也就是全域變數,要宣告全域變數的話不用 var,直接變數名稱就可以了,就像上面那段 code,不過實際上,這樣寫是會出錯的,沒寫 var 的話,第二個 foo 會跑出 foo 尚未定義的錯誤,所以寫成標題那樣是比較沒問題的,不過有時候,程式碼會全部包在一個 function scope 裡面,避免安全的問題,但是在這個 scope 裡面用 var 宣告變數的話,變數又不會是全域的,這時其實加上 window 就可以了:

(function () {
foo = window.foo || {};
})();

也可以用 if 判斷:

(function () {
if (! window.foo ) { window.foo = {} }
})();

最後我還發現一件趣事,大家可以猜猜看下面的 code 會不會有錯誤:

(function () {
foo = undefined;
foo = foo || {};
})()
拾貳 21

String and String Object

JavaScript 中,基本的資料型態有數值、字串、布林三種,而這些資料的指派都有兩種方法,一種是直接指派值,另一種是用建構函式,以字串為例:

var sv = "1234567890";
var so = new String("1234567890");

以前我一直以為兩種是等價的,不過在看Efficient JavaScript這篇文章時才發現兩者不是完全相等,在使用字串的 method 如 .charAt() 時,第一種字串值要先轉換成第二字串物件,然後才執行 .charAt() ,當需要大量執行字串的 method 時,用第二個方法來宣告字串變數理論上會比較快,不過我實際測試之後才注意到文章該段最後有說到這是 Opera 才有特別做最佳化的,測試用的code如下:

var s = "1234567890";
//var s = new String("1234567890");

var start = (new Date()).getTime();
for( var j = 0; j < 10000; j++ ) {
  for( var i = 0; i < s.length; i++ ) {
    s.charAt(i);
  }
}
var end = (new Date()).getTime();
alert(end-start);

結果如下:

Opera Firefox IE
"blah" 234 313 344
new String() 156 381 266
unit: micro seconds

可以發現 Opera 用 new String() 時有比較快, IE 雖然也有,不過我在某些電腦上測試結果是和 Firefox 差不多,沒列出來的 safari 其實表現也和 Firefox 差不多,至於 Google Chrome 在編譯的時候有最佳化過,結果都是超快,無法作為參考。所以結論是,還是繼續用普通的方法就好了XD。

拾貳 08

JavaScript 二三事

好久沒寫 blog 了,來記錄一下最近和 JavaScript 有關的消息,首先是新書,High Performance JavaScript,是除了JavaScript Ninja外我最近比較期待的新書,不過兩本都是明年才會出,JavaScript Ninja 是John Resig寫的,目標讀者是開發 JavaScript Framework 的開發者,所以內容相當深,我有先買預覽的電子版,裡面的 code 就常常看到暈頭, High Performance 那本則是 YUI 的開發者之一Zakas Nicholas寫的,之前也寫過不少書,不過我都沒看過就是,目前期待主要是書名的關係。

第二個則是Loading JavaScript as strings這篇文章,提到如果先把 js 程式碼先用字串形式讀進來,再用 eval() 來執行速度反而會比直接邊讀邊執行還要快,這項技巧可以用在 js 量大的 web application,對於之後才要用的 code 就用這種方法讀,讓頁面的生成可以快一點,詳細的內容在 12/8 的O'Reilly Velocity Online Conference會介紹並 demo ,換算成台灣時間好像是週三凌晨一點多開始。

最後一個不是新東西,其實是Google 的文章,裡面有講到會造成 memory leak 的原因,第一種是 IE 的 event function 可能會造成記憶體浪費(其實原因和下面的很像),解法是自己寫一個 event dispatcher ,像是 jQuery 就是這樣,第二種就是把資料附加在 DOM 元件上,例如:

var node = document.getElementById('getMe');
node.myData = 123;

像這樣可以把資料付在 DOM node 物件上,再某些情況下很有用,但是如果這些附加的資料包含其他 DOM node 的話,就會造成 memory leak ,建議的處理方法是完全不用這種特性,至於 jQuery 則是有個data可以用,用法就像是 key, value 的資料型態。

玖月 30

json2.js 和 toJSON()

JSON有認識加上有寫過 JavaScript 來處理 JSON 的人或許都知道json2.js這個Douglas Crockford寫的 JSON 處理器,他可以安全的轉換 JSON 和 JavaScript 的物件,不過我因為資料封裝的問題,希望能自己實作子物件的 toJSON function,本來看了一下 json2.js 的原始碼以為他可以支援,不過實際測試後才發現直接用 json2.js 會造成 toJSON 函式產生的字串會多過一次 quote 的動作,舉例來說 {"a":3} 會被轉成 "{\"a\":3}" ,結果就是造成轉回物件的時候得到錯誤的結果,為了處理這個問題,我寫了一個 function來包 json2.js,用法可以參考test頁的原始碼,不過簡單說,就是把物件丟給他,他會傳回一個 function,執行這個 function 就會得到 JSON 格式字串,當然子物件有 toJSON 的話就會先用它,沒的話才會用 JSON.stringify 。

不過使用上有個小小的安全性問題要注意,我是假設 toJSON 傳回的字串是安全的,當然這樣假設很危險,所以我自己的物件實作 toJSON 時也是把想要傳回的物件先建立起來,然後丟給 JSON.stringify ,如果考慮到自己的子物件也有實作 toJSON 的話,那丟給我寫的 toJSON 也是可以的。

查了一下YUI 的文件,發現原來 JSON2.js 的設計裡,物件自己作 toJSON 的方法是傳新的物件,而不是傳已經轉成 string 的。

玖月 01

TinyMCE Compressor 的 bug

有在 Twitter follow 我的人大概上週五會看到這篇,會發出這樣的叫喊其實要回朔到五個月前,那時無知的我還在快樂的試著玩 TinyMCE Compressor,這東西可以減少 TinyMCE 的 HTTP Request 數,減少 loading 時間、頻寬,還可以讓使用者體驗更好,不過那時的我怎樣弄就是弄不成功,沒有錯誤訊息,但是用 FireBug 之類的開發工具檢查 HTTP Request 就是會看到多餘的那些 Request ,百思不得其解,直到上週五經過更嚴密的交叉比對後,終於茅塞頓開,發現問題的癥結,也跟著從內心喊叫出:「 幹,split 完要 trim 一下啊!! 」這句肺腑之言啊。

狀況是這樣的, TinyMCE 裡面有個地方用來記錄哪些 plugin 已經呼叫過,如果還沒呼叫過,那需要用到時就會建立 Request 來跟 server 要檔案,TinyMCE Compressor 自然也會需要對這個地方作些處理,它會把已經包在檔案內的 plugin 都標註為已經呼叫過的狀態,問題就出在這,我本來用下面的設定:

tinyMCE_GZ.init({
	plugins : 'style, layer, table, save'
});

每個逗點後面都有個空白,我覺得這樣的 coding style 也比較好,結果 TinyMCE Compressor 在做 plugin 呼叫註記的時候,沒把空白去掉(不過 php 端可以正確把 plugin 包進來),接著到了正式初始 TinyMCE 時用一樣的 pluing 設定:

tinyMCE.init({
	plugins : 'style, layer, table, save'
});

這裡卻有把空白去掉,結果它自己認為這些 plugin 沒呼叫過,就重新呼叫了一次...orz,目前是有去回報 bug ,不過不知道會不會受理,總之有要用 TinyMCE 的就小心逗點後面不要加空白吧。

肆月 20

Use DOMContentLoaded ?

onload 越來越少人在用,而改用像是DOMContentLoaded這種事件來代替,像是jQuery也有個ready event可以用,主要是因為 onload 事件還要等待網頁中所有的元素都讀取完畢(或是 timeout),這些元素包括圖片,其他網站的 style, script,flash 物件等,常常訪客開始看網頁內容時,需要執行的 script 卻還沒開始執行,不過並不是所有瀏覽器都有支援 DOMContentLoaded 或是提供其他替代方案,所以各家 js library 為了處理這問題就無所不用其極限。

我是傾向用另外一個方法處理這問題,不過需要一些對網頁內元件的控制能力,其實也很簡單,就是把 script 放在頁面尾端,然後馬上跑,這方法除了可以解決上述問題外,還有另外兩個好處,一是所有瀏覽器都支援,二是可以讓網頁內容先讀進來才跑 script,這也是 YSlow 的建議項目之一,當然如果你就是想那讓那些瀏覽器的使用者看起來感覺不好,就當我沒說吧XD。

貳月 03

Safari 的 re 支援

過年前犯的錯誤,就是用到太新的 Regular Expression:

(?!pattern)

結果 Safari 就出錯了,然後某站新年期間用 Safari 都可能出現錯誤,我還一度以為是 jQuery 1.31 還有 bug,結果看來是我的問題~_~。

拾貳 25

document.lcoation不是string

就如同arguments不是陣列一樣,document.location 也不是字串,其實我多少了解這樣設計的原因,不過用起來還是很不方便,要正常的用各種字串的函式要先強制轉換一下:

var loc = document.location + '';

此類別所有文章


其它資訊

關於本網站

本網站是O3(othree)的個人部落格,主要內容為網路標準、網頁設計,穿插些ACG心得和敗家紀錄,如果需要聯絡我請寄信到

Google Friend Connect

分類彙整

我在看什麼

訂閱本網誌

貼紙

時間がない


認證、授權

XHTML, CSS,WCAG,創用CC 姓名標示