$30 off During Our Annual Pro Sale. View Details »

進階 JavaScript

進階 JavaScript

Ping-Yen Tsai

July 05, 2013
Tweet

More Decks by Ping-Yen Tsai

Other Decks in Technology

Transcript

  1. 進階 JavaScript
    蔡秉諺
    1

    View Slide

  2. JavaScript 歷史
    • Netscape 發明
    • 1995 年
    • 原名 LiveScript
    • Navigator 2.0 Beta 裡

    View Slide

  3. Netscape 看 Java 那麼紅
    • 想取代 Java Applet
    • LiveScript 改名 JavaScript
    • 語法往 Java 靠攏
    • Sun 抗議
    • Netscape 不理
    • JavaScript !== Java
    Java 和 JavaScript 都是 1995 年⾯面世

    View Slide

  4. JavaScript !== Java
    • JavaScript 是
    • Java 的 syntax
    • Scheme 的 function
    • Self 的 prototype
    • Perl 的 regular expression
    • …
    • 四不像

    View Slide

  5. Netscape 把 JavaScript 提交 ECMA
    • ECMA
    • European Computer Manufacturers Association
    • 1996 年
    • 變成⼯工業標準
    • Standard ECMA-262
    • ECMAScript

    View Slide

  6. JavaScript 外依 ECMAScript 實作的語⾔言
    • ActionScript
    • 1998 年
    • ⽤用在 Flash 裡

    View Slide

  7. 微軟 vs. Netscape
    • 1996 年
    • IE 3.0 同時內建 VBScript JScript
    • VBScript
    • 語法類似 VB
    • JScript
    • 依 ECMAScript 實作
    <br/><script type="text/vbscript" ><br/><script ><br/>

    View Slide

  8. ECMAScript 版本
    • 第 1 版 1997/6
    • 第 2 版 1998/6
    • 第 3 版 1999/12
    • 第 4 版 放棄
    • 第 5 版 2009/12
    • 第 5.1 版 2011/6
    • 第 6 版 進⾏行中

    View Slide

  9. ECMAScript 新版舊版相⽐比
    • 新版
    • 只多東⻄西
    • 不少東⻄西
    • 向下相容
    • 往 Self 或 Java 靠攏?
    • ECMAScript 5 compatibility table
    • ECMAScript 6 compatibility table

    View Slide

  10. 安裝 Google Chrome
    • https://www.google.com/chrome

    View Slide

  11. 開啟 JavaScript 控制台
    • 開啟⽅方式
    • 右上選單按鈕 -> ⼯工具 -> JavaScript 控制台
    • 滑⿏鼠右鍵 -> 檢查元素 -> 左下 Show Console

    View Slide

  12. 玩 JavaScript 控制台
    > 1 + 1
    2
    > var a = 1;
    undefined
    > a
    1
    > alert(a);
    undefined
    > window
    Window
    下⼀一⾏行顯⽰示的是什麼?


    就好像在程式碼前加上 var x = 

    變成 var x = 1 + 1

    然後把 x 的值顯⽰示在下⼀一⾏行
    網址 about:blank 就是⼀一個

    乾淨的 JavaScript 環境

    View Slide

  13. 安裝 Notepad++
    • http://notepad-plus-plus.org/
    • 新增 內容寫
    <br/>// JavaScript 打這裡<br/>
    • 儲存為 demo.html
    • ⽤用 Chrome 開啟

    View Slide

  14. console.log
    • 結果顯⽰示在 JavaScript 控制台
    <br/>console.log(document);<br/>
    • Console API Reference - Chrome DevTools

    View Slide

  15. jsFiddle
    • http://jsfiddle.net/
    • 試試
    • Run
    • Save
    • Choose Framework

    View Slide

  16. Core JavaScript
    Client-side
    JavaScript
    Core
    JavaScript
    Server-side
    JavaScript
    Core
    JavaScript
    JScript .NET
    Core
    JavaScript

    View Slide

  17. 假設⾄至少會⼀一類 C 語⾔言
    • 類 C 語⾔言
    • C 、 C++ 、 C# 、 Java
    • 講 JavaScript 與其它類 C 語⾔言不同之處

    View Slide

  18. JavaScript 資料型態
    • 五個 Primitive type
    • number
    • string
    • boolean
    • null
    • undefined
    • 其它都是物件
    • Object
    • Function
    • Array
    • …

    View Slide

  19. number
    • 值 float 沒有型態 int
    • 10 進位 1234567
    • 8 進位 01234567
    • 16 進位 0x1234567
    • 科學記數法 1.234567E6
    • IEEE 754
    • 精準度只到 15 位
    • 9999999999999999 不準
    parseInt('010');
    // ECMAScript 5 前吐 8
    // ECMAScript 5 後吐 10
    1.1 + 1.1 + 1.1
    // 3.3000000000000003
    FOR 迴圈注意

    View Slide

  20. string
    • 沒有型態 char
    • 只有⻑⾧長度為 1 的 string
    • 'a'
    • 單雙引號括起皆可
    • "abc"
    • 'abc'
    • 特殊字元
    • \n \r \t \' \" \\

    View Slide

  21. string
    • string 中的單⼀一字元
    • ⽤用 8 進位表⽰示
    • \101 A
    • \251 ©
    • ⽤用 16 進位表⽰示
    • \x41 A
    • \xA9 ©
    • ⽤用 Unicode 表⽰示
    • \u0041 A
    • \u4E2D 中
    • UTF-16 Big Endian
    > 'abc\u4E2Dxyz'
    "abc中xyz"
    https://graph.facebook.com/pingyen.tsai

    View Slide

  22. boolean
    • true / false

    View Slide

  23. null 與 undefined
    • 是資料型態 也是資料型態唯⼀一的值
    • not defined 和 undefined 不⼀一樣
    • not defined 是 JavaScript 錯誤
    var a;
    alert(a); // undefined
    var b = null;
    alert(b); // null
    b = undefined;
    alert(b); // undefined
    alert(c); // ReferenceError: c is not defined

    View Slide

  24. Object
    • 除了 Primitive type 外 都是 Object
    • Array Function 也是 Object
    • Object 最⼤大特性 可以有屬性
    • Primitive type 不可以有屬性
    var a = 1;
    a.b = 2;
    alert(a.b); // undefined
    var a = new Object();
    a.b = 2;
    alert(a.b); // 2
    沒有錯誤訊息 但寫不進去

    View Slide

  25. Object 屬性的兩種存取語法
    • 點 . 和中括號 []
    • o.p o['p'] 意義相同
    • 注意 [ ] 裡是字串
    • 屬性名稱可以包含任意字元
    var o = new Object();
    o.p = 1;
    alert(o.p); // 1
    o['p'] = 2;
    alert(o['p']); // 2
    alert(o.p); // 2
    var str = 'p';
    alert(o[str]); // 2
    別⽤用 eval('o.' + str)
    o['………'] = 2;
    alert(o['………']); // 2

    View Slide

  26. Object 屬性的值可以是任何東⻄西
    • 可以是 number string boolean null undefined

    Object Array Function … 任何東⻄西
    var o = new Object();
    o.p = 1;
    o.p = 'abc';
    o.p = true;
    o.p = new Object();
    o.p = new Array();
    o.p = function() { alert('!'); };

    View Slide

  27. Object 屬性可以動態新增修改刪除
    var o = new Object();
    o.p = 1;
    o.p = function(){ alert('f'); }
    o.p(); // f
    delete o.p; // delete(o.p)

    View Slide

  28. Object 屬性不存在是 undefined
    • 變數不存在是 JavaScript 錯誤 not defined
    var o = new Object();
    alert(o.p); // undefined
    o.p = 1;
    alert(o.p); // 1
    delete o.p;
    alert(o.p); // undefined
    alert(a); // ReferenceError: a is not defined

    View Slide

  29. Object 依 Reference Copy Compare Pass
    • Primitive type 依 value Copy Compare Pass
    • string 也是依 value
    var o = new Object(),
    o2 = o;
    alert(o.p); // undefined;
    o2.p = 1;
    alert(o.p); // 1
    var o = new Object();
    f(o);
    alert(o.p); // 1
    function f(o) { o.p = 1; }
    var a = 1;
    f(a); // Pass by value
    alert(a); // 1
    function f(a) { a += 2; }
    var str = 'abc',
    str2 = 'abc';
    alert(str === str2); // true

    View Slide

  30. 以上物件特性全部物件適⽤用
    • 所以 Object 、 Array 、 Function … 都
    • 可以有屬性
    • 可以動態新增修改刪除屬性
    • 依 Reference Copy Compare Pass
    • …

    View Slide

  31. Object 實字
    • 實字的英⽂文 Literal
    • 檔案較⼩小 效能較佳
    • JSON 學 Object 實字
    var o = new Object();
    var o2 = new Object();
    o2.p = 1;
    o2.q = 'abc';
    var o3 = new Object();
    o3['…'] = true;
    var o = {};
    var o2 = { p : 1, q : 'abc' };
    var o3 = { '…' : true };
    左右兩邊意義相同

    View Slide

  32. 把 Object 當 Java Map ⽤用
    var salaryMap = {
    john : 1000,
    mary : 1200
    };
    salaryMap.peter = 1500;
    var name = 'mark',
    amount = 2000;
    salaryMap[name] = amount;
    if(salaryMap[name] !== undefined)
    alert(salaryMap[name]);
    for(var n in salaryMap) {
    alert(n);
    alert(salaryMap[n]);
    }
    delete salaryMap[name];

    View Slide

  33. Exercise 中華電信苗栗市服務據點
    • http://www.cht.com.tw/portal/Location
    • 建⽴立物件 chtMap 據點名稱當屬性名稱 據點地址當屬性值
    • 查有沒有據點苗栗府前特約服務中⼼心
    • 依序 alert 出 chtMap 中的據點名稱和地址
    • 把 chtMap 的屬性值改為物件 記下據點的地址和電話
    • 依序 alert 出 chtMap 中的據點名稱、地址、電話

    View Slide

  34. JavaScript 是 Dynamic type
    • Static type
    • 變數型態不能改變
    • 例 Java 、 C 、 C# …
    • Dynamic type
    • 變數型態可以改變
    • 例 JavaScript 、 PHP …
    • JavaScript ⽤用中性詞 var 宣告變數
    • JavaScript 物件屬性同變數
    int v = 1;
    v = "abc";
    error
    var v = 1;
    v = 'abc';
    v = function() { alert('f'); }
    v(); // f

    View Slide

  35. ⽤用 typeof 取得變數值資料型態
    var a = 1;
    alert(typeof(a)); // number
    alert(typeof a); // number
    var b = {};
    if(typeof b === 'object')
    alert('b is an object.');
    typeof 回傳資料型態的字串

    View Slide

  36. ⽤用 typeof 判斷變數宣告沒
    alert(a); // ReferenceError: a is not defined JavaScript error 程式執⾏行中斷
    if(a) // ReferenceError: a is not defined
    alert(a);
    JavaScript error 程式執⾏行中斷
    if(typeof a !== 'undefined')
    alert(a);
    not defined 的資料型態是 undefined

    View Slide

  37. JavaScript 是 Weak typing
    • 資料型態不符
    • 會依 JavaScript 覺得對的⽅方式⾃自動轉型
    • Weak typing 相反是 Strong typing
    • 例 Java 、 C 、 C# …
    var str = 'abc';
    alert(str.charAt(1)); // b
    ⾃自動轉型 str -> new String(str) 

    (new String(str)).charAt(1) string -> String
    number -> Number
    boolean -> Boolean
    var n = 1;

    n.toString();
    int n = 1;

    (new Integer(n)).toString();
    Java vs.
    JavaScript

    View Slide

  38. JavaScript ⾃自動轉型
    • string 加法運算 ⾃自動轉型 string
    • 減乘除運算 ⾃自動轉型 number
    • if( ) 中
    • 0 NaN '' null undefinied ⾃自動轉型 false
    • 其餘皆⾃自動轉型 true
    • {} [] ' ' …
    alert(1 + '2'); // 12
    alert(1 - '2'); // -1

    alert('1' * 2); // 2

    alert('1' / '2'); // 0.5

    View Slide

  39. NaN
    • not a number
    • 減乘除運算 ⾃自動轉型 number
    • 結果常是 NaN
    alert(1 - 'A'); // NaN
    alert(typeof NaN); // number
    alert(NaN === NaN); // false
    alert(isNaN(NaN)); // true
    和 NaN 做數字運算 結果恆 NaN
    NaN 是⼀一個數字
    NaN 不等於任何東⻄西
    請⽤用 isNaN( ) 判斷是不是 NaN

    View Slide

  40. JavaScript 覺得對的⽅方式⾃自動轉型
    • JavaScript 覺得對 !== 你覺得對
    • 稀奇古怪靈異事件⼀一⼤大堆
    • http://zero.milosz.ca/
    • http://wtfjs.com/

    View Slide

  41. JavaScript 運算⼦子
    • 與 C C++ C# Java ⼤大致相同
    • 注意⾃自動轉型
    • == != ⾃自動轉型後⽐比較
    • === !== 資料型態相同⽐比較
    • 效能較佳

    View Slide

  42. JavaScript 運算⼦子 && ||
    • 不是回傳 true false
    • 回傳結果確⽴立當下的運算元
    • if() 裡⾯面 ⾃自動轉型 true false
    alert(0 && 'a'); // 0
    alert(1 && 'a'); // 'a'
    alert(0 || 'a'); // 'a'
    alert(1 || 'a'); // 1
    var a = b ? b : '1'; var a = b || '1';
    結果⼀一樣

    效能較佳
    變數 b 需已宣告

    View Slide

  43. Core JavaScript 事先定義物件
    • Object Number String Boolean
    • Array Function Date Math RegExp
    • http://w3schools.com/
    • Google 搜尋 w3shools Math
    • Client-side 中除了以上物件 都是 DOM 物件

    View Slide

  44. Array
    • Array 內元件不需同⼀一資料型態
    var arr = new Array();
    alert(arr.length); // 0
    arr[0] = 'abc';
    arr[1] = true;
    arr[2] = 10;
    alert(arr.length); // 3

    View Slide

  45. Array
    • new Array() 時傳⼊入參數
    • 如只傳⼊入⼀一個參數 且型態為 number
    • 是設定 Array ⻑⾧長度
    • 反之
    • 是設定 Array 內元件
    var arr = new Array(10);
    alert(arr.length); // 10
    alert(arr[0]); // undefined
    var arr = new Array(10, 'abc', true);
    alert(arr.length); // 3
    alert(arr[0]); // 10
    alert(arr[1]); // abc
    alert(arr[2]); // true
    var arr = new Array('10');
    alert(arr.length); // 1
    alert(arr[0]); // 10

    View Slide

  46. Array length
    var arr = new Array('abc',
    'xyz');
    arr[9] = 100;
    alert(arr.length); // 10
    alert(arr[5]) // undefined
    var arr = new Array('a', 'b',
    'c');
    arr.length = 10;
    alert(arr.length); // 10
    var arr = new Array('a', 'b', 'c', 'd', 'e');
    alert(arr[3]); // 'd'
    arr.length = 3;
    alert(arr.length); // 3
    alert(arr[3]); // undefined
    Array length 可以寫
    截短陣列 改 length 即

    View Slide

  47. 分辨 Array 屬性和索引
    • Array 也是物件 ⼀一樣可以有屬性
    • 何時是屬性?何時是索引?
    • 試著把 [ ] 內 string 轉成 number
    • 結果為 NaN 視為屬性 反之索引
    var arr = new Array();
    arr['a'] = 'abc';
    alert(arr.a); // abc
    alert(arr.length); // 0
    arr[0] = 'xyz';
    alert(arr.length); // 1
    arr['1'] = 100;
    alert(arr.length); // 2
    alert(arr[1]); // 100

    View Slide

  48. Array 實字
    • 檔案較⼩小 效能較佳
    • JSON 學 Array 實字
    左右兩邊意義相同
    var arr = new Array();
    var arr2 = new Array('abc', 1, true);
    var arr = [];
    var arr2 = ['abc', 1, true];
    var arr = [100];
    alert(arr.length); // 1
    alert(arr[0]); // 100
    沒有傳⼊入⼀一個參數問題

    View Slide

  49. RegExp
    • Google 搜尋 RegExp
    • Regular Expression (RegExp) in JavaScript
    • RegExp 實字
    • 檔案較⼩小 效能較佳
    • JSON 沒有學 RegExp 實字
    左右兩邊意義相同
    var re = new RegExp('CHT');
    var re2 = new RegExp('CHT', 'g');
    var re3 = new RegExp('CHT', 'gi');
    var re = /CHT/;
    var re2 = /CHT/g;
    var re3 = /CHT/gi;

    View Slide

  50. Exercise w3schools Date
    • 請⽤用 Google 搜尋 w3schools Date
    • 利⽤用 w3schools 說明完成
    • alert 格式 yyyy/mm/dd 的今天⽇日期
    • 利⽤用 Date.parse() 處理
    • 2012/12/21
    • 2012-12-21
    • 2012-13-21
    • 並判斷結果是否可⽤用

    View Slide

  51. Function
    • Function 也是物件 物件特性都適⽤用
    var f = new Function('x', 'y', 'return x + y');
    alert(f(1, 2)); // 3
    注意!傳⼊入參數是 string
    幾乎沒⼈人這樣⽤用

    因為不習慣 且效能較差

    多半⽤用 Function 實字

    View Slide

  52. Function 實字

    View Slide

  53. Function 實字
    • Function Declaration
    • Function Expression
    • 宣告函式的同時將 Function Reference 丟出
    alert(f(1, 2)); // 3
    function f(x, y) { return x + y; }
    var f = function(x, y) { return x + y; }
    alert(f(1, 2)); // 3
    alert(f(1, 2)); // ReferenceError: f is not defined
    var f = function(x, y) { return x + y; }
    等於在 excution context 的最上⽅方寫

    var f = function(x, y) { return x + y; }

    View Slide

  54. Function Expression
    • Anonymous Function Expression
    • Named Function Expression
    • IE9 與 IE9 以下有 bug
    var f = function(x, y) { return x + y; }
    var f = function g () {
    alert(typeof f); // function
    alert(typeof g); // function
    }
    alert(typeof f); // function
    alert(typeof g); // undefined
    f(); IE9 與 IE9 以下會跳
    function

    View Slide

  55. Anonymous Function (Expression)
    var a = [1, 3, 2, 5, 4];
    function compare(a, b){
    return a - b;
    }
    a.sort(compare);
    alert(a); // 1,2,3,4,5
    var a = [1, 3, 2, 5, 4];
    a.sort(function(a, b) {
    return a - b;
    });
    alert(a); // 1,2,3,4,5
    JavaScript sort() Method – W3Schools

    View Slide

  56. ⾃自我執⾏行的 Anonymous Function
    (function() {
    /* 乾淨的變數空間 */
    var a = 1;
    })();
    alert(a); // ReferenceError: a is not defined
    var a =
    (function(x) {
    return x * 10;
    })(10);
    alert(a); // 100
    以 jQuery 為例

    View Slide

  57. Function 參數個數不受限
    function f(a, b, c) {
    alert(a);
    alert(b);
    alert(c);
    }
    f(1); // 1, undefined,
    undefined
    f(1, 2, 3, 4); // 1, 2, 3

    View Slide

  58. Function 也可以當參數傳遞
    function f() { alert('!'); }
    var g = f;
    g(); // !
    function f() { alert('!'); }
    function g(a) { a(); }
    g(f); // !

    View Slide

  59. arguments 存取參數
    • arguments 是 Array-like 物件
    • 也就是不是 Array
    • Array 的屬性除 length 外皆無
    • length 使⽤用⽅方式同 Array length
    • Google 搜尋 arguments MDN
    function g() { alert('!'); }
    f(1, 2, g, 4);
    function f() {
    alert(arguments.length); // 4
    alert(arguments[1]); // 2
    arguments[2](); // !
    }

    View Slide

  60. arguments 與函式 Parameter 可並存
    f(1, 2, 3, 4);
    function f(x, y, z) {
    alert(z); // 3
    alert(arguments[2]); // 3
    alert(arguments[3]); // 4
    }

    View Slide

  61. Anonymous Function 也可以遞迴
    • arguments.callee 指向函式⾃自⼰己本⾝身
    var ans = (function(n) { // factorial
    if(n <= 1)
    return 1;
    return n * arguments.callee(n - 1);
    })(3);
    alert(ans); // 6
    var ans = (function m (n) { // factorial
    if(n <= 1)
    return 1;
    return n * m(n - 1);
    })(3);
    alert(ans); // 6
    alert(typeof m); // undefined
    arguments.callee 效能較差 多⽤用 Named Function Expression 取代
    ECMAScript 5 Strict Mode 移除
    arguments.callee

    View Slide

  62. 給予 Function 參數初始值
    function f(a, b, c) {
    a = a || 'xyz';
    b = b || 100;
    c = c !== undefined ? c : 100;
    alert(a + ', ' + b + ', ' + c);
    }
    f(); // xyz, 100, 100
    f('CHT'); // CHT, 100, 100
    f('CHT', 0, 0); // CHT, 100, 0
    記得考量 falsy value

    View Slide

  63. 函式中宣告變數不寫 var 會變全域變數
    (function() {
    var a = 1;
    })();
    alert(a); // ReferenceError: a is not defined
    (function() {
    a = 1;
    })();
    alert(a); // 1
    左右就差⼀一個 var

    View Slide

  64. Function 中的 this
    • 和函式本⾝身無關 和函式被呼叫的⽅方式有關
    function f() { alert(this.p); }
    var a = { p : 1, m : f },
    b = { p : 2, m : f };
    a.m(); // 1
    b.m(); // 2
    f(); // undefined

    View Slide

  65. ⽤用 call() apply() 指定 Function 中的 this
    function f()
    { alert(this.p); }
    var a = { p : 1, m : f },
    b = { p : 2, m : f };
    f.call(a); // 1
    f.apply(a); // 1
    a.m.call(b); // 2
    a.m.apply(b); // 2
    第⼀一個參數指定函式中 this

    View Slide

  66. call() apply() 差別
    function f(x, y) { alert(this.p + x + y); }


    var a = { p : 1, m : f };

    f.apply(a, [3, 4]); // 8
    f.call(a, 3, 4); // 8
    要傳進函式 f 的參數
    併為⼀一陣列 做為 apply 第⼆二個參數
    要傳進函式 f 的參數
    依序做為 call 第⼆二三個參數

    View Slide

  67. apply() 常搭配 arguments 使⽤用
    function f(x, y) { alert(this.p + x + y); }
    var a = { p : 1, m : f };
    g(3, 4); // 6
    function g() {
    arguments[0] -= 2;
    f.apply(a, arguments);
    }
    ⾃自動轉型 Array 物件

    View Slide

  68. 未指定函式中 this 時
    • ECMAScript 5 Strict Mode 下 this 是 undefined
    • 反之 this 是 Global Object
    • Global 變數就是 Global Object 的屬性
    • Client-side 的 Global Object 是 window
    function f() { alert(this.p); }
    f(); // undefined
    var p = 1;
    f(); // 1
    alert(window.p); // 1
    "use strict";
    function f() { alert(this); }
    f(); // undefined

    View Slide

  69. Exercise apply()
    • 現有 square() sum() 兩函式如右
    • 請寫⼀一函式 calculate()
    • 傳⼊入參數個數不定
    • 利⽤用 square() sum() 搭配 apply()
    • 計算傳⼊入參數個別平⽅方後總合
    function square() {
    var n = arguments.length;
    for(var i = 0; i < n; ++i)
    arguments[i] *= arguments[i];
    return arguments;
    } 把傳⼊入參數都平⽅方
    function sum() {
    var sum = 0,
    n = arguments.length;
    for(var i = 0; i < n; ++i)
    sum += arguments[i];
    return sum;
    }
    把傳⼊入參數加總

    View Slide

  70. Function 裡還可以寫 Function
    function f() {
    g();
    function g() {
    alert(1);
    }
    }
    f(); // 1
    g(); // ReferenceError: g is not defined
    外⾯面看不⾒見
    裡⾯面的函式

    View Slide

  71. 裡⾯面 Function 的宣告⽅方式
    f();
    function f() {
    g(); // 1
    function g() { alert(1); }
    }
    f();
    function f() {
    var g = function() { alert(1); }
    g(); // 1
    }
    f();
    function f() {
    g(); // ReferenceError: g is not defined
    var g = function() { alert(1); }
    }
    等於在 excution context 的最上⽅方寫

    var g = function() { alert(1); }

    View Slide

  72. 裡⾯面的函⽰示可以存取外⾯面函⽰示的變數
    • 外⾯面函式存取不到裡⾯面函式的變數
    f();
    function f() {
    var c = 0;
    g();
    alert(c); // 1
    g();
    alert(c); // 2
    function g() { ++c; }
    }

    View Slide

  73. 裡外函式⼀一樣名稱變數 裡⽤用裡 外⽤用外
    f();
    function f() {
    var c = 0;
    g();
    alert(c); // 0
    function g() {
    alert(c); // undefined
    var c = 1;
    alert(c); // 1
    }
    }
    alert(c); // undefined
    var c = 1;
    var c;
    alert(c); // undefined
    c = 1;
    JavaScript 直譯成
    等同宣告於 excution context 的最
    上⽅方

    View Slide

  74. Closure = 函式 + 函式外變數
    • 函式外變數的⽣生存期間
    • 變成和函式的⽣生存期間綁在⼀一起
    function f() {
    var c = 0;
    function g() { ++c; }
    }
    函式 g ⽣生存期間與函式 f 執⾏行期間⼀一樣
    var h = f();
    function f() {
    var c = 0;
    function g() { ++c; }
    return g;
    }
    函式 g ⽣生存期間與函式 f 執⾏行期間不⼀一樣
    變數 c 和函式 g ⽣生存期間綁⼀一起

    View Slide

  75. Closure 實例
    var h1 = f();
    h2 = f();
    h1(); // 1
    h1(); // 2
    h2(); // 1
    function f() {
    var c = 0;
    function g() { alert(++c); }
    return g;
    }
    函式 f 第⼀一次執⾏行
    產⽣生了第⼀一份變數 c 、函式 g 與 Closure
    第⼀一份函式 g 被回傳給 h1
    函式 f 第⼆二次執⾏行
    產⽣生了第⼆二份變數 c 、函式 g 與 Closure
    第⼆二份函式 g 被回傳給 h2
    第⼀一份變數 c 、函式 g 與 Closure

    第⼆二份變數 c 、函式 g 與 Closure
    是完全分開、各⾃自獨⽴立的

    View Slide

  76. Closure 匿名函式化
    var h = f();
    function f() {
    var c = 0;
    function g() { ++c; }
    return g;
    }
    var h = (function() {
    var c = 0;
    return function() { ++c; }
    })();
    ⾃自我執⾏行的匿名函式

    View Slide

  77. Global 變數與 Closure 實作⽐比較
    var c = 0;
    var h = function() { alert(++c); };
    h(); // 1
    h(); // 2
    h(); // 3
    var h = (function() {
    var c = 0;
    return function() { alert(++c); };
    })();
    h(); // 1
    h(); // 2
    h(); // 3
    ⼤大家都存取得到 Closure 外存取不到

    View Slide

  78. Scope chain
    • 先找⺫⽬目前 Function 有無此變數
    • 如無⼀一層⼀一層往外找
    • 太多層 影響效能
    • 宣告變數 記得寫 var
    var a = 1;
    f();
    function f() {
    var b = 2;
    g();
    function g() {
    var c = 3;
    h();
    function h() {
    var d = 4;
    alert(d); // 4
    alert(c); // 3
    alert(b); // 2
    alert(a); // 1
    }
    }
    }

    View Slide

  79. Scope chain
    • 避免太多層 影響效能
    • 以 jQuery 為例
    • 需考量使⽤用情境
    var c = 0;
    f(c); // 1
    f(c); // 1
    function f(c) {
    ++c;
    alert(c);
    }
    var c = 0;
    f(); // 1
    f(); // 2
    function f() {
    ++c;
    alert(c);
    }
    (function( window, undefined ) {

    // ...

    window.jQuery = window.$ = jQuery;

    // ...

    })( window );

    View Slide

  80. Closure 實例
    • 可達成近似 Java Class Private Member 效果
    • JavaScript ⺫⽬目前還不⽀支援 Class 繼承
    • Google Maps JavaScript API v3 範例
    • Using closures in event listeners
    • Vexed's Blog 搜尋 Closure
    • http://blog.xuite.net/vexed

    View Slide

  81. Exercise 匿名函式 Closure
    • 請利⽤用匿名函式 Closure 寫⼀一函式
    • 第⼀一次執⾏行 alert 2 的 1 次⽅方是 2
    • 第⼆二次執⾏行 alert 2 的 2 次⽅方是 4
    • 第三次執⾏行 alert 2 的 3 次⽅方是 8
    • … 以此類推
    • 只可有此函式 不得有其它 Global 變數

    View Slide

  82. Constructor
    • 任何 Function 都可以當 Constructor
    • 前⾯面加 new 即可
    function Cat(name) { this.name = name; }
    var cat1 = new Cat('kitty'),
    cat2 = new Cat('lucky');
    alert(cat1.name); // kitty
    alert(cat2.name); // lucky
    alert(cat1 instanceof Cat); // true
    alert(cat1.constructor); // function Cat(name) { … }

    View Slide

  83. 函式當 Constructor ⽤用前⾯面記得寫 new
    • 除 ECMAScript 5 Strict Mode 下 this 為 undefined 外
    • 沒寫 new 不會有錯誤訊息
    function Cat(name) { this.name = name; }
    var cat1 = Cat('kitty');
    alert(cat1); // undefined
    alert(name); // kitty
    ECMAScript 5 Strict Mode 外

    this 是 Global 物件

    Global 物件的屬性就是 Global 變數
    所以變成設定 Global 變數 name

    View Slide

  84. 如果當 Constructor 的函式回傳物件
    • new 出來的是回傳的物件
    function Cat(name) {

    this.name = name;

    return { p : 1 }

    }


    var cat1 = new Cat('kitty');


    alert(cat1.name); // undefined

    alert(cat1.p); // 1

    alert(cat1 instanceof Cat); // false

    alert(cat1.constructor); // function
    Object() { … }

    View Slide

  85. Coding Style 區分 Constructor 函式
    • Constructor 函式
    • 名稱開頭字⺟母⼤大寫
    • 不 return
    • Core JavaScript 事先定義物件 Date
    • 可當 Constructor 使⽤用 也可不當
    var d = new Date();
    alert(d.constructor); // function Date() { ... }
    var d2 = Date();
    alert(d2); // Mon Jul 16 2012 00:45:25 GMT+0800 (台北標準時間)

    View Slide

  86. Prototype 繼承
    • Prototype 是 JavaScript 的繼承⽅方式
    • Java 的繼承⽅方式是 Class
    • ECMAScript 6 有考慮也⽀支援 Class 繼承
    • 但⺫⽬目前沒有任何瀏覽器⽀支援
    • ECMAScript 6 compatibility table
    • 其它 Prototype 繼承的語⾔言多死光了
    • Prototype-based_programming - Wikipedia, the free
    encyclopedia

    View Slide

  87. 使不使⽤用 Prototype ⽐比較
    function Cat(name) {
    this.name = name;
    this.meow = function() {
    alert('meow');
    }
    }
    var cat1 = new Cat('kitty'),
    cat2 = new Cat('lucky');
    cat1.meow() // meow
    cat2.meow() // meow
    alert(cat1.meow === cat2.meow); // false
    function Cat(name) {
    this.name = name;
    }
    Cat.prototype.meow = function() {
    alert('meow');
    }
    var cat1 = new Cat('kitty'),
    cat2 = new Cat('lucky');
    cat1.meow() // meow
    cat2.meow() // meow
    alert(cat1.meow === cat2.meow); // true
    未使⽤用 Prototype
    cat1.meow 和 cat2.meow
    指向記憶體中不同函式
    使⽤用 Prototype
    cat1.meow 和 cat2.meow
    指向記憶體中同⼀一函式
    meow 指到 function 沒那麼簡單

    View Slide

  88. prototype 與 __proto__
    • 每個 Function 都有
    • ⼀一個 enumerable 為 false 的屬性 prototype 指向⼀一物件
    • 此物件有⼀一屬性 constructor 指向 Function 本⾝身
    enumerable 為 false 就是

    for … in 不會跳出的屬性
    function Cat(name) {
    this.name = name;
    }
    alert(Cat.prototype); // [object Object]
    alert(Cat.prototype.constructor === Cat); // true

    View Slide

  89. prototype 與 __proto__
    • 把 Function 當 Constructor 執⾏行
    • JavaScript 偷多執⾏行
    • 新物件.__proto__ = 函式.prototype
    __proto__ 也是 enumerable 為 false 屬性
    function Cat(name) {
    this.name = name;
    }
    var cat1 = new Cat('kitty');
    alert(cat1.__proto__ === Cat.prototype); // true

    View Slide

  90. prototype 與 __proto__
    • 當要取的物件屬性不存在時
    • 會到 __proto__ 所指物件上找
    function Cat(name) { this.name = name; }
    alert(Cat.prototype); // [object Object]
    Cat.prototype.meow = function() { alert('meow'); }
    var cat1 = new Cat('kitty');
    alert(cat1.__proto__ === Cat.prototype); // true
    cat1.meow() // meow
    alert(cat1.meow === cat1.__proto__.meow); // true
    alert(cat1.__proto__.meow === Cat.prototype.meow); // true

    View Slide

  91. prototype 與 __proto__
    function Cat(name) { this.name = name; }
    alert(Cat.prototype); // [object Object]
    alert(Cat.prototype.constructor); // function Cat(name) { ... }
    Cat.prototype.meow = function() { alert('meow'); }
    var cat1 = new Cat('kitty');
    alert(cat1.__proto__ === Cat.prototype); // true
    alert(cat1.__proto__.constructor); // function Cat(name) { ... }
    cat1.meow() // meow
    alert(cat1.constructor); // function Cat(name) { ... }

    View Slide

  92. prototype 與 __proto__
    • 只有取物件屬性不存在時會到 __proto__ 所指物件找
    • 存物件屬性的時候不會 function Cat(name) { this.name = name; }
    Cat.prototype.meow = function()
    { alert('meow'); }
    var cat1 = new Cat('kitty'),
    cat2 = new Cat('lucky');
    cat1.meow(); // meow
    cat2.meow(); // meow
    cat2.meow = function() { alert('bark'); }
    cat2.meow(); // bark
    cat1.meow(); // meow

    View Slide

  93. prototype 與 __proto__
    • 只有取物件屬性不存在時
    • 會到 __proto__ 所指物件找
    • 刪物件屬性的時候不會
    function Cat(name) { this.name = name; }
    Cat.prototype.meow = function() { alert('meow'); }
    var cat1 = new Cat('kitty');
    delete cat1.meow;
    cat1.meow(); // meow
    function Cat(name) {
    this.name = name;
    }
    Cat.prototype.meow = function() {
    alert('meow');
    }
    var cat1 = new Cat('kitty');
    cat1.meow = function() {
    alert('bark');
    }
    delete cat1.meow;
    cat1.meow(); // meow

    View Slide

  94. 是存還是取 只看到 Prototype 物件那⼀一層
    function Cat(name) { this.name = name; }
    Cat.prototype.bag = {};
    var cat1 = new Cat('kitty');
    // var cat1Bag = cat1.bag;
    // cat1Bag.money = 5;
    cat1.bag.money = 5;
    alert(Cat.prototype.bag.money); // 5
    意義相同
    先取 cat1.bag
    再設定 cat1.bag 所指物件的屬性 money

    View Slide

  95. hasOwnProperty
    • 判斷是⾃自⼰己的屬性
    • 還是 __proto__ 上找來的
    function Cat(name) { this.name = name; }
    Cat.prototype.meow = function()
    { alert('meow'); }
    var cat1 = new Cat('kitty'),
    cat2 = new Cat('lucky');
    alert(cat1.hasOwnProperty('meow')); // false
    alert(cat2.hasOwnProperty('meow')); // false
    cat2.meow = function() { alert('bark'); }
    alert(cat1.hasOwnProperty('meow')); // false
    alert(cat2.hasOwnProperty('meow')); // true

    View Slide

  96. 把 Function 的 prototype 屬性覆蓋
    • 把 Function 的 prototype 屬性
    • 覆蓋成另⼀一個物件
    • 記得物件屬性 constructor
    function Cat(name) { this.name = name; }
    Cat.prototype = {
    meow : function() { alert('meow'); },
    jump : function() { alert('jump'); },
    constructor : Cat
    }
    var cat1 = new Cat('kitty');

    View Slide

  97. 把 Function 的 prototype 屬性覆蓋
    function Cat(name) { this.name = name; }
    Cat.prototype = {
    meow : function() { alert('meow'); },
    jump : function() { alert('jump'); }
    }
    var cat1 = new Cat('kitty');
    alert(cat1.constructor); // function
    Object() { ... }
    忘記寫屬性 constructor
    cat1 找不到
    找 cat1.__proto__
    cat1.__proto__ 找不到

    cat1.__proto__.__proto__

    View Slide

  98. constructor 屬性⽤用處
    var cat1 = (function() {
    function Cat(name) {
    this.name = name;
    }
    return new Cat('kitty');
    })();
    var cat2 = new cat1.constructor('lucky');
    ⾃自我執⾏行的匿名函式
    外部存取不到 function Cat
    利⽤用 cat1.constructor 存取

    View Slide

  99. Prototype chain
    function Animal() { }
    Animal.prototype.sleep = function() { alert('sleep'); }
    function Cat(name) { this.name = name; }
    Cat.prototype = new Animal();
    Cat.prototype.meow = function() { alert('meow'); }
    Cat.prototype.constructor = Cat;
    var cat1 = new Cat('kitty');
    alert(cat1.name); // kitty
    cat1.meow(); // meow
    cat1.sleep(); // sleep
    先找 cat1
    找不到找 cat1.__proto__ 也就是 Cat.prototype
    找不到找 cat1.__proto__.__proto__ 也就是 Animal.prototype
    找不到找 cat1.__proto__.__proto__.__proto__也就 Object.prototype

    View Slide

  100. instanceof
    function Animal() { }
    Animal.prototype.sleep = function() { alert('sleep'); }
    function Cat(name) { this.name = name; }
    Cat.prototype = new Animal();
    Cat.prototype.meow = function() { alert('meow'); }
    Cat.prototype.constructor = Cat;
    var cat1 = new Cat('kitty');
    alert(cat1 instanceof Cat); // true
    alert(cat1 instanceof Animal); // true
    alert(cat1 instanceof Object); // true
    alert(cat1 instanceof Array); // false
    cat1.__proto__ === Cat.prototype 

    cat1.__proto__.__proto__ === Animal.prototype

    cat1.__proto__.__proto__.__proto__ === Object.prototype
    右運算元 prototype 屬性值
    在不在左運算元 Prototype chain 上

    View Slide

  101. isPrototypeOf
    function Animal() { }
    Animal.prototype.sleep = function() { alert('sleep');
    }
    function Cat(name) { this.name = name; }
    Cat.prototype = new Animal();
    Cat.prototype.meow = function() { alert('meow'); }
    Cat.prototype.constructor = Cat;
    var cat1 = new Cat('kitty');
    alert(Cat.prototype.isPrototypeOf(cat1)); // true
    alert(Animal.prototype.isPrototypeOf(cat1)); // true
    alert(Object.prototype.isPrototypeOf(cat1)); // true
    檢查物件在傳⼊入 isPrototypeOf 函式參數的 Prototype chain 上否
    每個物件都有⼀一個屬性名稱 isPrototypeOf 的函式
    isPrototypeOf 也是 enumerable 為 false 屬性

    View Slide

  102. 記住 __proto__ 屬性 new 時就綁定
    • Prototype chain 檢查的是 __proto__ 屬性串
    function Cat(name) { this.name = name; }
    var cat1 = new Cat('kitty');
    Cat.prototype = {
    meow : function() { alert('meow'); },
    jump : function() { alert('jump'); },
    constructor : Cat
    }
    alert(cat1 instanceof Cat); // false
    cat1.__proto__ !== 新的 Cat.prototype

    View Slide

  103. Exercise Prototype
    • 設計三個當 Constructor ⽤用的 Function
    • 分別叫 Organization 、 Company 、 CHT
    • 令 Company.protype 上有⼀一屬性 earnMoney
    • 屬性值為 function() { alert('earnMoney'); }
    • 令 Organization.protype 上有⼀一屬性 recruit
    • 屬性值為 function() { alert('recruit'); }
    • 令 Company 繼承 Organization 、 CHT 繼承 Company
    • 跑 var cht = new CHT(); cht.earnMoney(); cht.recruit();

    View Slide

  104. Vexed's Blog
    • http://blog.xuite.net/vexed
    • 站內搜尋
    • closure
    • prototype
    • anonymous
    • arguments.callee
    • function expression
    • strict mode

    View Slide