面向對象是JS的重點與難點,但也是走向「掌握JS」的必經之路,有不少的文章或書籍中都對其進行了詳細的描述,本沒有必要再寫這些,可是對於學習來講,講給別人聽對本身來講是一種更好的受益方式。我想經過簡潔的語言來描述建立對象的方法以及這種方法的優缺點。javascript
本系列內容:java
基本建立模式segmentfault
對象字面量建立對象函數
工廠模式學習
構造函數模式測試
更新時間this
2015年12月6日:建立code
2017年7月8日:精簡內容,修正錯誤對象
建立對象的方法有許多,各有利弊。知其然,作到會用;知其因此然,作到爲何用這種方法。才能是真正的掌握。ip
var person = new Object(); person.name = "張三"; person.job = "學生"; person.viewName = function(){ console.log(this.name); }
這是一種最基礎的建立對象的方法,使用新建Object
的方法建立對象,而且爲其添加屬性和方法。
但這種方式有個很差的地方是重複使用了多個person
變量,並且沒有任何的封裝性可言,因而就出現了更受開發人員喜好的對象字面量形式。
var person = { name: "張三", job: "學生", viewName: function(){ console.log(this.name); } }
這種方式的好處顯而易見,就是解決了以前的缺點。
但在實際需求中,須要建立一批相似的對象就有些力不從心了。好比一個小組有六個成員,我要基於每一個組員進行對象實例化,那麼我要寫6遍以上的代碼,而且爲其命名爲person1~person6。若是能夠像流水線通常建立對象就行了:給其提供原料(名字和職務),讓其自動建立出組員,使用函數剛好能作到。
var person = function(name, job){ var o = new Object(); o.name = name; o.job = job; o.viewName = function(){ console.log(this.name); } return o; }; var person1 = person("張三","學生"); var person2 = person("李四","學生");
工廠模式利用"建立對象函數"造成流水線的模式,使其流程化,將建立的過程都封裝到函數中,對外只暴露每一個對象的特性(經過參數的形式傳入)。
具體的實現流程是:在函數內建立了一個對象,將傳入的參數做爲對象的屬性,在最後將其返回。調用函數,函數就會返回擁有特定屬性的對象。
工廠模式流程化了建立對象的方法,使其建立對象變得很是簡便,但其中出了一個問題,既然person1和person2都使用person函數建立,那麼,有什麼方法能夠證實person1和person2"師出同門"呢?或者用JS的話說是怎樣解決對象識別問題,答案是工廠模式不能證實。因而又出現了構造函數模式,用此模式能夠肯定person1和person2的關係。
var Person = function(name, job){ this.name = name; this.job = job; this.viewName = function(){ console.log(this.name); } } var person1 = new Person("張三","學生"); var person2 = new Person("李四","學生");
與以前工廠模式的方法對比:
Person變量名首字母大寫了
在函數內沒有顯式的建立及返回對象而使用了this
建立時使用了new
關鍵字。
Person變量首字母大寫是爲了區別普通函數,除此以外,別無它用。既然Person的首字母大寫只是爲了讓本身一眼辨別出他是構造函數,在功能上是相同的。那麼寫成person固然能夠,只是這樣不推薦(沒法區分普通函數與構造函數)。
使用new操做符必須經歷四個步驟
建立一個新的對象
將構造函數的做用域賦值給新對象
執行構造函數的代碼:爲其添加屬性和方法
返回新的對象
使用new操做符建立的對象都有一個constructor
屬性,該屬性指向構造函數。
person1.constructor == Person; // true person1.constructor === person2.constructor;// true console.log(person1.constructor);// 返回構造函數 //function (name, job){ // this.name = name; // this.job = job; // this.viewName = function(){ // console.log(this.name); // } //}
在測試的時候發現一個問題:不使用new關鍵字建立Object對象爲何constructor有值?
再回到原來的需求,小組有兩我的,我要建立兩個對象,對象的名字和職位可能不同,可是打印每一個人的名字這個方法是同樣的。
對於以上幾種模式建立的對象。
person1.viewName === person2.viewName;// false
我每次建立一個對象,都建立一次viewName,可是每次都不相等(person1.viewName == person2.viewName返回false)。且若是有一天咱們想把viewName方法改爲return返回name值,我要每一個對象都改嗎?咱們只要把這個方法作成對象公用的就行了,咱們能夠這樣:
var Person = function(name, job){ this.name = name; this.job = job; this.viewName = viewName; } function viewName(){ console.log(this.name); } var person1 = new Person("張三","學生"); var person2 = new Person("李四","學生");
可是這又出現了一個問題,沒有封裝性可言啊,viewName明明是Person的私有方法,可是放在外面,變成了誰均可以調用,原型函數模式解決了這個問題。