JavaScript 建立對象的七種方式

來源:互聯網
上載者:User

標籤:自訂類   efi   tor   CQ   var   ble   property   其他應用   操作符   

JavaScript建立對象的方式有很多,通過Object建構函式或對象字面量的方式也可以建立單個對象,顯然這兩種方式會產生大量的重複代碼,並不適合量產。接下來介紹七種非常經典的建立對象的方式,他們也各有優缺點。

原廠模式

 

function createPerson(name, job) {

  var o = new Object()

  o.name = name

  o.job = job

  o.sayName = function() {

    console.log(this.name)

  }

  return o

}

var person1 = createPerson(‘Jiang‘, ‘student‘)

var person2 = createPerson(‘X‘, ‘Doctor‘)

 

可以無數次調用這個工廠函數,每次都會返回一個包含兩個屬性和一個方法的對象

 

原廠模式雖然解決了建立多個相似對象的問題,但是沒有解決對象識別問題,即不能知道一個對象的類型

 

建構函式模式

 

function Person(name, job) {

  this.name = name

  this.job = job

  this.sayName = function() {

    console.log(this.name)

  }

}

var person1 = new Person(‘Jiang‘, ‘student‘)

var person2 = new Person(‘X‘, ‘Doctor‘)

 

沒有顯示的建立對象,使用new來調用這個建構函式,使用new後會自動執行如下操作

 

  • 建立一個新對象

  • 這個新對象會被執行[[prototype]]連結

  • 這個新對象會綁定到函數調用的this

  • 返回這個對象

 

使用這個方式建立對象可以檢測物件類型

 

person1 instanceof Object // true

person1 instanceof Person //true

 

但是使用建構函式建立對象,每個方法都要在每個執行個體上重新建立一次

 

原型模式

 

function Person() {

}

Person.prototype.name = ‘Jiang‘

Person.prototype.job = ‘student‘

Person.prototype.sayName = function() {

  console.log(this.name)

}

var person1 = new Person()

 

將資訊直接添加到原型對象上。使用原型的好處是可以讓所有的執行個體對象共用它所包含的屬性和方法,不必在建構函式中定義對象執行個體資訊。

 

原型是一個非常重要的概念,在一篇文章看懂proto和prototype的關係及區別中講的非常詳細

 

更簡單的寫法

 

function Person() {

}

Person.prototype = {

  name: ‘jiang‘,

  job: ‘student‘,

  sayName: function() {

    console.log(this.name)

  }

}

var person1 = new Person()

 

將Person.prototype設定為等於一個以對象字面量形式建立的對象,但是會導致.constructor不在指向Person了。

 

使用這種方式,完全重寫了預設的Person.prototype對象,因此 .constructor也不會存在這裡

 

Person.prototype.constructor === Person  // false

 

如果需要這個屬性的話,可以手動添加

 

function Person() {

}

Person.prototype = {

  constructor:Person

  name: ‘jiang‘,

  job: ‘student‘,

  sayName: function() {

    console.log(this.name)

  }

}

 

不過這種方式還是不夠好,應為constructor屬性預設是不可枚舉的,這樣直接設定,它將是可枚舉的。所以可以時候,Object.defineProperty方法

 

Object.defineProperty(Person.prototype, ‘constructor‘, {

  enumerable: false,

  value: Person

})

 

缺點

 

使用原型,所有的屬性都將被共用,這是個很大的優點,同樣會帶來一些缺點

 

原型中所有屬性執行個體是被很多執行個體共用的,這種共用對於函數非常合適。對於那些包含基本值的屬性也勉強可以,畢竟執行個體屬性可以屏蔽原型屬性。但是參考型別值,就會出現問題了

 

function Person() {

}

Person.prototype = {

  name: ‘jiang‘,

  friends: [‘Shelby‘, ‘Court‘]

}

var person1 = new Person()

var person2 = new Person()

person1.friends.push(‘Van‘)

console.log(person1.friends) //["Shelby", "Court", "Van"]

console.log(person2.friends) //["Shelby", "Court", "Van"]

console.log(person1.friends === person2.friends) // true

 

friends存在與原型中,執行個體person1和person2指向同一個原型,person1修改了引用的數組,也會反應到執行個體person2中

 

組合使用建構函式模式和原型模式

 

這是使用最為廣泛、認同度最高的一種建立自訂類型的方法。它可以解決上面那些模式的缺點

 

使用此模式可以讓每個執行個體都會有自己的一份執行個體屬性副本,但同時又共用著對方法的引用

 

這樣的話,即使執行個體屬性修改參考型別的值,也不會影響其他執行個體的屬性值了

 

function Person(name) {

  this.name = name

  this.friends = [‘Shelby‘, ‘Court‘]

}

Person.prototype.sayName = function() {

  console.log(this.name)

}

var person1 = new Person()

var person2 = new Person()

person1.friends.push(‘Van‘)

console.log(person1.friends)  //["Shelby", "Court", "Van"]

console.log(person2.friends) // ["Shelby", "Court"]

console.log(person1.friends === person2.friends) //false

 

動態原型模式

 

動態原型模式將所有資訊都封裝在了建構函式中,初始化的時候,通過檢測某個應該存在的方法時候有效,來決定是否需要初始化原型

 

function Person(name, job) {

  // 屬性

  this.name = name

  this.job = job

 

  // 方法

  if(typeof this.sayName !== ‘function‘) {

    Person.prototype.sayName = function() {

       console.log(this.name)

    }

  }

 

}

var person1 = new Person(‘Jiang‘, ‘Student‘)

person1.sayName()

 

只有在sayName方法不存在的時候,才會將它添加到原型中。這段代碼只會初次調用建構函式的時候才會執行。

 

此後原型已經完成初始化,不需要在做什麼修改了

 

這裡對原型所做的修改,能夠立即在所有執行個體中得到反映

 

其次,if語句檢查的可以是初始化之後應該存在的任何屬性或方法,所以不必用一大堆的if語句檢查每一個屬性和方法,只要檢查一個就行

 

寄生建構函式模式

 

這種模式的基本思想就是建立一個函數,該函數的作用僅僅是封裝建立對象的代碼,然後再返回建立的對象

 

function Person(name, job) {

  var o = new Object()

  o.name = name

  o.job = job

  o.sayName = function() {

    console.log(this.name)

  }

  return o

}

var person1 = new Person(‘Jiang‘, ‘student‘)

person1.sayName()

 

這個模式,除了使用new操作符並把使用的封裝函數叫做建構函式之外,和原廠模式幾乎一樣

 

建構函式如果不返回對象,預設也會返回一個新的對象,通過在建構函式的末尾添加一個return語句,可以重寫調用建構函式時返回的值

 

穩妥建構函式模式

 

首先明白穩妥對象指的是沒有公用屬性,而且其方法也不引用this。

 

穩妥對象最適合在一些安全環境中(這些環境會禁止使用this和new),或防止資料被其他應用程式改動時使用

 

穩妥建構函式模式和寄生模式類似,有兩點不同:一是建立對象的執行個體方法不引用this,而是不使用new操作符調用建構函式

 

function Person(name, job) {

  var o = new Object()

  o.name = name

  o.job = job

  o.sayName = function() {

    console.log(name)

  }

  return o

}

var person1 = Person(‘Jiang‘, ‘student‘)

person1.sayName()

 

和寄生建構函式模式一樣,這樣建立出來的對象與建構函式之間沒有什麼關係,instanceof操作符對他們沒有意義

JavaScript 建立對象的七種方式

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.