我的學習筆記分享函數
爲了講清楚面向對象,其實是須要幾個前置知識的。
包括前面的幾篇文章【原型鏈】 【this】 和今天要說的【new】性能
仍是先說結論: new只是一個語法糖,這個語法糖被設計出來,使用場景是批量建立對象學習
通篇文章,咱們都是在實現這個需求,不斷優化,最終實現一個new語法糖。優化
相似這樣的士兵ojbthis
var 士兵 = { ID: 1, 兵種: '美國大兵', 攻擊力: 5, 生命值: 42, 攻擊: function(){console.log('攻擊')}, 防護: function(){console.log('防護')}, 死亡: function(){console.log('死亡')}, }
var 士兵 var 士兵們 = [] for (var i = 0 ; i < 100 ; i++){ 士兵 = { ID: 1, 兵種: '美國大兵', 攻擊力: 5, 生命值: 42, 攻擊: function(){console.log('攻擊')}, 防護: function(){console.log('防護')}, 死亡: function(){console.log('死亡')}, } 士兵們.push(士兵) } 最終咱們獲得了array士兵們
根據第二篇文章 JS面向對象之二【原型鏈】(對象和對象的關係).md),咱們知道這裏的攻擊、防護、死亡都是匿名函數,在內存空間都會佔據空間。
這些函數的內容徹底相同,300個匿名函數卻要佔用300個內存空間,十分浪費。prototype
天然地,咱們就想到JS的原型鏈就是專門解決這個問題的,咱們把共同的屬性放到__proto__裏,全部士兵的__proto__都指向相同的內存空間。設計
var 士兵 var 士兵們 = [] for (var i=0 ; i<100 ; i++){ 士兵 = { ID: 1, 生命值: 42 } 士兵.__proto__ = 士兵共 士兵們.push(士兵) } var 士兵共 = { 兵種: '美國大兵', // 若是兵種和攻擊力也是同樣的話,那麼也須要放到__proto__裏去共享 攻擊力: 5, 攻擊: function(){console.log('攻擊')}, 防護: function(){console.log('防護')}, 死亡: function(){console.log('死亡')}, } 最終依舊獲得了array士兵們
(以上代碼可粘貼運行)
如今咱們省掉了以前297個匿名函數所佔用的空間。讓他們的__proto__都指向'士兵共'這個內容空間就OK了code
var soldier var soldiers= [] for (var i=0 ; i<100 ; i++){ soldier = { ID: 1, 生命值: 42 } soldier.__proto__ = soldierCommon soldiers.push(soldier) } var soldierCommon = { 兵種: '美國大兵', // 若是兵種和攻擊力也是同樣的話,那麼也須要放到__proto__裏去共享 攻擊力: 5, 攻擊: function(){console.log('攻擊')}, 防護: function(){console.log('防護')}, 死亡: function(){console.log('死亡')}, }
var soldierCommon = { 兵種: '美國大兵', // 若是兵種和攻擊力也是同樣的話,那麼也須要放到__proto__裏去共享 攻擊力: 5, 攻擊: function(){console.log('攻擊')}, 防護: function(){console.log('防護')}, 死亡: function(){console.log('死亡')}, } function createSoldier(){ var obj = { ID: 1, 生命值: 42 } obj.__proto__ = soldierCommon return obj } ------分割線以上是建立構造函數, 分割線如下,是使用構造函數------ var soldiers = [] for(var i = 0 ;i<100 ; i++){ soldiers.push(createSoldier()) }
// 讓soldierCommon成爲構造函數的屬性(由於函數也是obj,固然能夠有屬性) // soldierCommon能夠改叫xxx,只是一個名字,只是爲了讓這個對象和createSoldier產生聯繫 createSoldier.xxx = { 兵種: '美國大兵', 攻擊力: 5, 攻擊: function(){console.log('攻擊')}, 防護: function(){console.log('防護')}, 死亡: function(){console.log('死亡')}, } function createSoldier(){ var obj = { ID: 1, 生命值: 42 } obj.__proto__ = createSoldier.xxx return obj } ------分割線以上是建立構造函數, 分割線如下,是使用構造函數------ var soldiers = [] for(var i = 0 ;i<100 ; i++){ soldiers.push(createSoldier()) }
那麼如今還能夠優化嗎? 上面這段代碼,惟一的缺點就是xxx不太容易理解。對象
因此,JS之父爲了容易理解將這個xxx,也就是共有屬性的引用,統一叫作prototype,雖然prototype對於中國人來講依舊很差理解。內存
createSoldier.prototype = { 兵種: '美國大兵', 攻擊力: 5, 攻擊: function(){console.log('攻擊')}, 防護: function(){console.log('防護')}, 死亡: function(){console.log('死亡')}, } function createSoldier(){ var obj = { ID: 1, 生命值: 42 } obj.__proto__ = createSoldier.prototype return obj } ------分割線以上是建立構造函數, 分割線如下,是使用構造函數------ var soldiers = [] for(var i = 0 ;i<100 ; i++){ soldiers.push(createSoldier()) }
好了,仔細看看上面的代碼,還有什麼可優化的地方嗎?
內存、變量名、代碼集中都作了優化,也就是範例式的代碼。
那麼,JS之父也認爲這個就是最好的代碼,他但願,當JS開發者們須要批量建立特定對象時,都這樣寫。
因而,JS之父創造了new這個語法糖。
function Soldier(){ this.ID = 1 this.生命值 = 42 } Soldier.prototype.兵種 = '美國大兵' Soldier.prototype.攻擊力 = '65 Soldier.prototype.攻擊 = function(){console.log('攻擊')} Soldier.prototype.防護 = function(){console.log('防護')} Soldier.prototype.死亡 = function(){console.log('死亡')} ------分割線以上是建立構造函數, 分割線如下,是使用構造函數------ var soldiers = [] for(var i = 0 ;i<100 ; i++){ soldiers.push( new Soldier()) }
v2.2 沒有使用new語法的函數createSoldier
function createSoldier(){ var obj = { ID: 1, 生命值: 42 } obj.__proto__ = createSoldier.prototype return obj }
v3.0 使用了new語法的函數Soldier
function Soldier(){ // this = {} JS偷偷作的第1個事情 // this.__proto__ = Soldier.prototype JS偷偷作的第2個事情 this.ID = 1 this.生命值 = 42 // return this JS偷偷作的第3個事情 } Soldier.prototype = { JS偷偷給Soldier.prototype加了個constructor屬性 constructor : Soldier }
對比一下,當你使用new語法,JS之父幫你作了什麼事情
其餘注意事項
因此使用了new,就可讓代碼沒有廢話。
你只須要設置對象的自有屬性和共有屬性。JS幫你建立空對象,幫你搞定this指向,幫你改變this的__proto__,幫你return this