JS中建立對象的方法

JS中建立對象的方法

最近手頭一個項目剛完成,下一個顯目還在準備中,趁這個空檔期,拿起塵封多年的JS書,
重溫一遍JS面向對象程序設計,而後就得出下文,算是一個總結吧。

也許,你會說 「建立對象不就是一對花括號的事嗎?」,是的,目前咱們最經常使用,
也是最便捷的方式就是所謂的一對花括號的事,也就是咱們常說的JSON對象(嚴格意義上,這其實不算JSON對象,具體咱們這裏不作深刻),以下:前端

let obj = {
    name:'xiaohong',
    age: 17,
    gender: 'female'
}

這是就是咱們常說的對象字面量(Literal)的方法建立對象,應該是目前使用最普遍的方法了。
這總方法基本上等同與下面(建立Object實例)的方法git

let obj = new Object()
obj.name = 'xiaohong'
obj.age = 17
obj.gender: 'female'

可是因爲 對象字面量的方法,比較簡潔直觀,足以知足大部分場景下的需求,因此被開發着們普遍採用,
而Object實例的方式就不多有人問津了。
不過字面量方法也是有缺點的,缺點就是徹底沒有複用性可言,若是須要建立多個對象,
就會有不少重複的代碼,好比:es6

var studentA = {
    name: 'xiaohong'
    age: 17,
    gender: 'female'
}
var studentB = {
    name: 'xiaoming'
    age: 18,
    gender: 'male'
}
var studentC = {
    name: 'lili'
    age: 17,
    gender: 'female'
}

不難看出,三個對象只有冒號後面的內容不同,其餘的代碼都是冗餘的,那有什麼辦法能夠避免這個冗餘呢?
日常開發中,若是咱們碰到一個要重複用到的功能的時候,咱們會怎麼作?對的,
就是把這個功能封裝成一個函數,而後重複調用:github

function Student(name,age,gender){
    // 如下代碼還能夠用es6這樣寫 return {name,age,gender}
    // 詳情請參考es6 屬性簡寫
    return {
        name:name,
        age:age,
        gender:gender
    }
}
// 而後在須要的時候,調用一下這個函數,傳進一些參數便可
var studentA = Student('xiaohong',17,'f')
var studentB = Student('xiaoming',18,'m')
var studentC = Student('lili',17,'f')

這樣是否是簡潔不少,每次只要調用一下Student這個函數,而後傳進名字,年齡,性別,
就能獲得一個你想要的對象了。
這種方法叫 工廠模式 ,是否是真的很像一個加工廠呢? 這種方法對建立多個對象的時候頗有用,
不過這種方法也是有缺點的,就是沒法知道對象的類型,好比,
我想經過條件語句判斷studentA是否是一個Student對象,就作不到面試

typeof studentA === 'Student'   //false
studentA instanceof Student     // false

因爲工廠模式在對象識別的問題上不堪重任,因此咱們一般用 構造函數 模式來解決對象識別的問題函數

function Student(name,age,gender){
    this.name = name
    this.age = age
    this.gender = gender
}
// 經過調用構造函數,new一個對象(這個估計是有其餘面嚮對象語言基礎的童鞋對容易接受的一種方式)
var studentA = new Student('xiaohong',17,'f')
var studentB = new Student('xiaoming',18,'m')
var studentC = new Student('lili',17,'f')

構造函數跟工廠模式的很類似,區別主要在如下2點:學習

  1. 沒有返回對象,而是直接把參數賦值給this做用域下的同名變量,由於new的時候,

會把this指向調用new出來的那個實例對象,因此就完成了賦值操做this

  1. 調用構造函數的時候,在構造函數前面加一個new(

若是沒加new,就當作普通函數使用,做用域會在當前代碼塊的環境下面,函數裏面的值會賦給當前做用域)prototype

經過構造函數new出來的對象,咱們是能檢測到它的類型的設計

studentA instanceof Student // true
studentA instanceof Object  // true

事實上,當咱們使用 new 實例化一個構造函數的時候,js其實偷偷的在背後作了4件事,這個也是個比較經典的面試題:

  1. 建立一個新對象(prototype 指向構造函數的prototype)
  2. 把做用域(this)指給這個對象
  3. 執行構造函數的代碼
  4. 返回這個對象

然而,構造函數也不是沒有缺點,使用構造函數建立的對象裏面都是數據是沒啥問題,
可是若是對象裏面有函數(方法)呢?
仍是上面那個代碼,咱們拿來稍微修改一下,須要給學生增長一個學習的技能:

function Student(name,age,gender){
    this.name = name
    this.age = age
    this.gender = gender
    this.study = fucntion() { console.log('我在學習...')}
 }

這樣咋看起來,也沒啥毛病,調用一些實例的study,也能夠打印出「我在學習...」

var studentA = new Student('xiaohong',17,'f')
studentA.study()   // 我在學習...

可是,若是咱們這樣

var studentA = new Student('xiaohong',17,'f')
var studentB = new Student('xiaoming',18,'m')
studentA.study == studentB.study  // false

咱們發現,2個實例的study不是指向同一個函數,而是2個不一樣的函數,可是他們的功能如出一轍
至關於這樣

studentA.study = fucntion() { console.log('我在學習...')}
studentB.study = fucntion() { console.log('我在學習...')}
studentC.study = fucntion() { console.log('我在學習...')}

這讓強迫症怎麼接受?
事實證實,寫代碼的,大部分都有強迫症,因而,就有了原型模式
原型模式的原理,就是我不把方法和屬性添加到構造函數裏面去,我直接添加到構造函數的原型裏面去,
因爲原型的共享的,因此咱們在這邊就解決了冗餘:

function Student(){}   // 聲明一個空函數
Student.prototype.name = 'xiaohong'
Student.prototype.age = 17
Student.prototype.gender = 'f'
Student.prototype.study = fucntion() { console.log('我在學習...')}

var studentA = new Student()
var studentB = new Student()
studentA.study == studentA.study  // true

這樣,就能解決函數重複聲明的問題,全部的實例,都共享原型上的函數study.然而,函數是共享了沒錯,
不過其餘數據也共享了,全部實例上都會有相同的name,age,gender,這也不是咱們想要的效,這時,
聰明的你確定會想,把數據放在構造函數裏面,只把方法放在原型裏面:

function Student(name,age,gender){
    this.name = name
    this.age = age
    this.gender = gender
 }
 Student.prototype.study = fucntion() { console.log('我在學習...')}

這樣把普通的數據放在構造函數裏面聲明,把函數(方法)放在原型上聲明的模式,
咱們稱之爲組合模式(即組合使用構造函數模式和原型模式),組合模式,既有數據的獨立,又有方法的共享
能夠說是比較完美的一種對象的建立方式了。ES6的class語法糖實現的原理大致上也是利用組合模式。

以上就是ES5裏面建立對象的一些經常使用模式,固然還有一些不經常使用的奇葩的模式,好比動態原型模式,
寄生構造函數模式,穩妥構造函數模式...等等,,這裏就不一一列舉了,感興趣的童鞋自行百度一下

好了,關於建立對象的話題,就到這裏了,感謝收看!

若是以爲對您有用,請給本文的github加個star,萬分感謝,另外,github上還有其餘一些關於前端的教程和組件,有興趣的童鞋能夠看看,大家的支持就是我最大的動力。

相關文章
相關標籤/搜索