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