JS-建立對象

建立對象

使用new Object()或者對象字面量均可以建立對象,可是這樣建立的對象過於簡單,不易於對象的屬性與方法的擴展與繼承。
下面講的對象能夠與JavaEE中的bean作類比。css

工廠模式

對,首先可能想到的是使用設計模式中的工廠模式設計模式

function createPizza(type) {
  var o = new Object();
  o.type = type;
  o.bake = function() {
    alert('Start~');
    alert(this.type);
    alert('End~');
  };
  return o;
}

var cheesePizza = createPizza('cheese');
var veggiePizza = createPizza('veggie');
cheesePizza.bake();

優勢

工廠模式解決了建立多個相似對象的問題瀏覽器

缺點

對象沒法識別,即建立出來的對象沒法經過instanceof等分析出屬於哪一種類型函數

構造函數模式

用構造函數可用來建立特定類型的對象this

// 構造函數首字母遵循OO語言慣例進行大寫
function Pizza(type) {
  this.type = type;
  this.bake = function() {
    alert('Start~');
    alert(this.type);
    alert('End~');
  };
}

var cheesePizza = new Pizza('cheese');
var veggiePizza = new Pizza('veggie');
cheesePizza.bake();

與工廠模式相比:prototype

  1. 沒有在方法中顯示創造對象(o);
  2. 直接將屬性與方法賦值給this;
  3. 沒有return語句

在用new的時候,會經歷一下4步:設計

  1. 建立一個新對象
  2. 將構造函數的做用域賦值給新對象(此時this指向新對象)
  3. 執行構造函數代碼(爲對象添加屬性)
  4. 返回新對象
若是不使用new,將構造函數當作函數使用,則this指向Global對象(在瀏覽器中爲window對象),固然,能夠使用call方法來指定做用域,例如
var o = new Object();
Pizza.call(o, 'salty');
o.bake();

使用構造函數方法,每一個實例對象都有一個constructor構造函數屬性,該屬性指向Pizza(使用對象字面量、工廠模式方法建立的對象該屬性指向Object)eslint

cheesePizza.constructor == Pizza

檢查某個對象屬於哪一種類型,通常使用instanceof,cheesePizza同時屬於PizzaObject(之因此屬於Object,是由於全部對象均繼承於Object)指針

cheesePizza instanceof Pizza;
cheesePizza instanceof Object;

優勢

與工廠模式相比,構造函數模式可以識別出對象類型
與下面的原型模式相比,可以實現對象屬性的互相獨立,在引用類型屬性上頗有用code

缺點

每一個實例對象的方法都是獨立的,致使方法不可以共享

原型模式

每一個函數(不是實例對象)都有一個prototype屬性,該屬性是一個指針,指向一個對象,對象的用途是包含全部實例共享的屬性和方法。prototype經過調用構造函數建立的那個對象實例的原型對象。使用原型對象的好處是可讓全部實例對象共享屬性與方法。

function Pizza() {

}

Pizza.prototype.type = 'original'
Pizza.prototype.bake = function() {
  alert('Start~');
  alert(this.type);
  alert('End~');
};

var cheesePizza = new Pizza();
cheesePizza.type = 'cheese';
var veggiePizza = new Pizza();
veggiePizza.type = 'veggie';

cheesePizza.bake();
veggiePizza.bake();

各個對象共享屬性與方法,同時每一個對象均可以創建本身的屬性,並屏蔽掉原型對象的同名屬性,由於共享屬性與方法,因此如下等式成立

cheesePizza.bake == veggiePizza.bake

對象字面量重寫原型對象

也能夠經過對象字面量來重寫整個原型對象:

Pizza.prototype = {
  type: 'original',
  bake: function() {
    alert('Start~');
    alert(this.type);
    alert('End~');
  }
}

這樣徹底重寫,原型對象上的constructor屬性再也不指向Pizza函數(全新的constructor指向Object),不過不影響經過instanceof來識別對象類型。若是constructor特別重要的話,能夠顯式將它置爲適當的值:

Pizza.prototype = {
  constructor: Pizza,
  type: 'original',
  bake: function() {
    alert('Start~');
    alert(this.type);
    alert('End~');
  }
}

不過這種方式會將constructor的屬性特徵變爲可枚舉,而默認狀況下它是不可枚舉的,若是想不可枚舉,能夠使用Object.defineProperty()方法。

原型的動態性

對原型對象的修改會體如今實例對象上,即便實例對象先被建立。可是經過對象字面量重寫的原型對象則沒有該動態性

優勢

定義在原型對象上的屬性,可以保證在各實例對象上的共享

缺點

對於引用類型的屬性,各實例的共享會致使額外的問題。

組合使用構造函數模式與原型模式

整合構造函數模式與原型模式,構造函數模式用於定義實例屬性,原型模式用於定義方法和共享屬性。

動態原型模式

寄生構造函數模式

穩妥構造函數模式

各建立模式在Chrome瀏覽器中的表現

能夠經過Chrome瀏覽器觀察使用工廠模式建立的cheesePizza對象屬性爲:

cheesePizza
{type: "cheese", bake: ƒ}
  bake: ƒ ()
  type: "cheese"
  __proto__:
    constructor: ƒ Object()
    hasOwnProperty: ƒ hasOwnProperty()
    isPrototypeOf: ƒ isPrototypeOf()
    propertyIsEnumerable: ƒ propertyIsEnumerable()
    toLocaleString: ƒ toLocaleString()
    toString: ƒ toString()
    valueOf: ƒ valueOf()
    __defineGetter__: ƒ __defineGetter__()
    __defineSetter__: ƒ __defineSetter__()
    __lookupGetter__: ƒ __lookupGetter__()
    __lookupSetter__: ƒ __lookupSetter__()
    get __proto__: ƒ __proto__()
    set __proto__: ƒ __proto__()

使用構造函數模式建立cheesePizza對象屬性爲:

cheesePizza
Pizza {type: "cheese", bake: ƒ}
  bake: ƒ ()
  type: "cheese"
  __proto__:
    constructor: ƒ Pizza(type)
    __proto__:
      constructor: ƒ Object()
      hasOwnProperty: ƒ hasOwnProperty()
      isPrototypeOf: ƒ isPrototypeOf()
      propertyIsEnumerable: ƒ propertyIsEnumerable()
      toLocaleString: ƒ toLocaleString()
      toString: ƒ toString()
      valueOf: ƒ valueOf()
      __defineGetter__: ƒ __defineGetter__()
      __defineSetter__: ƒ __defineSetter__()
      __lookupGetter__: ƒ __lookupGetter__()
      __lookupSetter__: ƒ __lookupSetter__()
      get __proto__: ƒ __proto__()
      set __proto__: ƒ __proto__()

使用原型模式建立cheesePizza對象屬性爲:

cheesePizza
Pizza {type: "cheese"}
  type: "cheese"
  __proto__:
    bake: ƒ ()
    type: "original"
    constructor: ƒ Pizza()
    __proto__:
      constructor: ƒ Object()
      hasOwnProperty: ƒ hasOwnProperty()
      isPrototypeOf: ƒ isPrototypeOf()
      propertyIsEnumerable: ƒ propertyIsEnumerable()
      toLocaleString: ƒ toLocaleString()
      toString: ƒ toString()
      valueOf: ƒ valueOf()
      __defineGetter__: ƒ __defineGetter__()
      __defineSetter__: ƒ __defineSetter__()
      __lookupGetter__: ƒ __lookupGetter__()
      __lookupSetter__: ƒ __lookupSetter__()
      get __proto__: ƒ __proto__()
      set __proto__: ƒ __proto__()

參考文章

ESLint 須要約束 for-in (guard-for-in)

我的不按期更新主頁

相關文章
相關標籤/搜索