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