⚠ 預備知識:
- 了解原型和原型鏈
- 了解
this
綁定
1 new 運算符簡介
MDN文檔:
new
運算符創建一個用戶定義的對象類型的實例或具有構造函數的內置對象的實例。
class Person {
constructor(name) {
this.name = name;
}
}
// 創建自定義對象類型的實例
const person = new Person('小明')
// 創建具有構造函數的內置對象的實例
const date = new Date()
new
的作用:創建對象的實例
2 new 究竟干了什么事
上面說了new
的作用是創建對象的實例,那么它究竟是怎么創建實例的,內部干了哪幾件事?
以new Person()
為例,當它執行時,會發生以下事情:
- 創建一個空的簡單
JS
對象
const obj = {}
- 給這個對象添加屬性
__proto__
,並將該屬性鏈接到構造函數的原型對象
obj.__proto__ = Person.prototype
- 調用構造函數
Person
,並將this
綁定到新創建的對象obj
Person.apply(obj)
- 如果構造函數沒有顯式返回一個對象,則返回新創建的對象,即
obj
3 模擬實現 new 運算符
如上所述,new
運算符就干了這么4
件事,下面我們就根據這4個步驟用函數來模擬實現new
(面試手寫代碼)
const _new = function(constructor, ...args) {
const obj = {}
obj.__proto__ = constructor.prototype
const res = constructor.apply(obj, args)
// 這一步在"補充"中會詳細解釋
return res instanceof Object ? res : obj
}
代碼非常簡單,就是按照上面4
步,一步一步寫就可以了
4 補充
-
ES5
提供了Object.create
方法,該方法可以創建一個對象,並讓新對象的__proto__
屬性指向已經存在的對象。所以我們可以使用這個方法合並1、2兩步
const obj = Object.create(constructor.prototype)
// 等價於
const obj = {}
obj.__proto__ = constructor.prototype
-
對於第
4
步,再解釋一下-
如果構造函數沒有顯式
return
(通常情況)那么
person
就是新創建的對象obj
-
如果構造函數返回的不是一個對象,比如
1
、"abc"
那么
person
還是新創建的對象obj
-
function Person() {
...
return 1
}
-
如果構造函數顯式返回了一個對象,比如
{}
、function() {}
那么
person
就不是新創建的對象obj
了,而是顯式return
的這個對象
function Person() {
// 函數也是對象
return function() {}
}
所以我們在_new
函數最后一句代碼是:
return res instanceof Object ? res : obj
- 注意,模擬實現的函數
_new
傳入的參數只能是構造函數,不能是類
class Animal { ...}_new(Animal)// 會報錯:Class constructor Animal cannot be invoked without 'new'// 類只能通過new來創建實例