Posts Tagged ‘Javascript’

有需要瀏覽器與網頁的審核組織嗎!??

Friday, October 8th, 2010


這張圖是在網路上搜尋找到的,如果把”網路世界”畫成一個真實的街道圖,也許真的就是長這樣吧… 挺有趣的~ 注意到最大的那棟Google建築附近一直在施工… XD

最近在看JavaScript的書時想到,如果有一個像審核iPhone App的組織,來審核要發行的Browser和網頁的話,這是一件好事嗎?

好處是以後所有要發行的Browser都要強制follow一樣的規則才可發行,不會再跑出像IE 6, 7那樣不標準的瀏覽器。不過在現在自由軟體當道的網路世界裡,似乎不太可行。或者可以改成比較軟性的作法,通過認證的Browser給予一個認證標章logo,並定期公佈新Browser或其新版本的資訊及測試結果供使用者比較和下載。灌輸使用者最好用這些認證過的Browser來瀏覽網頁,才能得到比較好的體驗。這樣一來,時間久了,使用者就會慢慢養成習慣選擇比較好的Browser軟體(就像選防毒軟體一樣),Browser開發商就不得不follow規則了。

如此一來,網頁開發者在寫頁面時就不用再做一大堆client / feature的判斷,程式碼也會比較乾淨好維護。而大型網站也可以將Web App服務送審,取得認證標章,讓使用者在使用該服務時獲得更安全的保障和更好的體驗。而一般的小網站或個人網頁當然也可以不透過認證,使用者仍然可以瀏覽。聽起來這樣的idea似乎不錯,但相對的,會不會因此扼殺了網頁程式和瀏覽器的自由度呢?? 就像現在許多人會去越獄iPhone,下載沒通過認證的軟體一樣。另外,還有一個問題是,網頁App不像一般的OS App一樣,是可以隨時修改的。萬一一開始送審時通過,但卻在日後的新改版出現問題,也很難防範。除非規定要通過認證的網站每次改版都要重新送審,並註記修改的部份,但這樣一來,會不會反而增加了App的開發時間和難度呢?

這真是一個令人爭議的問題啊,不知道未來Chrome OS正式上線後會是怎麼做? 或者仍維持現狀? 在幾年前只有IE當道時,從沒想過會有這種情形(瀏覽器百家爭鳴),所以自然不需要這種組織出現。但後來慢慢有了Firefox, Opera, Safari, Chrome…etc. 網頁的前端技術,也慢慢越變越複雜… JavaScript, AJAX, JSONP, CSS, Flex, Silverlight…etc.。最近,隨著Facebook電影的上映,似乎也宣告著未來網路世界的來臨,更蓬勃發展、更複雜、更有趣和………..更危險。

這一切,也許都要歸功於Google、Yahoo、Facebook、Microsoft、Apple…etc. 彼此之間的良性競爭(我指在網路技術方面)吧~ 如果大家為了侵犯某某專利,互相告來告去,這真的是對人類的未來科技發展有幫助嗎? I don’t think so… 這也是我想選擇Web Front-end技術做為我未來focus的主要技術的原因,我希望有一天,我寫出來的網頁程式是真的對人類有幫助的。也期待未來有更多的網路技術可以讓我玩~~ :)

The picture source is from:
http://www.deg.byu.edu/ding/WebEvolution/evolution-review.html

寫JavaScript時的好習慣(Good Practices)

Thursday, September 16th, 2010
以下內容是根據讀完”Professional JavaScript for Web Developers 2nd Edition“這本書的心得而來。
  1. 一個function要碼都有return值(在不同condition時),要碼就都沒有。不要有時會return值,有時卻不會。容易造成混洧。
  2. 不要用with statement。因為它會造成執行效能降低。而且會增加debug時的困難。
  3. if – else裡的statement最好都要用括號括起來,即使只有一行。這樣可以增加程式碼的可讀性。
  4. 每行statement最好都要有分號(;)結尾。雖然JavaScript允許每行的結尾可以沒有分號,但這樣之後若要做code壓縮(自動刪除空白和斷行)時,就會產生錯誤了。
  5. 永遠不要用浮點數(floating number)來做compare比較。因為浮點數在JavaScript裡是有誤差值的。
  6. 若要將一個字串(string)變數轉為數字(number)型態時,最好是用parseInt或parseFloat作轉換。若是其他資料型態(data type),則使用Number() casting function。
  7. 透過在function裡的arguments物件,可以模擬類似其他程式語言(如: Java)的多形(Polymorphism)function。在處理時,可以根據傳入不同的參數型態或數量做不同的處理變化。(詳見這篇)
  8. 宣告一個變數時記得前面一定要加var。雖然不加var也是JavaScript可接受的寫法(會變成global variable),但是這樣容易造成混洧和發生錯誤。
  9. 儘量避免明示宣告一個primitive wrapped object(String, Boolean, Number,例: var str = new String(‘test…’);)。因為這會讓開發者搞不清楚他們是在處理reference value or primitive value,容易造成混洧。
  10. 在一個遞迴(recursive)或匿名(anonymous)函式裡,最好使用arguments.callee代替指定function name。這樣一來,日後即使換了function name(reference),也不用跟著調整function code裡面寫到的名稱。
  11. 在使用Closure (a anonymous function inside another function)時,只有在真正需要用到時才用這個寫法,別過度使用它。因為它會保留上層function的整個scope,造成額外的記憶體消耗。
  12. 儘用少用setInterval,因為它有可能會讓一段code還沒結束前就開始執行下一次的程序。可以改用setTimeout加上遞迴(recursive)寫法來達成與setInterval一樣的效果,這樣可保證每次執行code時,上一次程序已經執行結束。
  13. 如果要用JavaScript判斷不同瀏覽器或Capability來做例外處理,最好當成是一般解法無法運作時的最後手段。非不得已才用這個方式。
  14. 不要過度頻繁的操作element的innerText或innerHTML,因為這會降低執行速度,比較沒效率。如果有個迴圈會連續對某個element改寫這兩個properties值,最好先將HTML或文字寫在string buffer裡,然後只做一次改寫的動作。(詳見這篇)
  15. 當使用指定innerHTML來改變一個element時,寫code時最好不要將其element的children綁定event handler。如果element的children已經有綁定event handler,最好手動將綁定的event handler移除掉(例: targetElm.onclick = null;),避免memory leak發生(尤其在IE)。
  16. 儘量減少event handler(function)的數量,因為綁定越多的handler會消耗更多memory,而降低執行效率。可以使用”Event Delegation“的技巧來減少event handler的數量。
  17. 當要寫一段判斷式時(if, while…etc.),最好總是確保括號裡的陳述是一個Boolean值。例如要判斷一個變數是否為一個字串才做處理,最好寫成 if( typeof str == ’string’ ) ,而不要寫成 if( str )。後者雖然也可work(因變數原格式會被自動轉成Boolean格式),但檢查條件鬆散許多,較容易發生不該出現的狀況。
  18. JavaScript與CSS、HTML彼此之間應該儘量減少耦合(coupling)程度。HTML負責提供內容(content),CSS專職呈現(appearance),JavaScript則處理行為(behavior)(詳見這篇)。意即: 在HTML裡不該出現JavaScript及CSS style的code,在JavaScript裡不該去處理CSS style及HTML tag。過度的耦合會造成code maintain上的困難。
  19. 當一段程式邏輯需要耗費大量時間運算時,可以試著將可分割的程式區塊切成數小段,用setTimeout指定一小段時間間隔後再執行。這樣可以讓頁面有更多喘息的時間來回應使用者的操作行為,而有更好的使用者互動經驗。
  20. 將Event Handler裡面的商業邏輯獨立出來。Event Handler應該只處理與Event有關資料,例如抓取keyPress event的keyCode或event target。若要利用這些值做一些處理,則改在別的function裡做。不要pass event object到Event Handler以外的地方。
  21. 儘量減少access global variable的次數可以增進效能,因為減少了traverse time。如果一個function裡有數個地方會access同一個global variable(如: document),可以先用一個local variable去指向global variable,後續的code再access local variable,這樣可加快速度。
  22. 如果要建立一個Storage來存放資料時,用Array會比Object快。在Access資料的速度上,前者的複雜度為O(1),後者為O(n)。
  23. 若一段code有很多if-else時,改採用switch寫法執行速度會比較快一些。另外可以將比較容易match到的case條件排在比較上面,比較少match到的case排在下面,也會讓效能上有些許提昇。
  24. 儘量減少對DOM的操作會使效能有非常顯著的提升,DOM的運算是Browser裡最耗運算資源的。當要對一個HTML element連續插入很多或複雜的child element時,可以用DocumentFragment先將整個DOM結構建立好,再一次加進element,速度會快很多! (詳見這篇)

其他參考:
JSLint – JavaScript Validation Tool
YUI Compressor – JavaScript Compress Tool
Ant – 利用Ant將數個js檔案合併為一個檔案教學

本書作者的Blog: http://www.nczonline.net/

JavaScript中的內定物件與函式: arguments, callee, caller, this, apply(), call()

Wednesday, September 1st, 2010

arguments, caller, callee, this都是用在函式(function)內的特殊內定物件。而apply()及call()則是用來呼叫函式的不同作法。

  • arguments
    可用來取得function傳入的實際變數Array。這個變數特別適合用在撰寫”多形”(Polymorphism)函式上,即可以根據不同的傳入參數做不同的處理。
    範例一 – 加總函式

    function sum() {
    	var total = 0;
    	for( var i=0; i<arguments.length; i++ ) {
    		total += arguments[i];
    	}
    	return total;
    }
    
    // 測試
    log( sum() );                              // 結果 = 0
    log( sum(1, 2) );                          // 結果 = 3
    log( sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) ); // 結果 = 55
    

    範例二 – 自我介紹函式

    function introduce() {
    	var callback = null;
    	var msg = '';
    	for( var i=0; i<arguments.length; i++ ) {
    		var p = arguments[i];
    		if( typeof p == 'string' ) {
    			msg += '我叫'+p;
    		} else if( typeof p == 'number' ) {
    			msg += '今年'+p+'歲';
    		} else if( typeof p == 'function' ) {
    			callback = p;
    		}
    	}
    
    	if( callback != null ) {
    		callback(msg);
    	} else {
    		log( msg );
    	}
    }
    
    // 測試2
    introduce('David');                    // console印出"我叫David"
    introduce('David', 29);                // console印出"我叫David今年29歲"
    introduce('David', function(msg) {     // 跳出"我叫David"的訊息
    	alert(msg);
    });
    introduce('David', 29, function(msg) { // 跳出"我叫David今年29歲"的訊息
    	alert(msg);
    });
    
  • callee
    此為arguments的屬性之一,可取得被call function本身。
  • caller
    可用來取得call該function的來源物件。
  • this
    指到函數的擁有者(Owner)。
  • apply()與call()
    apply與call兩者本身的功能相同,都可以用來特別指定被call function中的this變數。
    不同之處在於傳入參數的寫法不同:

    apply( thisArg, argArray ); // 第二個參數必須是個Array,否則會產生參數型態錯誤的Error
    call( thisArg[, arg1, arg2…] );

以下範例將秀出callee, caller, this及apply(), call()的用法

function methodA(p1, p2, p3) {
	log('========================');
	log( arguments ); // 實際傳入的參數陣列
	log( arguments.callee ); // 指到methodA
	log( arguments.callee.caller ); // 指到call methodA的object
	log( '宣告參數長度: '+arguments.callee.length );
	log( '實際參數長度: '+arguments.length );
	log( this );
	log( p1 );
	log( p2 );
	log( p3 );
}

function handleCaller() {
	methodA('xxx', 'yyy');
	methodA.apply(handleCaller, ['xxx', 'yyy']); // 指定this object
}

function init() {
	handleCaller();
	methodA.call(handleCaller, 'xxx', 'yyy'); // 指定this object
}
init();

結果:
注意到第一個結果區塊的this指到window物件了,而其它兩個執行結果則指到handleCaller
而第三個結果區塊的function caller指到init,其它兩個執行結果則指到handleCaller

以上範例中會使用到的 log function – 用於輸出文字到Firebug或Chrome, IE8的console

function log(msg) {
	if( window.console ) {
		console.log(msg);
	}
}

參考:
http://www.ijavascript.cn/jiaocheng/caller-callee-call-apply-464.html
http://blog.darkthread.net/blogs/darkthreadtw/archive/2009/03/11/js-this-and-closure.aspx
http://blog.darkthread.net/blogs/darkthreadtw/archive/2009/04/10/js-func-apply.aspx