前言
要實現(xiàn)手寫new
,關(guān)鍵在于先吃透它的本質(zhì)。new
作為 JavaScript 中創(chuàng)建對象的核心操作符,看似簡單的語法背后,藏著一套嚴謹?shù)膱?zhí)行邏輯。只有先弄清楚它究竟是什么—— 是連接構(gòu)造函數(shù)與實例對象的橋梁?還是激活原型鏈關(guān)聯(lián)的開關(guān)?再明確它能完成哪些核心功能—— 是初始化對象屬性,還是建立繼承關(guān)系?最后拆解它的執(zhí)行過程中每一步都發(fā)生了什么—— 從創(chuàng)建空對象到綁定原型,從執(zhí)行構(gòu)造函數(shù)到返回實例…… 搞懂了這些,手寫new的思路才會清晰起來。接下來,我們一起來揭露這個東西
new 是什么?
new
是JavaScript中用于創(chuàng)建對象實例的關(guān)鍵操作符,它是面向?qū)ο缶幊讨袑ο髮嵗暮诵臋C制。
我們通常利用new
來實例化一個對象:
function Person(name, age) {
this.name = name;
this.age = age;
this.Talk = function () {
console.log('我是' + this.name);
}
}
const person1 = new Person('張三', 25);
console.log(person1);
person1.Talk();
我們可以看到利用new
產(chǎn)生的實例繼承了構(gòu)造函數(shù)的屬性和方法,并且成功實例化了一個對象。
new 的過程中發(fā)生了什么?
當使用new
調(diào)用函數(shù)時,JavaScript引擎會執(zhí)行以下步驟:
- 創(chuàng)建新對象:創(chuàng)建一個全新的空對象
{}
- 鏈接原型:將這個新對象的
[[Prototype]]
(即__proto__
)鏈接到構(gòu)造函數(shù)的prototype
對象 - 綁定this:將構(gòu)造函數(shù)中的
this
綁定到這個新對象 - 執(zhí)行構(gòu)造函數(shù):執(zhí)行構(gòu)造函數(shù)中的代碼(通常用于初始化對象)
- 返回對象:如果構(gòu)造函數(shù)沒有返回對象,則自動返回這個新對象
當然,對于這5條,1
,3
就不用說了,
1
是基礎(chǔ)步驟,我們要返回一個實例化對象,必須得初始化一個,沒有米怎么蒸米飯呢?
3
的話,上一期的this
指向中有講過,傳送門??=>美麗的地方0^0~
2
,我們可以在瀏覽器中console.log(person1)
,查看它的__proto__
是否等于Person.prototype
4
,我們也可以隨便在構(gòu)造函數(shù)中加一句console.log('whatever u want')
,觀察它是否會執(zhí)行
5
,重點來咯!當構(gòu)造函數(shù)顯式返回一個對象時,new
操作符會忽略原本創(chuàng)建的新對象,直接返回構(gòu)造函數(shù)返回的這個對象。此時新對象的屬性初始化將被丟棄,只有返回對象的內(nèi)容會被保留。
構(gòu)造函數(shù)返回對象完整規(guī)則:
- 返回對象類型(包括數(shù)組、函數(shù)等)
→ 完全替代new
默認創(chuàng)建的對象 - 返回原始值(數(shù)字、字符串等)
→ 被忽略,仍然返回new
創(chuàng)建的新對象 - 沒有return語句
→ 正常返回new
創(chuàng)建的新對象
示例:
function Case1() {
this.a = 1;
return { b: 2 };
}
console.log(new Case1());
function Case2() {
this.a = 1;
return 123;
}
console.log(new Case2());
function Case3() {
this.a = 1;
}
console.log(new Case3());
手寫new
okk,既然我們都知道了你new
出一個對象安慰自己沒有對象的事實時會發(fā)生的事情了,我們開始手寫一個new
吧!
記住這靈魂的舞步~ :
- 創(chuàng)建新對象:創(chuàng)建一個全新的空對象
{}
- 鏈接原型:將這個新對象的
[[Prototype]]
(即__proto__
)鏈接到構(gòu)造函數(shù)的prototype
對象 - 綁定this:將構(gòu)造函數(shù)中的
this
綁定到這個新對象 - 執(zhí)行構(gòu)造函數(shù):執(zhí)行構(gòu)造函數(shù)中的代碼(通常用于初始化對象)
- 返回對象:如果構(gòu)造函數(shù)沒有返回對象,則自動返回這個新對象
ok,假設(shè)我們有一個構(gòu)造函數(shù)Person
,要利用我們的手寫new
創(chuàng)建一個實例,
那么首先我們要創(chuàng)建一個函數(shù),用來實現(xiàn)new
:
function Person(name, age) {
this.name = name;
this.age = age;
}
function myNew(){}
現(xiàn)在我們要實現(xiàn)創(chuàng)建一個新的空對象:
function myNew(){
var obj = {};
}
接下來,我們要確立原型,鏈接到構(gòu)造函數(shù),那么該怎么做呢?
既然我們要用到構(gòu)造函數(shù),那么我們應(yīng)該至少應(yīng)該拿到構(gòu)造函數(shù)吧,所以我們就要把構(gòu)造函數(shù)和所需要的形參傳遞進來!
function myNew(constructor,...args){
var obj = new Object();
}
接下來我們開始綁定prototype:
function myNew(constructor,...args){
var obj = new Object();
obj.__proto__ = constructor.prototype;
}
Next,開始激情♂地綁定this
到新的實例對象上,那么怎么樣能夠?qū)?gòu)造函數(shù)的this
綁定到obj
到上面呢?上一期我們學習了顯式綁定,我們可以利用call
、apply
、bind
方法來將其綁定到理想目標上:
function myNew(constructor,...args){
var obj = new Object();
obj.__proto__ = constructor.prototype;
constructor.bind(obj,...args);
}
這樣我們就成功了,下一步就是要執(zhí)行構(gòu)造函數(shù)了,我們可以用一個變量接受bind
的結(jié)果并執(zhí)行它:
function myNew(constructor,...args){
var obj = new Object();
obj.__proto__ = constructor.prototype;
var before = constructor.bind(obj,...args);
before();
}
最后利用一個變量接受結(jié)果,判斷構(gòu)造函數(shù)返回的結(jié)果是否符合要求,
如果不符合則返回新對象,
如果符合則返回構(gòu)造函數(shù)準備好的結(jié)果:
function myNew(constructor,...args){
var obj = new Object();
obj.__proto__ = constructor.prototype;
var before = constructor.bind(obj,...args);
var res = before();
return typeof res === 'object' ? res || obj : obj;
}
OK,看到這里大家肯定也知道我們可以優(yōu)化一部分了。我們可以把創(chuàng)建對象到綁定prototype
以及 從綁定this
到判斷結(jié)果這一段優(yōu)化:
function myNew(constructor,...args){
const obj = Object.create(constructor.prototype);
const res = constructor.apply(obj, args);
return typeof res === 'object' ? res || obj : obj;
}
總結(jié)
想要手寫一個new
,就要深深記住它在創(chuàng)建過程中會發(fā)生的事情,所以要記住以下五點!?。。。?!
- 創(chuàng)建新對象:創(chuàng)建一個全新的空對象
{}
- 鏈接原型:將這個新對象的
[[Prototype]]
(即__proto__
)鏈接到構(gòu)造函數(shù)的prototype
對象 - 綁定this:將構(gòu)造函數(shù)中的
this
綁定到這個新對象 - 執(zhí)行構(gòu)造函數(shù):執(zhí)行構(gòu)造函數(shù)中的代碼(通常用于初始化對象)
- 返回對象:如果構(gòu)造函數(shù)沒有返回對象,則自動返回這個新對象
轉(zhuǎn)自https://juejin.cn/post/7533521571568336938
該文章在 2025/8/5 9:22:58 編輯過