SlideShare a Scribd company logo
1 of 26
JavaScript
Advanced Skill
by David Hung
2010-11-22
JavaScript 的組成
一般來說, JavaScript 其實是由三個部份所組成 :
ECMAScript
定義核心的程式語言架構、變數型態等
DOM (Document Object Model)
負責與頁面元素 (element) 溝通,例如修改元素的 HTML 內容
BOM (Browser Object Model)
負責與 Browser 溝通,例如取得螢幕的寬高等
JavaScript
ECMAScript BOMDOM
觀念澄清
在 JavaScript 裡可以 multi-thread 執行程式 ?
不可以 ! JavaScript 是一個 single thread 的語言,有一些
JavaScript Library 宣稱他們可以使程式碼跑起來像是 multi-
thread 。其實是用 setTimeout function ” ”來 模擬 multi-thread 的
行為而已,但實際上還是 single thread 。
※ 在 Browser 裡有一個 Queue 用來處理所有要執行的程式區
塊,利用 setTimeout 可以延後一個程式區塊的執行時間點。而
讓 Browser 有時間先做其他的事。
在 JavaScript 裡傳遞參數時,到底是 pass by value 還是
pass by reference?
全部都是 pass by value 。不過如果 pass 的參數型態為
reference type(i.e. object, array...etc.) 時,修改該物件裡的屬性
值,仍會影響到原先的物件資料。
DOM Event Flow
在 JavaScript 裡, Event 的傳遞分為兩個階段 :
Capture phase
target.addEventListener(type, listener, true);
Bubbling phase
target.addEventListener(type, listener, false);
寫 JavaScript 的好習慣 (Good Practice)
一個 function 要碼都有 return 值 ( 在不同 condition 時 ) ,要
碼就都沒有。不要有時會 return 值,有時卻不會。容易造成
混洧。
function getShortBrowserName(obj) {
if( obj.title == 'Firefox' ) {
return 'FF';
} else if ( obj.title == 'Internet Explorer' ) {
return 'IE';
}
}
上面這段 code 不好的地方在於,如果傳入 object 的 title 屬性不為 Firefox 或 Internet
Explorer 字串時,就不會 return 任何值。 Call 這個 method 的人就會接到 undefined ,
而這可能不是預期中的事。
寫 JavaScript 的好習慣 (Good Practice)
不要用 with statement 。因為它會造成執行效能降低,而且會
增加 debug 時的困難。
function updateBody() {
with(document.body) {
alert(tagName);
innerHTML = 'Hello World';
}
}
with statement 是用來縮減 code 的長度,可省略在 statement 裡面 aceess 宣告的
object 屬性值的前置字串。但使用 with statement 時,在執行 code 會多找一層 scope
導致效能變差。改用比較短的 local varibable 先將該 object 記起來是比較好的寫法,如
下 :
function updateBody() {
var body = document.body
alert(body.tagName);
body.innerHTML = 'Hello World';
}
寫 JavaScript 的好習慣 (Good Practice)
if – else 裡的 statement 最好都要用括號括起來,即使只有一
行。這樣可以增加程式碼的可讀性。
每行 statement 最好都要有分號 (;) 結尾。雖然 JavaScript 允
許每行的結尾可以沒有分號,但這樣之後若要做 code 壓縮
( 自動刪除空白和斷行 ) 時,就會產生錯誤了。
永遠不要用浮點數 (floating number) 來做 compare 比較。因
為浮點數在 JavaScript 裡是有誤差值的。
若要將一個字串 (string) 變數轉為數字 (number) 型態時,最
好是用 parseInt 或 parseFloat 作轉換。若是其他資料型態
(data type) ,則使用 Number() casting function 。
寫 JavaScript 的好習慣 (Good Practice)
透過在 function 裡的 arguments 物件,可以模擬類似其他程
式語言 ( 如 : Java) 的多形 (Polymorphism)function 。在處理
時,可以根據傳入不同的參數型態或數量做不同的處理變
化。
// 加總函式
function sum() {
var total = 0;
for( var i=0; i<arguments.length; i++ ) {
total += arguments[i];
}
return total;
}
// 測試 code
log( sum() ); // 0
log( sum(1, 2) ); // 3
log( sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) ); // 55
寫 JavaScript 的好習慣 (Good Practice)
宣告一個變數時記得前面一定要加 var 。雖然不加 var 也是
JavaScript 可接受的寫法 ( 會變成 global variable) ,但是這樣
容易造成混洧和發生錯誤。
儘量避免明示宣告一個 primitive wrapped object(String,
Boolean, Number ,例 : var str = new String(‘test…’);) 。因為
這會讓開發者搞不清楚他們是在處理 reference value or
primitive value ,容易造成混洧。
寫 JavaScript 的好習慣 (Good Practice)
在一個遞迴 (recursive) 或匿名 (anonymous) 函式裡,最好使
用 arguments.callee 代替指定 function name 。這樣一來,日
後即使換了 function name(reference) ,也不用跟著調整
function code 裡面寫到的名稱。
// a recursive function
function grabData() {
if( storage.length > 0 ) { // storage is a array
var obj = storage.shift();
// your handle code here
var method = arguments.callee;
window.setTimeout(function() {
method(); // execute grabData method actually
}, 300);
}
}
寫 JavaScript 的好習慣 (Good Practice)
在使用 Closure (a anonymous function inside another
function) 時,只有在真正需要用到時才用這個寫法,別過度
使用它。因為它會保留上層 function 的整個 scope ,造成額
外的記憶體消耗。
儘用少用 setInterval ,因為它有可能會讓一段 code 還沒結束
前就開始執行下一次的程序。可以改用 setTimeout 加上遞迴
(recursive) 寫法來達成與 setInterval 一樣的效果,這樣可保
證每次執行 code 時,上一次程序已經執行結束。
如果要用 JavaScript 判斷不同瀏覽器或 Capability 來做例外處
理,最好當成是一般解法無法運作時的最後手段。非不得已
才用這個方式。
寫 JavaScript 的好習慣 (Good Practice)
不要過度頻繁的操作 element 的 innerText 或 innerHTML ,
因為這會降低執行速度,比較沒效率。如果有個迴圈會連續
對某個 element 改寫這兩個 properties 值,最好先將 HTML
或文字寫在 string buffer 裡,然後只做一次改寫的動作。
// 原本的寫法,比較沒效率,做了 100 次 DOM Element 操作
var panel = document.getElementById('my_panel');
for( var i=0; i<100; i++ ) {
var item = document.createElement('div');
item.innerHTML = 'Item-'+i;
panel.appendChild(item);
}
// 改用 String Buffer 的寫法,只做一次 DOM Element 操作
var panel = document.getElementById('my_panel');
var html = '';
for( var i=0; i<100; i++ ) {
html += '<div>Item-'+i+'</div>';
}
panel.innerHTML = html;
寫 JavaScript 的好習慣 (Good Practice)
當使用指定 innerHTML 來改變一個 element 時,寫 code 時
最好不要將其 element 的 children 綁定 event handler 。如果
element 的 children 已經有綁定 event handler ,最好手動將
綁定的 event handler 移除掉 ( 例 : targetElm.onclick =
null;) ,避免 memory leak 發生 ( 尤其在 IE) 。
當要寫一段判斷式時 (if, while…etc.) ,最好總是確保括號裡
的陳述是一個 Boolean 值。例如要判斷一個變數是否為一個
字串才做處理,最好寫成 if( typeof str == ’string’ ) ,而不要
寫成 if( str ) 。後者雖然也可 work( 因變數原格式會被自動轉
成 Boolean 格式 ) ,但檢查條件鬆散許多,較容易發生不該出
現的狀況。
寫 JavaScript 的好習慣 (Good Practice)
儘量減少 event handler(function) 的數量,因為綁定越多的
handler 會消耗更多 memory ”,而降低執行效率。可以使用
Event Delegation“ 的技巧來減少 event handler 的數量。
// Event Delegation Sample
document.onclick = function(event){
//IE doesn't pass in the event object
event = event || window.event;
//IE uses srcElement as the target
var target = event.target || event.srcElement;
switch(target.id){
case "help-btn":
openHelp();
break;
case "save-btn":
saveDocument();
break;
case "undo-btn":
undoChanges();
break;
//others?
}
};
寫 JavaScript 的好習慣 (Good Practice)
JavaScript 與 CSS 、 HTML 彼此之間應該儘量減少耦合
(coupling) 程度。 HTML 負責提供內容 (content) , CSS 專職
呈現 (appearance) , JavaScript 則處理行為 (behavior) 。意
即 : 在 HTML 裡不該出現 JavaScript 及 CSS style 的 code ,
在 JavaScript 裡不該去處理 CSS style 及 HTML tag 。過度的
耦合會造成 code maintain 上的困難。
寫 JavaScript 的好習慣 (Good Practice)
當一段程式邏輯需要耗費大量時間運算時,可以試著將可分
割的程式區塊切成數小段,用 setTimeout 指定一小段時間間
隔後再執行。這樣可以讓頁面有更多喘息的時間來回應使用
者的操作行為,而有更好的使用者互動經驗。
// 原本的寫法
function insertItem() {
var panel = document.getElementById('my_panel');
for( var i=0; i<100; i++ ) {
var item = document.createElement('div');
item.innerHTML = 'Item-'+i;
item.onmouseover = function() {
this.style['background'] = 'gold';
};
item.onmouseout = function() {
this.style['background'] = 'transparent';
};
// ... other handle codes
panel.appendChild(item);
}
}
// 新的寫法
var count = 0;
function insertItem(index) {
if( index >= 100 ) return;
var panel = document.getElementById('my_panel');
var item = document.createElement('div');
item.innerHTML = 'Item-'+index;
item.onmouseover = function() {
this.style['background'] = 'gold';
};
item.onmouseout = function() {
this.style['background'] = 'transparent';
};
// ... other handle codes
panel.appendChild(item);
// delay a while to let browser take a break
var method = arguments.callee;
window.setTimeout(function() {
method(count++);
}, 50);
}
寫 JavaScript 的好習慣 (Good Practice)
將 Event Handler 裡面的商業邏輯獨立出來。 Event Handler
應該只處理與 Event 有關資料,例如抓取 keyPress event 的
keyCode 或 event target 。若要利用這些值做一些處理,則改
在別的 function 裡做。不要 pass event object 到 Event
Handler 以外的地方。
// 原本的 code
function handleKeypress(event) {
if( event.keyCode == 13 ) {
var target = EventUtil.getTarget(event);
var value = 5 * parseInt(target.value);
if( value > 10 ) {
var elm = document.
getElementById('error-msg');
elm.style.display = 'block';
}
}
}
// 改寫後的 code ,將商業邏輯獨立出來
function validateValue(value) {
value = 5 * parseInt(value);
if( value > 10 ) {
var elm = document
.getElementById('error-msg');
elm.style.display = 'block';
}
}
function handleKeypress(event) {
if( event.keyCode == 13 ) {
var target = EventUtil.getTarget(event);
validateValue(target.value);
}
}
寫 JavaScript 的好習慣 (Good Practice)
儘量減少 access global variable 的次數可以增進效能,因為
減少了 traverse time 。如果一個 function 裡有數個地方會
access 同一個 global variable( 如 : document) ,可以先用一
個 local variable 去指向 global variable ,後續的 code 再
access local variable ,這樣可加快速度。
// 原本的 code
function updateUI() {
var imgs = document
.getElementsByTagName('img');
for( var i=0, len=imgs.length; i<len, i++ ) {
imgs[i].title = document.title + 'image' + i;
}
var msg = document.getElementById('msg');
msg.innerHTML = 'Update complete';
}
// 改寫後的 code ,先宣告一個 local variable 去記
// document
function updateUI() {
var doc = document;
var imgs = doc.getElementsByTagName('img');
for( var i=0, len=imgs.length; i<len, i++ ) {
imgs[i].title = doc.title + 'image' + i;
}
var msg = doc.getElementById('msg');
msg.innerHTML = 'Update complete';
}
寫 JavaScript 的好習慣 (Good Practice)
如果要建立一個 Storage 來存放資料時,用 Array 會比 Object
快。在 Access 資料的速度上,前者的複雜度為 O(1) ,後者
為 O(n) 。
若一段 code 有很多 if-else 時,改採用 switch 寫法執行速度會
比較快一些。另外可以將比較容易 match 到的 case 條件排在
比較上面,比較少 match 到的 case 排在下面,也會讓效能上
有些許提昇。
寫 JavaScript 的好習慣 (Good Practice)
儘量減少對 DOM 的操作會使效能有非常顯著的提升, DOM
的運算是 Browser 裡最耗運算資源的。當要對一個 HTML
element 連續插入很多或複雜的 child element 時,可以用
DocumentFragment 先將整個 DOM 結構建立好,再一次加進
element ,速度會快很多 !
// 原本的寫法
function insertItem() {
var panel = document.getElementById('my_panel');
for( var i=0; i<100; i++ ) {
var item = document.createElement('div');
item.innerHTML = 'Item-'+i;
item.onmouseover = function() {
this.style['background'] = 'gold';
};
item.onmouseout = function() {
this.style['background'] = 'transparent';
};
// ... other handle codes
panel.appendChild(item);
}
}
// 改寫後的 code ,將 item 寫進 DocumentFragment
function insertItem() {
var panel = document.getElementById('my_panel');
var fragment = document
.createDocumentFragment();
for( var i=0; i<100; i++ ) {
var item = document.createElement('div');
item.innerHTML = 'Item-'+i;
item.onmouseover = function() {
this.style['background'] = 'gold';
};
item.onmouseout = function() {
this.style['background'] = 'transparent';
};
fragment.appendChild(item);
// ... other handle codes
}
panel.appendChild(fragment);
}
Naming Rule
Variable 請用小寫名詞,如 : person, card 。
Function 請用小寫動詞開頭,如 : getName(), pushEvent() 。
假如 Function 會回傳一個 Boolean 值,請用 is 開頭,如 :
isEnabled(), isVisible() 。
Constant 請用大寫及底線,如 : STATE, EVENT_TYPE 。
如果是 private 使用,可以在 Variable 及 Function 字首加上底
線。如 : _target, _getElement() 。
HTML Element 的 class name 、寫入 Cookie 或發送 HTTP
Request 的參數名稱請用底線 '_' 區隔單字。如 :
'window_panel', 'personal_setting', 'widget_position' 。
Convention Rule
在 JavaScript 裡,字串用單引號標示,在 HTML 裡用雙引號
標示。當規則定下來之後,如果有一天需要把 HTML element
改由 JavaScript 動態產生,就可以直接覆製 HTML code 到
JavaScript 字串變數裡,不需再擔心單雙引號相衝的問題。
縮排 Tab 改用空白取代。這是為了防止當很多人一起改 code
時,程式碼會因為每個人的編輯器不同, Tab 所表示的空白
字元數不同,而導致程式碼縮排不一致變的亂七八糟。
// in JavaScript
var str = 'Hello World';
// in HTML
<div class=“err-msg“></div>
// 假如必須要在 JavaScript 裡直接寫 HTML code
var html = '<div class=“err-msg“></div>';
利用 Ant 將 JavaScript 及 CSS 檔案串接
介紹文章 : http://www.julienlecomte.net/blog/2007/09/16/
好處 : 將多個 JavaScript 或 CSS 檔案串接成為一個檔案後,可
以減少 Browser 透過網路戴入的次數 (requests) 。進而加快頁
面的瀏覽速度。使用此方法串接 js 檔案時,需注意先後順序,
如同 <script> import js file 一般。
<?xml version="1.0" encoding="UTF-8"?>
<project basedir="." default="js.concatenate" name="JS Concatenation">
<!-- the directory to output to -->
<property name="build.dir" value="./js" />
<!-- the directory containing the source files -->
<property name="src.dir" value="./dev/src" />
<!-- Target to concatenate all js files -->
<target name="js.concatenate">
<concat destfile="${build.dir}/concatenated/all.js">
<filelist dir="${src.dir}/js" files="a.js, b.js"/>
<fileset dir="${src.dir}/js" includes="**/*.js" excludes="a.js, b.js"/>
</concat>
</target>
</project>
其他資源
Debuger
Firebug
Compressor
JSMin
YUI Compressor
Validator
JSLint
Framework
http://en.wikipedia.org/wiki/Comparison_of_JavaScript_framework
JavaScript 推薦書籍
Professional JavaScript for Web Developers, 2/e
JavaScript: The Good Parts
Pro JavaScript Design Patterns
Thank You!!

More Related Content

What's hot

jQuery源码学习
jQuery源码学习jQuery源码学习
jQuery源码学习fangdeng
 
Ecma script edition5-小试
Ecma script edition5-小试Ecma script edition5-小试
Ecma script edition5-小试lydiafly
 
05 MapKit and Text Input
05 MapKit and Text Input05 MapKit and Text Input
05 MapKit and Text InputTom Fan
 
02 Objective-C
02 Objective-C02 Objective-C
02 Objective-CTom Fan
 
Java华为面试题
Java华为面试题Java华为面试题
Java华为面试题yiditushe
 
JavaScript 闭包分享(一):传递参数
JavaScript 闭包分享(一):传递参数JavaScript 闭包分享(一):传递参数
JavaScript 闭包分享(一):传递参数Janlay Wu
 
ES5 introduction
ES5 introductionES5 introduction
ES5 introductionotakustay
 
Keep your code clean
Keep your code cleanKeep your code clean
Keep your code cleanmacrochen
 
lambda/closure – JavaScript、Python、Scala 到 Java SE 7
lambda/closure – JavaScript、Python、Scala 到 Java SE 7lambda/closure – JavaScript、Python、Scala 到 Java SE 7
lambda/closure – JavaScript、Python、Scala 到 Java SE 7Justin Lin
 
JavaScript 脚本控件(二)
JavaScript 脚本控件(二)JavaScript 脚本控件(二)
JavaScript 脚本控件(二)RANK LIU
 
异步编程与浏览器执行模型
异步编程与浏览器执行模型异步编程与浏览器执行模型
异步编程与浏览器执行模型keelii
 
Ejb工作原理学习笔记
Ejb工作原理学习笔记Ejb工作原理学习笔记
Ejb工作原理学习笔记yiditushe
 
107个常用javascript语句 oss 计算技术 - ossez info of tech
107个常用javascript语句   oss 计算技术 - ossez info of tech107个常用javascript语句   oss 计算技术 - ossez info of tech
107个常用javascript语句 oss 计算技术 - ossez info of techYUCHENG HU
 
Kissy editor开发与设计
Kissy editor开发与设计Kissy editor开发与设计
Kissy editor开发与设计yiming he
 

What's hot (19)

jQuery源码学习
jQuery源码学习jQuery源码学习
jQuery源码学习
 
前端测试
前端测试前端测试
前端测试
 
Ecma script edition5-小试
Ecma script edition5-小试Ecma script edition5-小试
Ecma script edition5-小试
 
Node way
Node wayNode way
Node way
 
05 MapKit and Text Input
05 MapKit and Text Input05 MapKit and Text Input
05 MapKit and Text Input
 
J Query Learn
J Query LearnJ Query Learn
J Query Learn
 
02 Objective-C
02 Objective-C02 Objective-C
02 Objective-C
 
JS2
JS2JS2
JS2
 
Java华为面试题
Java华为面试题Java华为面试题
Java华为面试题
 
JavaScript 闭包分享(一):传递参数
JavaScript 闭包分享(一):传递参数JavaScript 闭包分享(一):传递参数
JavaScript 闭包分享(一):传递参数
 
ES5 introduction
ES5 introductionES5 introduction
ES5 introduction
 
Keep your code clean
Keep your code cleanKeep your code clean
Keep your code clean
 
lambda/closure – JavaScript、Python、Scala 到 Java SE 7
lambda/closure – JavaScript、Python、Scala 到 Java SE 7lambda/closure – JavaScript、Python、Scala 到 Java SE 7
lambda/closure – JavaScript、Python、Scala 到 Java SE 7
 
Ooredis
OoredisOoredis
Ooredis
 
JavaScript 脚本控件(二)
JavaScript 脚本控件(二)JavaScript 脚本控件(二)
JavaScript 脚本控件(二)
 
异步编程与浏览器执行模型
异步编程与浏览器执行模型异步编程与浏览器执行模型
异步编程与浏览器执行模型
 
Ejb工作原理学习笔记
Ejb工作原理学习笔记Ejb工作原理学习笔记
Ejb工作原理学习笔记
 
107个常用javascript语句 oss 计算技术 - ossez info of tech
107个常用javascript语句   oss 计算技术 - ossez info of tech107个常用javascript语句   oss 计算技术 - ossez info of tech
107个常用javascript语句 oss 计算技术 - ossez info of tech
 
Kissy editor开发与设计
Kissy editor开发与设计Kissy editor开发与设计
Kissy editor开发与设计
 

Viewers also liked

AJAX Search & Cross Domain Survey
AJAX Search & Cross Domain SurveyAJAX Search & Cross Domain Survey
AJAX Search & Cross Domain Surveyfirestoke
 
Android進階UI控制元件
Android進階UI控制元件Android進階UI控制元件
Android進階UI控制元件艾鍗科技
 
What's Next in Growth? 2016
What's Next in Growth? 2016What's Next in Growth? 2016
What's Next in Growth? 2016Andrew Chen
 
32 Ways a Digital Marketing Consultant Can Help Grow Your Business
32 Ways a Digital Marketing Consultant Can Help Grow Your Business32 Ways a Digital Marketing Consultant Can Help Grow Your Business
32 Ways a Digital Marketing Consultant Can Help Grow Your BusinessBarry Feldman
 
Study: The Future of VR, AR and Self-Driving Cars
Study: The Future of VR, AR and Self-Driving CarsStudy: The Future of VR, AR and Self-Driving Cars
Study: The Future of VR, AR and Self-Driving CarsLinkedIn
 
Hype vs. Reality: The AI Explainer
Hype vs. Reality: The AI ExplainerHype vs. Reality: The AI Explainer
Hype vs. Reality: The AI ExplainerLuminary Labs
 

Viewers also liked (7)

AJAX Search & Cross Domain Survey
AJAX Search & Cross Domain SurveyAJAX Search & Cross Domain Survey
AJAX Search & Cross Domain Survey
 
OAuth簡介
OAuth簡介OAuth簡介
OAuth簡介
 
Android進階UI控制元件
Android進階UI控制元件Android進階UI控制元件
Android進階UI控制元件
 
What's Next in Growth? 2016
What's Next in Growth? 2016What's Next in Growth? 2016
What's Next in Growth? 2016
 
32 Ways a Digital Marketing Consultant Can Help Grow Your Business
32 Ways a Digital Marketing Consultant Can Help Grow Your Business32 Ways a Digital Marketing Consultant Can Help Grow Your Business
32 Ways a Digital Marketing Consultant Can Help Grow Your Business
 
Study: The Future of VR, AR and Self-Driving Cars
Study: The Future of VR, AR and Self-Driving CarsStudy: The Future of VR, AR and Self-Driving Cars
Study: The Future of VR, AR and Self-Driving Cars
 
Hype vs. Reality: The AI Explainer
Hype vs. Reality: The AI ExplainerHype vs. Reality: The AI Explainer
Hype vs. Reality: The AI Explainer
 

Similar to JavaScript Advanced Skill

Javascript 性能优化总结.docx
Javascript 性能优化总结.docxJavascript 性能优化总结.docx
Javascript 性能优化总结.docxbaixingfa
 
用Jquery实现拖拽层
用Jquery实现拖拽层用Jquery实现拖拽层
用Jquery实现拖拽层yiditushe
 
第三方内容开发最佳实践
第三方内容开发最佳实践第三方内容开发最佳实践
第三方内容开发最佳实践taobao.com
 
學好 node.js 不可不知的事
學好 node.js 不可不知的事學好 node.js 不可不知的事
學好 node.js 不可不知的事Ben Lue
 
Web设计 3 java_script初探(程序员与设计师的双重眼光)
Web设计 3 java_script初探(程序员与设计师的双重眼光)Web设计 3 java_script初探(程序员与设计师的双重眼光)
Web设计 3 java_script初探(程序员与设计师的双重眼光)ziggear
 
jQuery底层架构
jQuery底层架构jQuery底层架构
jQuery底层架构fangdeng
 
Node.js开发体验
Node.js开发体验Node.js开发体验
Node.js开发体验QLeelulu
 
旺铺前端设计和实现
旺铺前端设计和实现旺铺前端设计和实现
旺铺前端设计和实现hua qiu
 
PHP Coding Standard and 50+ Programming Skills
PHP Coding Standard and 50+ Programming SkillsPHP Coding Standard and 50+ Programming Skills
PHP Coding Standard and 50+ Programming SkillsHo Kim
 
網站設計100步
網站設計100步網站設計100步
網站設計100步evercislide
 
JavaScript 80+ Programming and Optimization Skills
JavaScript 80+ Programming and Optimization SkillsJavaScript 80+ Programming and Optimization Skills
JavaScript 80+ Programming and Optimization SkillsHo Kim
 
Asp.net mvc 培训
Asp.net mvc 培训Asp.net mvc 培训
Asp.net mvc 培训lotusprince
 
张所勇:前端开发工具推荐
张所勇:前端开发工具推荐张所勇:前端开发工具推荐
张所勇:前端开发工具推荐zhangsuoyong
 
Javascript autoload
Javascript autoloadJavascript autoload
Javascript autoloadjay li
 
Jquery指南
Jquery指南Jquery指南
Jquery指南yiditushe
 
从无阻塞并行脚本加载(Lab.js)到浏览器消息模型
从无阻塞并行脚本加载(Lab.js)到浏览器消息模型从无阻塞并行脚本加载(Lab.js)到浏览器消息模型
从无阻塞并行脚本加载(Lab.js)到浏览器消息模型裕波 周
 
前端MVC之backbone
前端MVC之backbone前端MVC之backbone
前端MVC之backboneJerry Xie
 

Similar to JavaScript Advanced Skill (20)

Javascript 性能优化总结.docx
Javascript 性能优化总结.docxJavascript 性能优化总结.docx
Javascript 性能优化总结.docx
 
用Jquery实现拖拽层
用Jquery实现拖拽层用Jquery实现拖拽层
用Jquery实现拖拽层
 
前端测试
前端测试前端测试
前端测试
 
第三方内容开发最佳实践
第三方内容开发最佳实践第三方内容开发最佳实践
第三方内容开发最佳实践
 
學好 node.js 不可不知的事
學好 node.js 不可不知的事學好 node.js 不可不知的事
學好 node.js 不可不知的事
 
Web设计 3 java_script初探(程序员与设计师的双重眼光)
Web设计 3 java_script初探(程序员与设计师的双重眼光)Web设计 3 java_script初探(程序员与设计师的双重眼光)
Web设计 3 java_script初探(程序员与设计师的双重眼光)
 
jQuery底层架构
jQuery底层架构jQuery底层架构
jQuery底层架构
 
Node.js开发体验
Node.js开发体验Node.js开发体验
Node.js开发体验
 
旺铺前端设计和实现
旺铺前端设计和实现旺铺前端设计和实现
旺铺前端设计和实现
 
PHP Coding Standard and 50+ Programming Skills
PHP Coding Standard and 50+ Programming SkillsPHP Coding Standard and 50+ Programming Skills
PHP Coding Standard and 50+ Programming Skills
 
網站設計100步
網站設計100步網站設計100步
網站設計100步
 
JavaScript 80+ Programming and Optimization Skills
JavaScript 80+ Programming and Optimization SkillsJavaScript 80+ Programming and Optimization Skills
JavaScript 80+ Programming and Optimization Skills
 
Asp.net mvc 培训
Asp.net mvc 培训Asp.net mvc 培训
Asp.net mvc 培训
 
Web base 吴志华
Web base 吴志华Web base 吴志华
Web base 吴志华
 
张所勇:前端开发工具推荐
张所勇:前端开发工具推荐张所勇:前端开发工具推荐
张所勇:前端开发工具推荐
 
Javascript autoload
Javascript autoloadJavascript autoload
Javascript autoload
 
Jquery指南
Jquery指南Jquery指南
Jquery指南
 
J query
J queryJ query
J query
 
从无阻塞并行脚本加载(Lab.js)到浏览器消息模型
从无阻塞并行脚本加载(Lab.js)到浏览器消息模型从无阻塞并行脚本加载(Lab.js)到浏览器消息模型
从无阻塞并行脚本加载(Lab.js)到浏览器消息模型
 
前端MVC之backbone
前端MVC之backbone前端MVC之backbone
前端MVC之backbone
 

JavaScript Advanced Skill

  • 2. JavaScript 的組成 一般來說, JavaScript 其實是由三個部份所組成 : ECMAScript 定義核心的程式語言架構、變數型態等 DOM (Document Object Model) 負責與頁面元素 (element) 溝通,例如修改元素的 HTML 內容 BOM (Browser Object Model) 負責與 Browser 溝通,例如取得螢幕的寬高等 JavaScript ECMAScript BOMDOM
  • 3. 觀念澄清 在 JavaScript 裡可以 multi-thread 執行程式 ? 不可以 ! JavaScript 是一個 single thread 的語言,有一些 JavaScript Library 宣稱他們可以使程式碼跑起來像是 multi- thread 。其實是用 setTimeout function ” ”來 模擬 multi-thread 的 行為而已,但實際上還是 single thread 。 ※ 在 Browser 裡有一個 Queue 用來處理所有要執行的程式區 塊,利用 setTimeout 可以延後一個程式區塊的執行時間點。而 讓 Browser 有時間先做其他的事。 在 JavaScript 裡傳遞參數時,到底是 pass by value 還是 pass by reference? 全部都是 pass by value 。不過如果 pass 的參數型態為 reference type(i.e. object, array...etc.) 時,修改該物件裡的屬性 值,仍會影響到原先的物件資料。
  • 4. DOM Event Flow 在 JavaScript 裡, Event 的傳遞分為兩個階段 : Capture phase target.addEventListener(type, listener, true); Bubbling phase target.addEventListener(type, listener, false);
  • 5. 寫 JavaScript 的好習慣 (Good Practice) 一個 function 要碼都有 return 值 ( 在不同 condition 時 ) ,要 碼就都沒有。不要有時會 return 值,有時卻不會。容易造成 混洧。 function getShortBrowserName(obj) { if( obj.title == 'Firefox' ) { return 'FF'; } else if ( obj.title == 'Internet Explorer' ) { return 'IE'; } } 上面這段 code 不好的地方在於,如果傳入 object 的 title 屬性不為 Firefox 或 Internet Explorer 字串時,就不會 return 任何值。 Call 這個 method 的人就會接到 undefined , 而這可能不是預期中的事。
  • 6. 寫 JavaScript 的好習慣 (Good Practice) 不要用 with statement 。因為它會造成執行效能降低,而且會 增加 debug 時的困難。 function updateBody() { with(document.body) { alert(tagName); innerHTML = 'Hello World'; } } with statement 是用來縮減 code 的長度,可省略在 statement 裡面 aceess 宣告的 object 屬性值的前置字串。但使用 with statement 時,在執行 code 會多找一層 scope 導致效能變差。改用比較短的 local varibable 先將該 object 記起來是比較好的寫法,如 下 : function updateBody() { var body = document.body alert(body.tagName); body.innerHTML = 'Hello World'; }
  • 7. 寫 JavaScript 的好習慣 (Good Practice) if – else 裡的 statement 最好都要用括號括起來,即使只有一 行。這樣可以增加程式碼的可讀性。 每行 statement 最好都要有分號 (;) 結尾。雖然 JavaScript 允 許每行的結尾可以沒有分號,但這樣之後若要做 code 壓縮 ( 自動刪除空白和斷行 ) 時,就會產生錯誤了。 永遠不要用浮點數 (floating number) 來做 compare 比較。因 為浮點數在 JavaScript 裡是有誤差值的。 若要將一個字串 (string) 變數轉為數字 (number) 型態時,最 好是用 parseInt 或 parseFloat 作轉換。若是其他資料型態 (data type) ,則使用 Number() casting function 。
  • 8. 寫 JavaScript 的好習慣 (Good Practice) 透過在 function 裡的 arguments 物件,可以模擬類似其他程 式語言 ( 如 : Java) 的多形 (Polymorphism)function 。在處理 時,可以根據傳入不同的參數型態或數量做不同的處理變 化。 // 加總函式 function sum() { var total = 0; for( var i=0; i<arguments.length; i++ ) { total += arguments[i]; } return total; } // 測試 code log( sum() ); // 0 log( sum(1, 2) ); // 3 log( sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) ); // 55
  • 9. 寫 JavaScript 的好習慣 (Good Practice) 宣告一個變數時記得前面一定要加 var 。雖然不加 var 也是 JavaScript 可接受的寫法 ( 會變成 global variable) ,但是這樣 容易造成混洧和發生錯誤。 儘量避免明示宣告一個 primitive wrapped object(String, Boolean, Number ,例 : var str = new String(‘test…’);) 。因為 這會讓開發者搞不清楚他們是在處理 reference value or primitive value ,容易造成混洧。
  • 10. 寫 JavaScript 的好習慣 (Good Practice) 在一個遞迴 (recursive) 或匿名 (anonymous) 函式裡,最好使 用 arguments.callee 代替指定 function name 。這樣一來,日 後即使換了 function name(reference) ,也不用跟著調整 function code 裡面寫到的名稱。 // a recursive function function grabData() { if( storage.length > 0 ) { // storage is a array var obj = storage.shift(); // your handle code here var method = arguments.callee; window.setTimeout(function() { method(); // execute grabData method actually }, 300); } }
  • 11. 寫 JavaScript 的好習慣 (Good Practice) 在使用 Closure (a anonymous function inside another function) 時,只有在真正需要用到時才用這個寫法,別過度 使用它。因為它會保留上層 function 的整個 scope ,造成額 外的記憶體消耗。 儘用少用 setInterval ,因為它有可能會讓一段 code 還沒結束 前就開始執行下一次的程序。可以改用 setTimeout 加上遞迴 (recursive) 寫法來達成與 setInterval 一樣的效果,這樣可保 證每次執行 code 時,上一次程序已經執行結束。 如果要用 JavaScript 判斷不同瀏覽器或 Capability 來做例外處 理,最好當成是一般解法無法運作時的最後手段。非不得已 才用這個方式。
  • 12. 寫 JavaScript 的好習慣 (Good Practice) 不要過度頻繁的操作 element 的 innerText 或 innerHTML , 因為這會降低執行速度,比較沒效率。如果有個迴圈會連續 對某個 element 改寫這兩個 properties 值,最好先將 HTML 或文字寫在 string buffer 裡,然後只做一次改寫的動作。 // 原本的寫法,比較沒效率,做了 100 次 DOM Element 操作 var panel = document.getElementById('my_panel'); for( var i=0; i<100; i++ ) { var item = document.createElement('div'); item.innerHTML = 'Item-'+i; panel.appendChild(item); } // 改用 String Buffer 的寫法,只做一次 DOM Element 操作 var panel = document.getElementById('my_panel'); var html = ''; for( var i=0; i<100; i++ ) { html += '<div>Item-'+i+'</div>'; } panel.innerHTML = html;
  • 13. 寫 JavaScript 的好習慣 (Good Practice) 當使用指定 innerHTML 來改變一個 element 時,寫 code 時 最好不要將其 element 的 children 綁定 event handler 。如果 element 的 children 已經有綁定 event handler ,最好手動將 綁定的 event handler 移除掉 ( 例 : targetElm.onclick = null;) ,避免 memory leak 發生 ( 尤其在 IE) 。 當要寫一段判斷式時 (if, while…etc.) ,最好總是確保括號裡 的陳述是一個 Boolean 值。例如要判斷一個變數是否為一個 字串才做處理,最好寫成 if( typeof str == ’string’ ) ,而不要 寫成 if( str ) 。後者雖然也可 work( 因變數原格式會被自動轉 成 Boolean 格式 ) ,但檢查條件鬆散許多,較容易發生不該出 現的狀況。
  • 14. 寫 JavaScript 的好習慣 (Good Practice) 儘量減少 event handler(function) 的數量,因為綁定越多的 handler 會消耗更多 memory ”,而降低執行效率。可以使用 Event Delegation“ 的技巧來減少 event handler 的數量。 // Event Delegation Sample document.onclick = function(event){ //IE doesn't pass in the event object event = event || window.event; //IE uses srcElement as the target var target = event.target || event.srcElement; switch(target.id){ case "help-btn": openHelp(); break; case "save-btn": saveDocument(); break; case "undo-btn": undoChanges(); break; //others? } };
  • 15. 寫 JavaScript 的好習慣 (Good Practice) JavaScript 與 CSS 、 HTML 彼此之間應該儘量減少耦合 (coupling) 程度。 HTML 負責提供內容 (content) , CSS 專職 呈現 (appearance) , JavaScript 則處理行為 (behavior) 。意 即 : 在 HTML 裡不該出現 JavaScript 及 CSS style 的 code , 在 JavaScript 裡不該去處理 CSS style 及 HTML tag 。過度的 耦合會造成 code maintain 上的困難。
  • 16. 寫 JavaScript 的好習慣 (Good Practice) 當一段程式邏輯需要耗費大量時間運算時,可以試著將可分 割的程式區塊切成數小段,用 setTimeout 指定一小段時間間 隔後再執行。這樣可以讓頁面有更多喘息的時間來回應使用 者的操作行為,而有更好的使用者互動經驗。 // 原本的寫法 function insertItem() { var panel = document.getElementById('my_panel'); for( var i=0; i<100; i++ ) { var item = document.createElement('div'); item.innerHTML = 'Item-'+i; item.onmouseover = function() { this.style['background'] = 'gold'; }; item.onmouseout = function() { this.style['background'] = 'transparent'; }; // ... other handle codes panel.appendChild(item); } } // 新的寫法 var count = 0; function insertItem(index) { if( index >= 100 ) return; var panel = document.getElementById('my_panel'); var item = document.createElement('div'); item.innerHTML = 'Item-'+index; item.onmouseover = function() { this.style['background'] = 'gold'; }; item.onmouseout = function() { this.style['background'] = 'transparent'; }; // ... other handle codes panel.appendChild(item); // delay a while to let browser take a break var method = arguments.callee; window.setTimeout(function() { method(count++); }, 50); }
  • 17. 寫 JavaScript 的好習慣 (Good Practice) 將 Event Handler 裡面的商業邏輯獨立出來。 Event Handler 應該只處理與 Event 有關資料,例如抓取 keyPress event 的 keyCode 或 event target 。若要利用這些值做一些處理,則改 在別的 function 裡做。不要 pass event object 到 Event Handler 以外的地方。 // 原本的 code function handleKeypress(event) { if( event.keyCode == 13 ) { var target = EventUtil.getTarget(event); var value = 5 * parseInt(target.value); if( value > 10 ) { var elm = document. getElementById('error-msg'); elm.style.display = 'block'; } } } // 改寫後的 code ,將商業邏輯獨立出來 function validateValue(value) { value = 5 * parseInt(value); if( value > 10 ) { var elm = document .getElementById('error-msg'); elm.style.display = 'block'; } } function handleKeypress(event) { if( event.keyCode == 13 ) { var target = EventUtil.getTarget(event); validateValue(target.value); } }
  • 18. 寫 JavaScript 的好習慣 (Good Practice) 儘量減少 access global variable 的次數可以增進效能,因為 減少了 traverse time 。如果一個 function 裡有數個地方會 access 同一個 global variable( 如 : document) ,可以先用一 個 local variable 去指向 global variable ,後續的 code 再 access local variable ,這樣可加快速度。 // 原本的 code function updateUI() { var imgs = document .getElementsByTagName('img'); for( var i=0, len=imgs.length; i<len, i++ ) { imgs[i].title = document.title + 'image' + i; } var msg = document.getElementById('msg'); msg.innerHTML = 'Update complete'; } // 改寫後的 code ,先宣告一個 local variable 去記 // document function updateUI() { var doc = document; var imgs = doc.getElementsByTagName('img'); for( var i=0, len=imgs.length; i<len, i++ ) { imgs[i].title = doc.title + 'image' + i; } var msg = doc.getElementById('msg'); msg.innerHTML = 'Update complete'; }
  • 19. 寫 JavaScript 的好習慣 (Good Practice) 如果要建立一個 Storage 來存放資料時,用 Array 會比 Object 快。在 Access 資料的速度上,前者的複雜度為 O(1) ,後者 為 O(n) 。 若一段 code 有很多 if-else 時,改採用 switch 寫法執行速度會 比較快一些。另外可以將比較容易 match 到的 case 條件排在 比較上面,比較少 match 到的 case 排在下面,也會讓效能上 有些許提昇。
  • 20. 寫 JavaScript 的好習慣 (Good Practice) 儘量減少對 DOM 的操作會使效能有非常顯著的提升, DOM 的運算是 Browser 裡最耗運算資源的。當要對一個 HTML element 連續插入很多或複雜的 child element 時,可以用 DocumentFragment 先將整個 DOM 結構建立好,再一次加進 element ,速度會快很多 ! // 原本的寫法 function insertItem() { var panel = document.getElementById('my_panel'); for( var i=0; i<100; i++ ) { var item = document.createElement('div'); item.innerHTML = 'Item-'+i; item.onmouseover = function() { this.style['background'] = 'gold'; }; item.onmouseout = function() { this.style['background'] = 'transparent'; }; // ... other handle codes panel.appendChild(item); } } // 改寫後的 code ,將 item 寫進 DocumentFragment function insertItem() { var panel = document.getElementById('my_panel'); var fragment = document .createDocumentFragment(); for( var i=0; i<100; i++ ) { var item = document.createElement('div'); item.innerHTML = 'Item-'+i; item.onmouseover = function() { this.style['background'] = 'gold'; }; item.onmouseout = function() { this.style['background'] = 'transparent'; }; fragment.appendChild(item); // ... other handle codes } panel.appendChild(fragment); }
  • 21. Naming Rule Variable 請用小寫名詞,如 : person, card 。 Function 請用小寫動詞開頭,如 : getName(), pushEvent() 。 假如 Function 會回傳一個 Boolean 值,請用 is 開頭,如 : isEnabled(), isVisible() 。 Constant 請用大寫及底線,如 : STATE, EVENT_TYPE 。 如果是 private 使用,可以在 Variable 及 Function 字首加上底 線。如 : _target, _getElement() 。 HTML Element 的 class name 、寫入 Cookie 或發送 HTTP Request 的參數名稱請用底線 '_' 區隔單字。如 : 'window_panel', 'personal_setting', 'widget_position' 。
  • 22. Convention Rule 在 JavaScript 裡,字串用單引號標示,在 HTML 裡用雙引號 標示。當規則定下來之後,如果有一天需要把 HTML element 改由 JavaScript 動態產生,就可以直接覆製 HTML code 到 JavaScript 字串變數裡,不需再擔心單雙引號相衝的問題。 縮排 Tab 改用空白取代。這是為了防止當很多人一起改 code 時,程式碼會因為每個人的編輯器不同, Tab 所表示的空白 字元數不同,而導致程式碼縮排不一致變的亂七八糟。 // in JavaScript var str = 'Hello World'; // in HTML <div class=“err-msg“></div> // 假如必須要在 JavaScript 裡直接寫 HTML code var html = '<div class=“err-msg“></div>';
  • 23. 利用 Ant 將 JavaScript 及 CSS 檔案串接 介紹文章 : http://www.julienlecomte.net/blog/2007/09/16/ 好處 : 將多個 JavaScript 或 CSS 檔案串接成為一個檔案後,可 以減少 Browser 透過網路戴入的次數 (requests) 。進而加快頁 面的瀏覽速度。使用此方法串接 js 檔案時,需注意先後順序, 如同 <script> import js file 一般。 <?xml version="1.0" encoding="UTF-8"?> <project basedir="." default="js.concatenate" name="JS Concatenation"> <!-- the directory to output to --> <property name="build.dir" value="./js" /> <!-- the directory containing the source files --> <property name="src.dir" value="./dev/src" /> <!-- Target to concatenate all js files --> <target name="js.concatenate"> <concat destfile="${build.dir}/concatenated/all.js"> <filelist dir="${src.dir}/js" files="a.js, b.js"/> <fileset dir="${src.dir}/js" includes="**/*.js" excludes="a.js, b.js"/> </concat> </target> </project>
  • 25. JavaScript 推薦書籍 Professional JavaScript for Web Developers, 2/e JavaScript: The Good Parts Pro JavaScript Design Patterns