【JS系列】一塊兒理解對象的7種建立方式(全)

前言

起初接觸JS時常見的簡單地建立單個對象的方式有下面三種:設計模式

  • 字面量,即var obj = {}
  • new Object()
  • Object.create()

以上三種方式在須要建立不少對象時會產生大量重複代碼。顯然須要更高效的方式,下面將介紹7種建立對象的方式安全

1. 工廠模式

1.1介紹

工廠模式正是源自設計模式中的工廠模式,其基本思想:函數

  • 既然建立對象數量多時產生了大量重複代碼
  • 那就建一座工廠,經過工廠來建立加工
  • 再返回建立好的對象
function createPerson(name, age) {
  var obj = new Object()
  obj.name = name
  obj.age = age
  obj.getName = function() {
    console.log(this.name)
  }
  return obj
}

var person1 = createPerson("AAA", 23)
person1.getName()   //AAA

var person2 = createPerson("BBB", 30)
person2.getName()   //BBB
複製代碼

1.2 優劣分析

  • 解決了複用性的問題
  • 但沒法判斷對象的類型(只知道是Objcet類型)

2. 構造函數模式

2.1 介紹

構造函數可建立特定類型的對象,相似Object和Array(實際上Object和Array自己就是構造函數)post

function Person(name, age) {
  this.name = name
  this.age = age
  this.getName = function() {
    console.log(this.name)
  }
}

var person1 = new Person("AAA", 23)
person1.getName()  //AAA

var person2 = new Person("BBB", 30)
person2.getName()  //BBB
複製代碼

經過上面代碼咱們能夠看到構造函數模式:優化

  • 沒有經過new Object()顯示建立對象
  • 屬性和方法賦值給了this
  • 無需return

2.2 構造函數也是函數

構造函數其實也是個函數,只是能夠經過new調用來建立對象,固然也可做爲普通函數使用ui

//做爲普通函數使用
Person("CCC", 24)
Person.getName() //CCC

//在一個對象內調用
var obj = {}
Person.call(obj, "DDD", 25)
obj.getName()    //DDD
複製代碼

2.3 優劣分析

  • 構造函數模式能夠建立具體類型的對象
console.log(person1 instanceof Object)  //true
console.log(person1 instanceof Person)  //true
複製代碼
  • 然而,構造函數中的方法是通用的,但每一個實例都建立了一份屬於本身的副本,形成內存浪費
console.log(person1.getName === person2.getName)  //false
複製代碼

3. 原型模式

3.1 介紹

原型模式即經過原型對象來實現屬性和方法的共享,實例對象不會建立各自的副本this

要理解原型模式,建議先理解透徹JS原型的概念——推薦閱讀一張圖完全KO原型鏈(prototype,__proto__)spa

function Person() {
}

Person.prototype.name = "AAA"
Person.prototype.age = 23
Person.prototype.getName = function() {
  console.log(this.name)
}

var person1 = new Person()
person1.getName()    //AAA

var person2 = new Person()
person2.name = "BBB"
person2.getName()    //BBB

console.log(person1.getName === person2.getName)  //true
複製代碼

然而原型對象也存在缺陷——對於引用類型的屬性,各實例對象間指向同一個地址,某個對象修改了屬性,全部對象都會受到影響prototype

function Person() {
}

Person.prototype.arr = [1,2,3]
Person.prototype.getArr = function() {
  console.log(this.arr)
}

var person1 = new Person()
person1.arr.push(4)
person1.getArr()    //1,2,3,4

var person2 = new Person()
person2.getArr()    //1,2,3,4

person1.arr.push(5)
person1.getArr()    //1,2,3,4,5
person2.getArr()    //1,2,3,4,5
複製代碼

3.2 優劣分析

  • 原型模式解決了屬性和方法的共享問題
  • 但對於引用類型的屬性,各實例對象會相互影響

4. 組合模式

4.1介紹

組合模式即組合構造函數模式和原型模式,取兩者之長,構造函數模式用於定義實例的屬性,原型模式用於定義方法和共享的屬性設計

function Person(name, age) {
  this.name = name
  this.age = age
  this.arr = [1,2,3]
}

Person.prototype = {
  getName: function() {
    console.log(this.name)
  }
}

var person1 = new Person("AAA", 23)
person1.arr.push(4)
console.log(person1.arr)  //1,2,3,4
person1.getName()         //AAA

var person2 = new Person("BBB", 30)
console.log(person2.arr)  //1,2,3
person2.getName()         //BBB
複製代碼

4.2 優劣分析

  • 組合模式是使用最普遍的一種模式,尤爲在須要定義引用類型時

5. 動態原型模式

5.1 介紹

剛說組合模式是承認度最高的一種模式,然而也有些美中不足——每建立一個實例對象,原型方法都被重複定義一次

動態原型模式正是解決這個問題,使用if語句,使得原型方法只初始化一次

function Person(name, age) {
  this.name = name
  this.age = age

  //這裏只須要使用任何一個方式或屬性,不必定是getName,getAge也能夠
  //只要保證if裏面的代碼只執行一次就行
  if(typeof this.getName !== 'function') {
    Person.prototype.getName = function() {
      console.log(this.name)
    }

    Person.prototype.getAge = function() {
      console.log(this.age)
    }
  }
}

var person = new Person("AAA", 23)
person.getName()    //AAA
複製代碼

5.2 優劣分析

  • 動態原型模式在組合模式的基礎上作了優化,可謂更加完美

6. 寄生構造函數模式

6.1 介紹

長得和工廠模式同樣,但調用方式和構造函數模式同樣的模式,經過new調用構造函數,本該返回一個實例對象,但return語句重寫了構造函數的返回值

function Person(name, age) {
  var obj = new Object()
  obj.name = name
  obj.age = age
  obj.getName = function() {
    console.log(this.name)
  }
  return obj
}

var person = new Person("AAA", 23)
person.getName()   //AAA
複製代碼

6.2 優劣分析

  • 這種方式和工廠模式沒什麼不一樣,要說不一樣的就是經過new來調用,仍然存在工廠模式的沒法判別對象類型的問題

  • 我的認爲這是一種多餘的方式,複雜而很差理解,也沒有什麼應用場景

7. 穩妥構造函數模式

7.1 介紹

先介紹一個概念——穩妥對象:

  • 沒有公共屬性
  • 不使用this
  • 不使用new調用

穩妥構造函數模式和工廠模式相似,但遵循穩妥對象的原則

function Person(name, age) {
  var obj = new Object()

  //getName是惟一讀取name的方式
  obj.getName = function() {
    console.log(name)
  }
  return obj
}

var person = Person("AAA", 23)
person.name = "BBB" //無效
person.getName()    //AAA
複製代碼

7.2 優劣分析

  • 穩妥構造函數模式的特色就是安全性,適用於某些須要安全執行的環境
  • 相似工廠模式,沒法判別對象類型

8. 總結

  1. 工廠模式:解決了大量重複代碼的問題,但沒法判別對象類型

  2. 構造函數模式:實例對象又具體的類型,但每一個實例對象都有方法的副本,形成內存浪費

  3. 原型模式:可共享方法和屬性,但存在引用類型相互影響的問題

  4. 組合模式:取構造函數模式和原型模式之長 (最經常使用)

  5. 動態原型模式:優化了組合模式

  6. 寄生構造函數模式:相似工廠模式,只是經過new調用

  7. 穩妥構造函數模式:相似工廠模式,只是提高了安全性

後記

但願本文對你有幫助,更多文章將持續更新……

感謝你的點贊和鼓勵

與本文相關的文章有:

【JS系列】一張圖完全KO原型鏈(prototype,__proto__)

【JS系列】對象詳解

【JS系列】繼承的這6種方式!(上)

【JS系列】繼承的這6種方式!(下)

相關文章
相關標籤/搜索