js中的對象建立的模式

對象建立模式:

  • 工廠模式
    • 因爲javascript中沒有類的概念,因此用開發人員發明了一種函數,經過函數來封裝特定接口建立對象的,見例子:
    function createObj (name, age) {
    		return {
    		name: name,
    		age: age
    		}
    	}
  • 構造函數模式
    • 該模式和上述工廠模式的不一樣點:
      • 沒有顯示地建立對象
      • 直接將屬性和方法賦給了this對象
      • 沒有return語句
      function Person (name, age){
          this.name = name;
          this.age = age;
      }
    • 構造函數名首字母約定大寫
    • 建立對象的過程大概分爲如下三個步驟:
      1. 建立一個對象
      2. 將構造函數的做用域賦給新對象
      3. 執行構造函數內的代碼,爲這個對象添加屬性
      4. 返回對象
      var obj = Object.create(Person.prototype);
      // 建立一個對象,將這個對象的原型指向構造函數的的原型;
      Person.call(obj);
      // 執行步驟2和3, 將構造函數的this指向建立的obj對象,並運行構造函數內的代碼,爲obj對象添加屬性
    • 須要注意的是: 若是構造函數中有return語句,返回的是引用類型的數據,則返回該引用類型數據
    • 若是作普通函數,在全局做用域中執行,則this指向window
    • 構造函數存在的問題:每一個方法都要在每一個實例上建立一遍,對此有一個簡單的方法解決,將方法函數的定義放在外面,可是若是有不少個方法,那就須要在外面定義不少個方法,好在能夠經過原型模式來解決這一問題
  • 原型模式
    • 將共同的方法屬性添加到函數的原型中,好處也體如今此處,讓全部的對象實例共享它包含的屬性和方法
      function Person () {};
      Person.prototype.name = 'zhanhui';
      Person.prototype.job = 'programmer';
      Person.prototype.sayName = function () {
          console.log(this.name);
      };
    • 每個函數都有一個prototype原型屬性,指向一個對象
    • prototype原型對象上有一個constructor屬性,指向構造函數
    • Object.getPrototypeOf() 獲取對象的原型屬性
    • isPrototypeOf()方法肯定對象之間是否存在原型關係
    • 雖然能夠經過對象實例訪問保存在原型中的值,可是不能經過對象實例重寫原型中的值,而且爲對象實例添加一個原型上重名的屬性時,這個屬性會屏蔽原型對象中保存的同名屬性,若是要回復對原型對象該屬性的訪問,能夠用delete操做符刪除實例屬性,見下例子:
    var person1 = new Person();
    var person2 = new Person();
    person1.name = 'wawa';
    console.log(person1.name); // 'wawa'來自實例對象
    console.log(person2.name); // 'zhanhui'來自原型對象
    • hasOwnProperty()獲取實例對象上的屬性,不能獲取原型對象的屬性
    • in 操做符 單獨使用或者配合for-in循環中使用
      • 單獨使用時,in操做符會在經過對象是否能訪問到給定的屬性時返回true,不管該屬性是否存在於實例中仍是原型中
      • for-in循環時,能夠經過對象訪問到、可枚舉的屬性,該屬性既能夠在實例中,也能夠是原型中,而且即便將該屬性的Enumerable標記爲false,也是能夠遍歷到的
      person1.age = 26;
      Object.defineProperty(Object.getPrototypeOf(person1), 'age', {
          enumerable: false
      });
      for (var key in person1) {
          console.log(key); // name job sayName
      }
      • for-in獲取key
      var obj = {
          x: 1,
          y: 2
          };
          var props = [];
          var i = 0;
      
          for (props[i++] in obj);
      
          props // ['x', 'y']
    • hasPrototypeProperty() 判斷讀取到的某屬性是在實例中讀取到還時原型中讀取到
    hasPrototypeProperty(person1, 'name'); // false person1中的name是從實例中讀取的
    hasPrototypeProperty(person2, 'name'); // true person2中的name是從原型中讀取的
    • Object.keys()返回全部可枚舉屬性的字符串數組
    • Object.getOwnPropertyNames()能夠獲取實例的全部屬性,無論是否可枚舉
    • 原型對象:
      • 默認原型對象的constructor是不可枚舉的,當咱們重寫原型時,constructor指向object構造函數,因此在重寫構造函數的原型對象時,若是constructor很重要,會用的到,就須要特別指定一下,見例子:
      function Person (){}
      Person.prototype = {
          constructor: Person, // 特別指定
          name: 'zhanhui',
          say: function() {
              console.log(this.name);
          }
      }
      // 將constructor屬性設置爲不可枚舉
      Object.defineProperty(Person.prototype, 'constructor', {
          enumberable: false
      })
      • 重寫原型後,調用構造函數時會爲實例添加一個指向最初的原型,而重寫原型則將構造函數和其最初的原型斷開了聯繫,實例化時又將實例對象的__proto__指向最初的原型,因此就存在問題,實例不能獲取重寫後的原型上的屬性和方法,見例子:
      var boo = new Person();
      boo.say() // error
      // 可是通過驗證並非,新的瀏覽器內核已經不存在這樣的問題了
      • 原型對象存在的問題:主要是其共享性所帶來的,例如原型對象上掛載了一個引用類型的屬性,其餘一個實例中更改這個引用屬性都會將影響擴散到其餘的全部實例上,見例子:
      function Person (){}
          Person.prototype = {
              constructor: Person, // 特別指定
              name: 'zhanhui',
              say: function() {
                  console.log(this.name);
              },
              friends: ['boo', 'mike']
          }
          var person1 = new Person();
          var person2 = new Person();
          person1.friends.push('lili');
          console.log(person1.friends); // ['boo', 'mike', 'lili']    console.log(person2.friends); // ['boo', 'mike', 'lili']
  • 組合構造函數模式和原型模式
    • 構造函數模式用來定義實例屬性,而原型模式用於定義方法和共享的屬性
    • 見例子:
    function Person (name, age) {
        this.name = name;
        this.age = age;
        this.friends = ['boo', 'mike'];
    }
    Person.prototype = {
        constructor: Person,
        say: function () {
            console.log(this.name);
        }
    }
  • 寄生構造函數模式
    • 其實和工廠模式相似,構造函數用來封裝建立對象的代碼,而後在返回新建立的對象,見例子:
    function Person (name, age) {
        var obj = {};
        obj.name = name;
        obj.age = age;
        obj.say = function () {
            console.log(this.name);
        }
    		return obj;
    }
    var person1 = new Person('zhanhui', 26);
    • 應用場景: 例如咱們要建立一個額外方法的數組
    • 特殊說明:構造函數返回的對象和構造函數以及構造函數的原型沒有關係,所以不能用instanceof來肯定對象類型
  • 穩妥構造函數
    • 所謂穩妥就是沒有公共屬性,其方法不使用new調用函數,也不引用this
    • 見例子:
    function Person (name,age){
        var o = {};
        // 定義私有變量和方法;
        function howOld () {
            console.log(age);
        }
        // 添加共有方法,這也是閉包的應用場景,共有方法訪問私有變量
        o.say = function () {
            console.log(this.name);
        };
        return o;
    }
     var person1 = Person('zh', 26);
    // 只能經過say方法訪問私有變量name
相關文章
相關標籤/搜索