最近手頭一個項目剛完成,下一個顯目還在準備中,趁這個空檔期,拿起塵封多年的JS書, 重溫一遍JS面向對象程序設計,而後就得出下文,算是一個總結吧。前端
也許,你會說 「建立對象不就是一對花括號的事嗎?」,是的,目前咱們最經常使用, 也是最便捷的方式就是所謂的一對花括號的事,也就是咱們常說的JSON對象(嚴格意義上,這其實不算JSON對象,具體咱們這裏不作深刻),以下:git
let obj = {
name:'xiaohong',
age: 17,
gender: 'female'
}
複製代碼
這是就是咱們常說的對象字面量(Literal)的方法建立對象,應該是目前使用最普遍的方法了。 這總方法基本上等同與下面(建立Object實例)的方法es6
let obj = new Object()
obj.name = 'xiaohong'
obj.age = 17
obj.gender: 'female'
複製代碼
可是因爲 對象字面量的方法,比較簡潔直觀,足以知足大部分場景下的需求,因此被開發着們普遍採用, 而Object實例的方式就不多有人問津了。 不過字面量方法也是有缺點的,缺點就是徹底沒有複用性可言,若是須要建立多個對象, 就會有不少重複的代碼,好比:github
var studentA = {
name: 'xiaohong'
age: 17,
gender: 'female'
}
var studentB = {
name: 'xiaoming'
age: 18,
gender: 'male'
}
var studentC = {
name: 'lili'
age: 17,
gender: 'female'
}
複製代碼
不難看出,三個對象只有冒號後面的內容不同,其餘的代碼都是冗餘的,那有什麼辦法能夠避免這個冗餘呢? 日常開發中,若是咱們碰到一個要重複用到的功能的時候,咱們會怎麼作?對的, 就是把這個功能封裝成一個函數,而後重複調用:面試
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點:this
經過構造函數new出來的對象,咱們是能檢測到它的類型的spa
studentA instanceof Student // true
studentA instanceof Object // true
複製代碼
事實上,當咱們使用 new 實例化一個構造函數的時候,js其實偷偷的在背後作了4件事,這個也是個比較經典的面試題:prototype
然而,構造函數也不是沒有缺點,使用構造函數建立的對象裏面都是數據是沒啥問題, 可是若是對象裏面有函數(方法)呢? 仍是上面那個代碼,咱們拿來稍微修改一下,須要給學生增長一個學習的技能:
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上還有其餘一些關於前端的教程和組件,有興趣的童鞋能夠看看,大家的支持就是我最大的動力。