進階 JavaScript

進階 JavaScript

7067c01e5e98f8b8211343054a908076?s=128

Ping-Yen Tsai

July 05, 2013
Tweet

Transcript

  1. 進階 JavaScript 蔡秉諺 1

  2. JavaScript 歷史 • Netscape 發明 • 1995 年 • 原名

    LiveScript • Navigator 2.0 Beta 裡
  3. Netscape 看 Java 那麼紅 • 想取代 Java Applet • LiveScript

    改名 JavaScript • 語法往 Java 靠攏 • Sun 抗議 • Netscape 不理 • JavaScript !== Java Java 和 JavaScript 都是 1995 年⾯面世
  4. JavaScript !== Java • JavaScript 是 • Java 的 syntax

    • Scheme 的 function • Self 的 prototype • Perl 的 regular expression • … • 四不像
  5. Netscape 把 JavaScript 提交 ECMA • ECMA • European Computer

    Manufacturers Association • 1996 年 • 變成⼯工業標準 • Standard ECMA-262 • ECMAScript
  6. JavaScript 外依 ECMAScript 實作的語⾔言 • ActionScript • 1998 年 •

    ⽤用在 Flash 裡
  7. 微軟 vs. Netscape • 1996 年 • IE 3.0 同時內建

    VBScript JScript • VBScript • 語法類似 VB • JScript • 依 ECMAScript 實作 <script language="vbscript" > <script type="text/vbscript" > <script >
  8. ECMAScript 版本 • 第 1 版 1997/6 • 第 2

    版 1998/6 • 第 3 版 1999/12 • 第 4 版 放棄 • 第 5 版 2009/12 • 第 5.1 版 2011/6 • 第 6 版 進⾏行中
  9. ECMAScript 新版舊版相⽐比 • 新版 • 只多東⻄西 • 不少東⻄西 • 向下相容

    • 往 Self 或 Java 靠攏? • ECMAScript 5 compatibility table • ECMAScript 6 compatibility table
  10. 安裝 Google Chrome • https://www.google.com/chrome

  11. 開啟 JavaScript 控制台 • 開啟⽅方式 • 右上選單按鈕 -> ⼯工具 ->

    JavaScript 控制台 • 滑⿏鼠右鍵 -> 檢查元素 -> 左下 Show Console
  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 環境
  13. 安裝 Notepad++ • http://notepad-plus-plus.org/ • 新增 內容寫 <script> // JavaScript

    打這裡 </script> • 儲存為 demo.html • ⽤用 Chrome 開啟
  14. console.log • 結果顯⽰示在 JavaScript 控制台 <script> console.log(document); </script> • Console

    API Reference - Chrome DevTools
  15. jsFiddle • http://jsfiddle.net/ • 試試 • Run • Save •

    Choose Framework
  16. Core JavaScript Client-side JavaScript Core JavaScript Server-side JavaScript Core JavaScript

    JScript .NET Core JavaScript
  17. 假設⾄至少會⼀一類 C 語⾔言 • 類 C 語⾔言 • C 、

    C++ 、 C# 、 Java • 講 JavaScript 與其它類 C 語⾔言不同之處
  18. JavaScript 資料型態 • 五個 Primitive type • number • string

    • boolean • null • undefined • 其它都是物件 • Object • Function • Array • …
  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 迴圈注意
  20. string • 沒有型態 char • 只有⻑⾧長度為 1 的 string •

    'a' • 單雙引號括起皆可 • "abc" • 'abc' • 特殊字元 • \n \r \t \' \" \\
  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
  22. boolean • true / false

  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
  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 沒有錯誤訊息 但寫不進去
  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
  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('!'); };
  27. Object 屬性可以動態新增修改刪除 var o = new Object(); o.p = 1;

    o.p = function(){ alert('f'); } o.p(); // f delete o.p; // delete(o.p)
  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
  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
  30. 以上物件特性全部物件適⽤用 • 所以 Object 、 Array 、 Function … 都

    • 可以有屬性 • 可以動態新增修改刪除屬性 • 依 Reference Copy Compare Pass • …
  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 }; 左右兩邊意義相同
  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];
  33. Exercise 中華電信苗栗市服務據點 • http://www.cht.com.tw/portal/Location • 建⽴立物件 chtMap 據點名稱當屬性名稱 據點地址當屬性值 •

    查有沒有據點苗栗府前特約服務中⼼心 • 依序 alert 出 chtMap 中的據點名稱和地址 • 把 chtMap 的屬性值改為物件 記下據點的地址和電話 • 依序 alert 出 chtMap 中的據點名稱、地址、電話
  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
  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 回傳資料型態的字串
  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
  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
  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
  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
  40. JavaScript 覺得對的⽅方式⾃自動轉型 • JavaScript 覺得對 !== 你覺得對 • 稀奇古怪靈異事件⼀一⼤大堆 •

    http://zero.milosz.ca/ • http://wtfjs.com/
  41. JavaScript 運算⼦子 • 與 C C++ C# Java ⼤大致相同 •

    注意⾃自動轉型 • == != ⾃自動轉型後⽐比較 • === !== 資料型態相同⽐比較 • 效能較佳
  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 需已宣告
  43. Core JavaScript 事先定義物件 • Object Number String Boolean • Array

    Function Date Math RegExp • http://w3schools.com/ • Google 搜尋 w3shools Math • Client-side 中除了以上物件 都是 DOM 物件
  44. Array • Array 內元件不需同⼀一資料型態 var arr = new Array(); alert(arr.length);

    // 0 arr[0] = 'abc'; arr[1] = true; arr[2] = 10; alert(arr.length); // 3
  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
  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 即 可
  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
  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 沒有傳⼊入⼀一個參數問題
  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;
  50. Exercise w3schools Date • 請⽤用 Google 搜尋 w3schools Date •

    利⽤用 w3schools 說明完成 • alert 格式 yyyy/mm/dd 的今天⽇日期 • 利⽤用 Date.parse() 處理 • 2012/12/21 • 2012-12-21 • 2012-13-21 • 並判斷結果是否可⽤用
  51. Function • Function 也是物件 物件特性都適⽤用 var f = new Function('x',

    'y', 'return x + y'); alert(f(1, 2)); // 3 注意!傳⼊入參數是 string 幾乎沒⼈人這樣⽤用
 因為不習慣 且效能較差
 多半⽤用 Function 實字
  52. Function 實字

  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; }
  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
  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
  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 為例
  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
  58. Function 也可以當參數傳遞 function f() { alert('!'); } var g =

    f; g(); // ! function f() { alert('!'); } function g(a) { a(); } g(f); // !
  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](); // ! }
  60. arguments 與函式 Parameter 可並存 f(1, 2, 3, 4); function f(x,

    y, z) { alert(z); // 3 alert(arguments[2]); // 3 alert(arguments[3]); // 4 }
  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
  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
  63. 函式中宣告變數不寫 var 會變全域變數 (function() { var a = 1; })();

    alert(a); // ReferenceError: a is not defined (function() { a = 1; })(); alert(a); // 1 左右就差⼀一個 var
  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
  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
  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 第⼆二三個參數
  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 物件
  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
  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; } 把傳⼊入參數加總
  70. Function 裡還可以寫 Function function f() { g(); function g() {

    alert(1); } } f(); // 1 g(); // ReferenceError: g is not defined 外⾯面看不⾒見 裡⾯面的函式
  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); }
  72. 裡⾯面的函⽰示可以存取外⾯面函⽰示的變數 • 外⾯面函式存取不到裡⾯面函式的變數 f(); function f() { var c =

    0; g(); alert(c); // 1 g(); alert(c); // 2 function g() { ++c; } }
  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 的最 上⽅方
  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 ⽣生存期間綁⼀一起
  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 是完全分開、各⾃自獨⽴立的
  76. Closure 匿名函式化 var h = f(); function f() { var

    c = 0; function g() { ++c; } return g; } var h = (function() { var c = 0; return function() { ++c; } })(); ⾃自我執⾏行的匿名函式
  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 外存取不到
  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 } } }
  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 );
  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
  81. Exercise 匿名函式 Closure • 請利⽤用匿名函式 Closure 寫⼀一函式 • 第⼀一次執⾏行 alert

    2 的 1 次⽅方是 2 • 第⼆二次執⾏行 alert 2 的 2 次⽅方是 4 • 第三次執⾏行 alert 2 的 3 次⽅方是 8 • … 以此類推 • 只可有此函式 不得有其它 Global 變數
  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) { … }
  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
  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() { … }
  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 (台北標準時間)
  86. Prototype 繼承 • Prototype 是 JavaScript 的繼承⽅方式 • Java 的繼承⽅方式是

    Class • ECMAScript 6 有考慮也⽀支援 Class 繼承 • 但⺫⽬目前沒有任何瀏覽器⽀支援 • ECMAScript 6 compatibility table • 其它 Prototype 繼承的語⾔言多死光了 • Prototype-based_programming - Wikipedia, the free encyclopedia
  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 沒那麼簡單
  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
  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
  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
  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) { ... }
  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
  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
  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
  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
  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');
  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__
  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 存取
  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
  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 上
  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 屬性
  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
  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();
  104. Vexed's Blog • http://blog.xuite.net/vexed • 站內搜尋 • closure • prototype

    • anonymous • arguments.callee • function expression • strict mode