深入了解JavaScript中的new關(guān)鍵字
手撕代碼
手寫new
是面試題高頻考點(diǎn),實(shí)現(xiàn)代碼也非常簡(jiǎn)單,但在實(shí)現(xiàn)后我對(duì)其為什么要這樣設(shè)計(jì)有著很深的疑惑,也看了許多文章,今天也來講一下為什么要這樣設(shè)計(jì)new
的實(shí)現(xiàn)
先來看下實(shí)現(xiàn)代碼:
function MyNew(Con,...args){ const obj = Object.create(Con); const result = Con.apply(obj, args); return result instanceof Object ? result : obj; }
我最初的感受是三行代碼很費(fèi)解,又是原型繼承,又是this
綁定,又是判斷類型的,其實(shí)這其中涉及到的知識(shí)點(diǎn)很多,雖然實(shí)現(xiàn)了new
的功能,但不知道為什么要這樣做
知其所以然
舉例
假設(shè)我們要開始全國(guó)人口普查,所以我們要制造一個(gè)表示人信息的對(duì)象,有名字,年齡,省份等信息,會(huì)吃東西,說話,行走,睡覺等行為
const person = { ID: i, name: "pangyu", age: "18", province: "山東", say() { console.log("說話"); }, eat() { console.log("吃東西"); }, walk() { console.log("行走"); }, sleep() { console.log("睡覺"); }, };
接下來查了100個(gè)人,那我們就利用for循環(huán)創(chuàng)建100個(gè)人的對(duì)象,實(shí)現(xiàn)批量統(tǒng)計(jì)
const roster = []; // 花名冊(cè) for (let i = 0; i < 100; i++) { const person = { ID: i, name: "pangyu", age: "18", province: "山東", say() { console.log("說話"); }, eat() { console.log("吃東西"); }, walk() { console.log("行走"); }, sleep() { console.log("睡覺"); }, }; roster.push(person); }
避免重復(fù)
統(tǒng)計(jì)了100個(gè)人之后,暴露了一個(gè)問題:
每個(gè)人的say,eat,walk,sleep方法都是一樣的,但每創(chuàng)建一個(gè)人都會(huì)重新創(chuàng)建這四個(gè)方法,那么100個(gè)人就創(chuàng)建了400個(gè)函數(shù),要是統(tǒng)計(jì)成千上萬人,消耗的內(nèi)存相當(dāng)大,這樣不妥
如何解決:
既然方法都是一樣的,那么就單獨(dú)抽離到一個(gè)對(duì)象中,實(shí)現(xiàn)復(fù)用這個(gè)對(duì)象就不會(huì)再重新創(chuàng)建了
const roster = []; // 花名冊(cè) const personBehavior = { say() { console.log("說話"); }, eat() { console.log("吃東西"); }, walk() { console.log("行走"); }, sleep() { console.log("睡覺"); }, }; for (let i = 0; i < 100; i++) { const person = { ID: i, name: "pangyu", age: "18", province: "山東", __proto__: personBehavior, }; roster.push(person); }
現(xiàn)在person的__proto__
屬性是personBehavior
公共方法,這其實(shí)就是原型的作用,避免公共方法的重復(fù)聲明,節(jié)省內(nèi)存,利于維護(hù)
功能模塊化
這樣實(shí)現(xiàn)了復(fù)用,但還不夠完美,我們可以把創(chuàng)建人信息放在一個(gè)單獨(dú)的createPerson
函數(shù)中,并讓公共屬性和這個(gè)方法聯(lián)系起來
const roster = []; // 花名冊(cè) function createPerson(i) { const person = {}; // 創(chuàng)建臨時(shí)對(duì)象 person.__proto__ = createPerson.prototype; // 臨時(shí)對(duì)象綁定原型(公共屬性) person.ID = i; person.name = "pangyu"; person.age = "18"; person.province = "山東"; return person; // 返回臨時(shí)對(duì)象 } createPerson.prototype = { say() { console.log("說話"); }, eat() { console.log("吃東西"); }, walk() { console.log("行走"); }, sleep() { console.log("睡覺"); }, }; for (let i = 0; i < 100; i++) { roster.push(createPerson(i)); }
這樣的功能模塊劃分較為清晰,那么在createPerson
函數(shù)中,JS之父發(fā)現(xiàn)這樣創(chuàng)建對(duì)象的操作非常常見,于是他就發(fā)明了new關(guān)鍵字來簡(jiǎn)化createPerson
中的操作
其中紅框內(nèi)的代碼其實(shí)屬于模版代碼,每創(chuàng)建一個(gè)對(duì)象都會(huì)走這樣的一套邏輯,只有給person
賦值自身屬性時(shí)才需要用戶手動(dòng)編寫,所以紅框中的代碼片段都會(huì)在new
中實(shí)現(xiàn)
使用new創(chuàng)建person
const roster = []; // 花名冊(cè) function createPerson(i) { // const person = {}; // 【省略】創(chuàng)建臨時(shí)對(duì)象 // person.__proto__ = createPerson.prototype; // 【省略】臨時(shí)對(duì)象綁定原型 // 綁定自身屬性 this.ID = i; this.name = "pangyu"; this.age = "18"; this.province = "山東"; // return person; // 【省略】返回臨時(shí)對(duì)象 } createPerson.prototype = { say() { console.log("說話"); }, eat() { console.log("吃東西"); }, walk() { console.log("行走"); }, sleep() { console.log("睡覺"); }, }; for (let i = 0; i < 100; i++) { roster.push(new createPerson(i)); }
回看new的實(shí)現(xiàn)
function MyNew(Con,...args){ const obj = Object.create(Con); // 創(chuàng)建臨時(shí)對(duì)象,綁定原型 const result = Con.apply(obj, args); // 調(diào)用構(gòu)造函數(shù),綁定this到臨時(shí)對(duì)象(賦值this自身屬性) return result instanceof Object ? result : obj; // 如果構(gòu)造函數(shù)返回值為對(duì)象類型,那么就返回,否則返回臨時(shí)對(duì)象 }
現(xiàn)在是不是對(duì)于new
有了更深的理解,其實(shí)它就是一個(gè)語法糖,把生成對(duì)象的模版代碼實(shí)現(xiàn)了, 用戶只需要關(guān)注自身屬性即可
總結(jié)
new執(zhí)行后做了什么
- 創(chuàng)建臨時(shí)對(duì)象/新對(duì)象
- 綁定原型(公共屬性)
- 指定this = 臨時(shí)對(duì)象(為this賦值自身屬性做準(zhǔn)備)
- 執(zhí)行構(gòu)造函數(shù)(this賦值自身屬性)
- 返回臨時(shí)對(duì)象(判斷構(gòu)造函數(shù)返回值是否為對(duì)象)
new的本質(zhì)是什么
語法糖,省略了創(chuàng)建對(duì)象所需的模版代碼
到此這篇關(guān)于深入了解JavaScript中的new關(guān)鍵字的文章就介紹到這了,更多相關(guān)JavaScript new內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JS實(shí)現(xiàn)批量上傳文件并顯示進(jìn)度功能
這篇文章主要介紹了JS實(shí)現(xiàn)批量上傳文件并顯示進(jìn)度功能,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-06-06layui輸入框中只允許輸入整數(shù)的實(shí)現(xiàn)方法
今天小編就為大家分享一篇layui輸入框中只允許輸入整數(shù)的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-09-09clientX,pageX,offsetX,x,layerX,screenX,offsetLeft區(qū)別分析
clientX,pageX,offsetX,x,layerX,screenX,offsetLeft區(qū)別分析,需要的朋友可以參考下。2010-03-03JavaScript子窗口調(diào)用父窗口變量和函數(shù)的方法
這篇文章主要介紹了JavaScript子窗口調(diào)用父窗口變量和函數(shù)的方法,涉及JavaScript窗口調(diào)用的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-10-10JS實(shí)現(xiàn)的車標(biāo)圖片提示效果代碼
這篇文章主要介紹了JS實(shí)現(xiàn)的車標(biāo)圖片提示效果代碼,涉及JavaScript鼠標(biāo)事件觸發(fā)頁面元素遍歷修改的相關(guān)實(shí)現(xiàn)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-10-10原生JS實(shí)現(xiàn)匯率轉(zhuǎn)換功能代碼實(shí)例
這篇文章主要介紹了原生JS實(shí)現(xiàn)匯率轉(zhuǎn)換功能代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05