最近手頭一個項目剛完成,下一個顯目還在準備中,趁這個空檔期,拿起塵封多年的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點:學習
會把this指向調用new出來的那個實例對象,因此就完成了賦值操做this
若是沒加new,就當作普通函數使用,做用域會在當前代碼塊的環境下面,函數裏面的值會賦給當前做用域)prototype
經過構造函數new出來的對象,咱們是能檢測到它的類型的設計
studentA instanceof Student // true studentA instanceof Object // true
事實上,當咱們使用 new 實例化一個構造函數的時候,js其實偷偷的在背後作了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上還有其餘一些關於前端的教程和組件,有興趣的童鞋能夠看看,大家的支持就是我最大的動力。