這一期所書寫的目的並非爲了介紹建立對象的方法,在紅皮書裏面,例子其實很清楚。在這篇文章中,想討論一下書中細節,並無解釋太清楚的地方。app
//工廠模式書本「 function createPerson(name,age){ var obj=new Object(); obj.name=name; obj.age=age; obj.load=function(){ console.log(obj.name,obj.age); } return obj; } var toti=createPerson('toti',18); toti.load(); //」工廠模式書本
工廠模式的一些要點:函數
解決:優化
建立多個類似對象問題this
傳參spa
缺點:不能識別對象類型prototype
優化:通常使用對象字面量寫法,再返回code
思考對象
對象暴露出來,其實也能夠用,可是賦值須要重複。ip
包在一個函數裏面,傳參方便原型鏈
這個模式作了什麼?
建立一個Object實例對象
爲實例obj添加屬性、方法
返回實例obj
至關於使用了一個普通的函數,去讓這個對象能夠複用。
書中:「不能識別對象類型」如何理解?
咱們的實例,當咱們去console.log(toti)的時候。可是工廠模式下,
咱們去獲取這個實例的時候,只能簡單的判斷它是一個對象。這就是它一個缺點,因而咱們有了後面的構造函數模式
使用對象字面量寫法優化
//工廠模式對象字面量「 function createPerson(name,age){ var obj={ name:name, age:age, load:function(){ console.log(this.name,this.age); } } return obj; } var mary=createPerson('mary',18); mary.load(); //」工廠模式對象字面量
對象字面量注意問題
this的用法
在obj對象裏面,this.name&this.age指向obj的做用域的name&age
若是不使用this,則name和age,指向createPerson的做用域。
在本例中,使用this.name,name均可以,由於是傳參,因此createPerson和obj兩個做用域變量同樣
//「 構造函數模式;「 構造函數當作構造函數使用,用new function Person(name,age){ this.name=name; this.age=age; this.load=function(){ console.log(this.name,this.age); } } var toti=new Person('toti',18); toti.load(); console.log(typeof toti); // 」構造函數模式;」構造函數當作構造函數使用,用new
發生了什麼?
在解釋發生的事情前,咱們要先詳細瞭解下new的做用。在紅皮書中,new的做用,解釋的的確很淺,簡單幾行字,不細讀,很難理清其中的邏輯。
NEW的做用
紅皮書中是這樣解釋的:
建立一個新對象
將構造函數的做用域賦值給新對象
執行構造函數中的代碼
返回新對象
這幾行文字,一開始我也覺得我讀懂了,可是它實在沒有很好地給讀者說明白new到底怎麼用的。
在這裏,我引用一個我提問中的網友的回答,下面是來自wei0613的回答:
function CO(){ this.p = 「I’m in constructed object」; this.alertP = function(){ alert(this.p); } } var o2 = new CO();
var obj ={}; obj.__proto__ = CO.prototype; CO.call(obj); return obj;
他用代碼形式給咱們講解了其中發生了什麼事:
new先建立了一個對象obj
而後CO函數的原型賦值給對象obj的原型
CO函數再使用call/apply方法把做用域賦給obj
到這一步才執行構造函數Co裏面的代碼!!!
返回obj對象
你們可能第一眼,並不能發現我這裏的邏輯和紅皮書的邏輯有什麼區別。首先,紅皮書的邏輯中,很明顯少了原型建立發生在哪一步,若是這裏不清楚,會影響你們理解接下來原型模式和動態原型模式的理解;其次,第4步是最重要的,也就是構造函數的代碼執行,是發生在第4步,call的使用和原型鏈的造成都發生在以前。若是咱們僅僅只有一個大概概念,當咱們遇到對象字面量重寫的時候,咱們極可能發現咱們代碼寫得都沒有問題,可是就是出bug的狀況。這個工做流邏輯你們必定要清楚。
構造函數裏this的做用
在new的時候,所謂的做用域賦給新對象,就是使用了call/apply方法。
Person.apply(obj,arguments);
this就指向了obj對象
把this的屬性方法一個個添加到obj對象裏面
其餘不是this的屬性和方法,都會被忽略,好比:
function Person(name, age,job){ this.name=name; this.age=age; this.load=function(){ console.log(this.name,this.age); } var job=job; }
job就不會被寫入obj對象裏面
注意,當咱們new Person()的時候,是把函數看成構造函數使用的,可是它也是函數,能夠像普通函數同樣使用
//「 構造函數當作普通函數使用,不用new function Person(name,age){ this.name=name; this.age=age; this.load=function(){ console.log(this.name,this.age); } } var mike=Person('mike',18); //mike.load();會報錯,Person沒有對象返回 window.load(); // 」構造函數當作普通函數使用,不用new
直接使用函數,等於在當前做用域下運行。在這種狀況下,咱們則會把this指向這個環境的做用域,在這裏是window。咱們使用mike.load()會報錯,由於屬性和方法並無添加到mike這個對象中,而是添加到了window這個對象。
若是咱們不用new,也能夠實現this指向咱們想指向的對象
//「 構造函數當作普通函數使用,call,apply function Person(name,age){ this.name=name; this.age=age; this.load=function(){ console.log(this.name,this.age); } } var obj={}; Person.call(obj,'mike',18); obj.load(); // 」構造函數當作普通函數使用,call,apply
這些變式其實都是在充分了解new和this的用法後,天然寫出來的。經過些變式,你們能夠更好理解它們的用法。
相比工廠模式,構造函數模式的優缺點及思考
當咱們console.log(toti):
咱們回顧工廠模式下,是:
因此構造函數模式在這裏比工廠模式更好,看到這裏你們應該明白書中:「不能識別對象類型」的問題了。
構造函數模式要點
解決:能夠識別爲一種特定的類型
缺點:構造函數的每一個方法都被實例了一遍
思考:
構造函數開頭大寫,其餘函數開頭小寫
不使用new,至關於普通函數使用,this指向window,爲window添加變量和方法
也可使用call和apply來爲第三方做用域添加
重點:
new
this