1. OOP
    1. Object-oriented Language,物件導向程式語言
    2. 特性
      1. 封裝Encapsulation
      2. 繼承Inheritance
      3. 多形Polymorphism
  2. Object(物件)
    1. 讓正真有需要的原始碼接觸資料,減少資料曝露的程度
    2. 程式碼再利用
    3. 物件結合資料與行為,建立一種新的資料型別, 其中可以儲存(store)資料,也可以根據資料而行動(act), 所以物件是個容器,其中儲存資料,並聯繫資料與依據資料行動的原始碼
    4. 資料(變數)+行為(函式)=物件
      1. 物件內的資料稱「property」(屬性、特性)
      2. 物件內的行為稱「method」(方法)
      3. property + method = Object
    5. .(點)
      1. 點號運算子('.' dot operator)用於取用物件property與method
      2. Object + . + property/method
        1. mail.from = "..."; mail.to = "..."; ... mail.send();
    6. 物件可以包含其他物件
      1. var mail = new Mail(new Date(), "from", ...);
      2. 在Mail建構式中傳入一個Date物件
    7. 物件Object在一個儲存容器內聯繫起變數與函式
  3. 建構式(constructor)
    1. property
      1. 物件具有資料,資料必須在物件建立時「初始化」,每個自訂物件都需要自己的建構式,名稱與「物件相同」。
      2. function Mail(from,to,body,subject){ this.from = from; this.to = to; this.body = body; this.subject = subject; }
        1. 建構式使用首字母大寫
        2. 建立property需使用JavaScript的關鍵字「this」, 關鍵字this區分物件property與一般變數
          1. this指定物件property的擁有權,同時設定property的初始值
          2. 建立屬於「這個(this)」物件的property
          3. this.from = from;
          4. 將收到的參數指定給新property
          5. 沒有this,建構式不會知道你正在建立物件property
      3. 以建構式建立物件時,我們使用new運算子,它呼叫物件的建構式,開啟物件建立過程。
        1. var mail = new Mail("from","to","body","subject");
        2. var mail
          1. 新物件儲存在變數裡
        3. new Mail(...)
          1. new運算子建立新Mail物件(呼叫建構式)
        4. "from","to","body",...
          1. 傳入參數給建構式,以設定property
    2. method
      1. function Mail(from,to,body,subject){ // Object method this.send = function(){ ... } }
        1. 該如何知道指令碼(函式)應放入method?
          1. method就是根據物件的property而採取某些行動, 換言之,如果指令碼需要取用物件內部資料,就非常 合適放入method
        2. 把函式轉為方法
          1. 宣告method
          2. 使用this建立method,與建立property類似
          3. this.send = function(){ }
          4. 把現有程式碼移入method裡
          5. 修改使用物件property
      2. 關於選用功能
        1. function Mail(from,to,body,subject,smtp,port){ ... //smtp與port為選用功能 this.smtp = smtp; this.port = port; }
        2. 當某個參數未傳入給function、method、constructor時, 在任何試圖使用參數值的原始碼裡,它的值都是null, 在缺少參數相對應的property將會被設為null
        3. 確認選用參數在function參數清單的最後面
          1. 例如:當funcion有兩個參數
          2. 兩個都傳入
          3. 只傳入第一個
          4. 兩個都不傳
          5. 無法只傳第二個
  4. 複本
    1. Mail物件的send()方法
      1. Mail物件的method是在建構式裡,利用關鍵字this建立,但依此建立的Mail物件都會各有一份物件方法的複本
      2. 關鍵字"this"用於設置「instance」擁有的property和method
      3. var mail1 = new Mail(...); var mail2 = new Mail(...); var mail3 = new Mail(...);
        1. 每個Mail物件(mail1,mail2,mail3),都會有自己的property與method複本
        2. 等於會有三份method
          1. 這是浪費又沒效率
      4. property為每個物件儲存獨特資料,method應該為物件所共享
    2. Class與instance
      1. 類別Class,是物件的描述,樣版、藍圖
        1. function Mail(...)
      2. 實例Instance,實際物件,依Class建立
        1. var mail = new Mail(...);
        2. mail是依Mail來建立的物件(instance)
      3. 每個instance的property多半都不一樣, 所以每個instance才需要有自己的property複本, 但method沒有必要複製到每個instance中
    3. Class擁有method
      1. class-owned instance method
        1. 當method為Class所擁有時,所有該Class的instance都可以取用此method,而不需要另外複製一份
      2. 在Class使用prototype
        1. 在JavaScript中每個物件都有一個prototype物件(以property存在), prototype用以設定Class level(類別層級)的property與method, 而非屬於instance
          1. 也就是說,我們需要把method的「擁有權」指派給Class,而不是指派小單一instance
        2. Mail.prototype.send = function(){}
          1. prototype使用需在建構式之外
          2. send()方法直接附加到Mail class本身,而非隸屬於某個instance, 這樣無論Mail class建立多少份instance,都只會有一份send()方法
          3. 當send()接受呼叫時,將在class內執行
          4. mail1.send(); mail2.send(); mail3.send();
          5. 當其他Mail物件的instance也呼叫了send()方法, 仍會執行Class內的同一方法
        3. class property
          1. 類別屬性,此property只需要在類別儲存一次,但能被所有instance存取
          2. Mail.prototype.smtp = "smtp.kkbruce.com"; Mail.prototype.port = "25";
          3. 此property只有一個值,讓所有instance共享
          4. 想成,它是class的全域變數,但只能讓class對應的instance取用
      3. 標準物件能也使用prototype
        1. 每個物件都有prototype,它允許在Class Level增加property與method
        2. 範例:擴充Date物件
          1. Date.prototype.shortFormat = function(){ return this.getFullYear() +'/'+(this.getMonth()+1)+'/'+ this.getDate(); }
          2. var d = new Date(); d.shortFormat();
          3. 傳回「年/月/日」格式日期
      4. Class自己的method
        1. 類別方法,class method
          1. 它屬於Class,只能取用class property,不能取用instance property
        2. 建立class method
          1. 直接為Class設定method,而不使用prototype
          2. Mail.showSMTP = function(){ alert('SMTP:'+Mail.prototype.smtp+' ,\n Port:'+Mail.prototype.port); } ... Mail.showSMTP();
          3. Mail.showSMTP
          4. 建立Mail物件的showSMTP方法
          5. Mail.prototype.smtp
          6. 為了從class method取用class property,你必須下探至prototype
          7. smtp是個Mail class property,所以Mail class method可以取用
          8. Mail.showSMTP();
          9. 直接透過Class名稱Mail來呼叫方法
      5. 回到建構式
        1. 讓建構式專注在property的建立與初始化
  5. OOP範例
    1. ajax物件
      1. function AjaxRequest() { if (window.XMLHttpRequest) { try { this.request = new XMLHttpRequest(); } catch(e) { this.request = null; } } else if (window.ActiveXObject) { try { this.request = new ActiveXObject("Microsoft.XMLHTTP"); } catch(e) { this.request = null; } } if (this.request == null) alert("建立Ajax物件錯誤.\n" + "細節:" + e.message); }
        1. AjaxRequest.prototype.send = function(type, url, handler, postDataType, postData) { //type, url, handler為get必要參數 //postDataType, postData為post必要參數 if (this.request != null) { this.request.abort(); url += "?dummy=" + new Date().getTime(); try { this.request.onreadystatechange = handler; this.request.open(type, url, true); // always asynchronous (true) if (type.toLowerCase() == "get") { this.request.send(null); } else { this.request.setRequestHeader("Content-Type", postDataType); this.request.send(postData); } } catch(e) { alert("Ajax程式錯誤.\n" + "細節:" + e); } } }
        2. AjaxRequest.prototype.getReadyState = function() { return this.request.readyState; }
        3. AjaxRequest.prototype.getStatus = function() { return this.request.status; }
        4. AjaxRequest.prototype.getResponseText = function() { return this.request.responseText; }
        5. AjaxRequest.prototype.getResponseXML = function() { return this.request.responseXML; }
      2. 宣告
        1. var ajax = new AjaxRequest();