摘要:面向?qū)ο笾膭?chuàng)建特定對象的語法糖個人學(xué)習(xí)筆記分享為了講清楚面向?qū)ο髮嶋H上是需要幾個前置知識的。于是之父創(chuàng)造了這個語法糖。
JS面向?qū)ο笾?【new】 (創(chuàng)建特定對象的語法糖)
個人學(xué)習(xí)筆記分享
為了講清楚面向?qū)ο?實際上是需要幾個前置知識的。
包括前面的幾篇文章【原型鏈】 【this】 和今天要說的【new】
還是先說結(jié)論: new只是一個語法糖,這個語法糖被設(shè)計出來,使用場景是批量創(chuàng)建對象
從場景說起: 假設(shè)這個世界沒有new,我們?nèi)绾闻縿?chuàng)建一百個士兵obj?通篇文章,我們都是在實現(xiàn)這個需求,不斷優(yōu)化,最終實現(xiàn)一個new語法糖。
類似這樣的士兵ojb
var 士兵 = { ID: 1, 兵種: "美國大兵", 攻擊力: 5, 生命值: 42, 攻擊: function(){console.log("攻擊")}, 防御: function(){console.log("防御")}, 死亡: function(){console.log("死亡")}, }版本v1.0: 最直覺的方法當(dāng)然是循環(huán)100次
var 士兵 var 士兵們 = [] for (var i = 0 ; i < 100 ; i++){ 士兵 = { ID: 1, 兵種: "美國大兵", 攻擊力: 5, 生命值: 42, 攻擊: function(){console.log("攻擊")}, 防御: function(){console.log("防御")}, 死亡: function(){console.log("死亡")}, } 士兵們.push(士兵) } 最終我們得到了array士兵們
根據(jù)第二篇文章 JS面向?qū)ο笾驹玩湣?對象和對象的關(guān)系).md),我們知道這里的攻擊、防御、死亡都是匿名函數(shù),在內(nèi)存空間都會占據(jù)空間。
這些函數(shù)的內(nèi)容完全相同,300個匿名函數(shù)卻要占用300個內(nèi)存空間,十分浪費。
自然地,我們就想到JS的原型鏈就是專門解決這個問題的,我們把共同的屬性放到__proto__里,所有士兵的__proto__都指向相同的內(nèi)存空間。
版本v1.1: 優(yōu)化內(nèi)存空間,使用__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士兵們
(以上代碼可粘貼運(yùn)行)
現(xiàn)在我們省掉了之前297個匿名函數(shù)所占用的空間。讓他們的__proto__都指向"士兵共"這個內(nèi)容空間就OK了
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("死亡")}, }版本v2.0: 封裝成createSoldier函數(shù),避免意大利式面條,讓代碼更加集中。
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 } ------分割線以上是創(chuàng)建構(gòu)造函數(shù), 分割線以下,是使用構(gòu)造函數(shù)------ var soldiers = [] for(var i = 0 ;i<100 ; i++){ soldiers.push(createSoldier()) }版本v2.1: 讓開發(fā)者一眼就知道soldierCommon和createSoldier是有關(guān)系的,讓代碼進(jìn)一步集中
// 讓soldierCommon成為構(gòu)造函數(shù)的屬性(因為函數(shù)也是obj,當(dāng)然可以有屬性) // soldierCommon可以改叫xxx,只是一個名字,只是為了讓這個對象和createSoldier產(chǎn)生聯(lián)系 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 } ------分割線以上是創(chuàng)建構(gòu)造函數(shù), 分割線以下,是使用構(gòu)造函數(shù)------ var soldiers = [] for(var i = 0 ;i<100 ; i++){ soldiers.push(createSoldier()) }
那么現(xiàn)在還可以優(yōu)化嗎? 上面這段代碼,唯一的缺點就是xxx不太容易理解。
所以,JS之父為了容易理解將這個xxx,也就是共有屬性的引用,統(tǒng)一叫做prototype,雖然prototype對于中國人來說依舊不好理解。
版本v2.2: 完美的代碼,將xxx改為prototype (只是一個名字,但是JS之父將它命名成了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 } ------分割線以上是創(chuàng)建構(gòu)造函數(shù), 分割線以下,是使用構(gòu)造函數(shù)------ var soldiers = [] for(var i = 0 ;i<100 ; i++){ soldiers.push(createSoldier()) }
好了,仔細(xì)看看上面的代碼,還有什么可優(yōu)化的地方嗎?
內(nèi)存、變量名、代碼集中都做了優(yōu)化,也就是范例式的代碼。
那么,JS之父也認(rèn)為這個就是最好的代碼,他希望,當(dāng)JS開發(fā)者們需要批量創(chuàng)建特定對象時,都這樣寫。
于是,JS之父創(chuàng)造了new這個語法糖。
版本v3.0 讓我們看看JS之父創(chuàng)造的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("死亡")} ------分割線以上是創(chuàng)建構(gòu)造函數(shù), 分割線以下,是使用構(gòu)造函數(shù)------ var soldiers = [] for(var i = 0 ;i<100 ; i++){ soldiers.push( new Soldier()) }對比v2.2 和 v3.0 這兩個版本,就是new幫我們做的事情。
v2.2 沒有使用new語法的函數(shù)createSoldier
function createSoldier(){ var obj = { ID: 1, 生命值: 42 } obj.__proto__ = createSoldier.prototype return obj }
v3.0 使用了new語法的函數(shù)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 }
對比一下,當(dāng)你使用new語法,JS之父幫你做了什么事情
第一 , JS幫你在函數(shù)里創(chuàng)建了一個this空對象,并且這個this指向是構(gòu)造函數(shù)的實例
第二 , JS幫你讓this的__proto__ 指向 構(gòu)造函數(shù)的原型,也就是prototype
第三 , JS幫你偷偷return了 this
第四 , JS偷偷給Soldier.prototype加了個constructor屬性
其他注意事項
構(gòu)造函數(shù)首字母大寫,習(xí)慣寫法
__proto__不能在生產(chǎn)環(huán)境出現(xiàn),因為會嚴(yán)重影響性能
用new調(diào)用的時候,也沒法用call了,因為JS之父幫你call了,this的指向就像你見到的指向?qū)嵗?/p>
所以使用了new,就可以讓代碼沒有廢話。
你只需要設(shè)置對象的自有屬性和共有屬性。
JS幫你創(chuàng)建空對象,幫你搞定this指向,幫你改變this的__proto__,幫你return this
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/92407.html
摘要:首先為了模擬類創(chuàng)建對象的功能搞出了構(gòu)造函數(shù)。也就是名字膚色膚色這里是繼承里的自有屬性生命值這里繼承的共有屬性的方法攻擊力兵種美國大兵攻擊防御死亡膚色 JS面向?qū)ο笾?【繼承】 我們已經(jīng)準(zhǔn)備了很多前置知識,包括 原型鏈,對象和對象之間的關(guān)系 this,對象和函數(shù)之間的關(guān)系 new, 用函數(shù)批量創(chuàng)建特定的對象的語法糖 JS面向?qū)ο蟮那笆澜裆?我們說,面向?qū)ο笫且环N寫代碼的套路。因為如...
摘要:一面向?qū)ο蟾拍蠲嫦驅(qū)ο缶褪鞘褂脤ο?。因此在?gòu)造函數(shù)中表示剛剛創(chuàng)建出來的對象。在構(gòu)造函數(shù)中利用對象的動態(tài)特性為其對象添加成員。 一、面向?qū)ο?1.1 概念 面向?qū)ο缶褪鞘褂脤ο蟆C嫦驅(qū)ο箝_發(fā)就是使用對象開發(fā)。 面向過程就是用過程的方式進(jìn)行開發(fā)。面向?qū)ο笫菍γ嫦蜻^程的封裝。 1.2 三大特性 抽象性所謂的抽象性就是:如果需要一個對象描述數(shù)據(jù),需要抽取這個對象的核心數(shù)據(jù) 提出需要的核心...
摘要:如果你已經(jīng)對機(jī)制已有了解,但是由于兩者對象機(jī)制的巨大本質(zhì)差異,對它和構(gòu)造函數(shù),實例對象的關(guān)系仍有疑惑,本文或許可以解答你的問題。所有的原型對象都會自動獲得一個屬性,這個屬性的值是指向原型所在的構(gòu)造函數(shù)的指針。 幫助面向?qū)ο箝_發(fā)者理解關(guān)于JavaScript對象機(jī)制 本文是以一個熟悉OO語言的開發(fā)者視角,來解釋JavaScript中的對象。 對于不了解JavaScript 語言,尤其是習(xí)...
摘要:前言我們在深入淺出面向?qū)ο蠛驮透拍钇谶@篇文章中了解到了如何使用解決重復(fù)創(chuàng)建浪費內(nèi)存的問題,其中的關(guān)鍵就是,那么這篇文章讓我們來重新了解的前世今生一個苦逼年級主任的故事開學(xué)啦高一年級主任龔主任需要為全年級每一位理科班新生錄入學(xué)號并為每一位 前言 我們在深入淺出面向?qū)ο蠛驮汀靖拍钇?】在這篇文章中了解到了如何使用new Function解決重復(fù)創(chuàng)建浪費內(nèi)存的問題,其中的關(guān)鍵就是new...
摘要:為啥我要自己實現(xiàn)一個語法糖為什么要自己實現(xiàn)一個語法糖呢因為之前對于里的語法糖一直是理論理解但是并親自嘗試實現(xiàn)過。直到有一天在頭條的面試中我聊了摸著自己的良心說我可以實現(xiàn)一個語法糖面試官嗯那你實現(xiàn)一個吧。我們知道構(gòu)造函數(shù)一般是不寫的。 為啥我要自己實現(xiàn)一個new語法糖? 為什么要自己實現(xiàn)一個new語法糖呢? 因為之前對于JS里的new語法糖一直是理論理解,但是并親自嘗試實現(xiàn)過。 直到有一...
閱讀 3680·2021-11-23 09:51
閱讀 1568·2021-11-04 16:08
閱讀 3620·2021-09-02 09:54
閱讀 3687·2019-08-30 15:55
閱讀 2668·2019-08-30 15:54
閱讀 1025·2019-08-29 16:30
閱讀 2113·2019-08-29 16:15
閱讀 2386·2019-08-29 14:05