原型和原型鏈

  • 構造函數

    是一種特殊的方法。主要用來在創建對象時初始化對象, 即為對象成員變量賦初始值,總與new運算符一起使用在創建對象的語句中。特別的一個類可以有多個構造函數 ,可根據其參數個數的不同或參數類型的不同來區分它們 即構造函數的重載
    人話:用來把一個對象構建起來的函數(給這個對象設定屬性啊參數啊定義之類的),就叫構造函數。

    function Foo (name, age) {    //構造函數首字母大寫
          this.name = name;
          this.age = age;
          this.class = 'class-1';
          return this;
    }
    var  f1 = new Foo (' zhangsan ', 20);
    var  f2 = new Foo (' zhangsan ', 20); //Foo就是f1和f2的構造函數。
    

    幫助理解

    • var a = {} 其實是var a = new Object() 的語法糖。

    • var a = [] 其實是var a = nwe Array() 的語法糖。

    • function Foo () {} 相當于 var Foo = new Function()

    • 使用 instanceof 判斷一個函數是否是一個變量的構造函數

      后面出現的Js內置函數,就是等號前面變量的構造函數


  • 原型規則

    • 所有引用類型(對象、數組、函數),都有對象特性,即都可以自由擴展屬性。
      var obj = {};   obj.a = 100;
      var arr = [];   arr.a = 100;
      function fn () {};  fn.a = 100;  //都可以去給他們添加屬性。
      
    • 所有的引用類型(對象、數組、函數),都有一個 " __proto__ " 屬性(約定稱之為隱式原型),屬性只是一個普通的對象。
      console.log (obj.__proto__);
      console.log (arr.__proto__);
      console.log (fn.__proto__);  //符合第一條規則,可以自由拓展屬性。
      
    • 所有的函數,都有一個 “ prototype ” 屬性(約定稱之為顯示原型),屬性值也是一個普通對象。
      console.log (fn.prototype); //函數也是引用類型,所以同時也符合第一條。
      
    • 所有的引用類型(對象、數組、函數), " __proto__ " 屬性值指向它的構造函數的 “ prototype ” 屬性值
      console.log (obj.__proto__ === Object.prototype);  //true
      //obj是一個對象,而Object就是obj的構造函數。符合這一條
      
    • 當試圖得到一個對象(函數、數組)的某個屬性時,如果對象本身沒有該屬性,就會去該對象的 __proto__(即該對象的構造函數的prototype)中尋找。
      //創建一個構造函數Foo
      function Foo (name, age) {
            this.name = name;
      };
      
      //給Foo的顯示原型添加一個屬性(函數)
      Foo.prototype.alertName = function () {
            alert (this.name);
      };
      
      //創建對象
      var f = new Foo ('zhangsan');  //Foo 就是 f 的構造函數
      f.printName = function () {
            console.log (this.name);
      };
      
      //測試
      f.printName ();  //f 本身有這個屬性,所以沒問題。
      f.alertName ();  //f 本身沒有這個屬性,所以就去f.__proto__里尋找,
                       //即到它的構造函數Foo的prototype里尋找,并且可以找到。
                       //里面的this永遠只想自身f
      
    • 補充——循環對象自身的屬性
      當我們循環獲取對象自身屬性的時候,并不希望獲取到其隱式原型(其構造函數的顯示原型)的屬性。
      var item;
      for (intem in f) {
            if (f.hasOwnProperty(item)) {
                  cosole.log (item);
            //雖然瀏覽器會在for in中屏蔽原型屬性,但加上會保證健壯性。
            }
      }
      



  • 原型鏈

    在上面,我們可以了解到,f.printName () 和 f.alertName () 是可以被找到的。
    但如果再加上 f.toString () 呢,f 及其 Foo.prototype 中都沒有這個屬性。

    上面所說 f.__proto__ 即 Foo.prototype 的屬性值就是一個普通對象,也就是說有構造函數即Object。參照上面的原型規則可得出以后流程圖。

    f.\_\_proto__ (Foo.prototype)中找,找不到。
    f.__proto__.__proto__ (Foo.prototype.__proto__)(Object.prototype)里找
    就找到了。
    但是,如果還是找不到呢
    ③ 繼續,到 Object.prototype.__proto__(有完沒完?)
    ④ 到了這里,為了避免死循環,Js規定,這里返回null。

    圖片參考自慕課網



  • instanceof 判斷函數是否是構造函數

    • f instanceof Foo ——判斷Foo是否為 f 的構造函數。
      答案是肯定的,邏輯是 f 的__proto__ 一層層往上看能否對應到 Foo.prototype

    • 在嘗試 f instanceof Object ——判斷Object
      答案也是肯定的。網上找也可以找到 Object.prototype



Wait me back

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容