模擬實現new
首先我們要知道new
做了什麼
- 創建一個新對象,並繼承其構造函數的
prototype
,這一步是爲了繼承構造函數原型上的屬性和方法 - 執行構造函數,方法內的
this
被指定爲該新實例,這一步是爲了執行構造函數內的賦值操作 - 返回新實例(規範規定,如果構造方法返回了一個對象,那麼返回該對象,否則返回第一步創建的新對象)
// new是關鍵字,這裏我們用函數來模擬,new Foo(args) <=> myNew(Foo, args)
function myNew(foo, ...args) {
// 創建新對象,並繼承構造方法的prototype屬性, 這一步是爲了把obj掛原型鏈上, 相當於obj.__proto__ = Foo.prototype
let obj = Object.create(foo.prototype)
// 執行構造方法, 併爲其綁定新this, 這一步是爲了讓構造方法能進行this.name = name之類的操作, args是構造方法的入參, 因爲這裏用myNew模擬, 所以入參從myNew傳入
let result = foo.apply(obj, args)
// 如果構造方法已經return了一個對象,那麼就返回該對象,否則返回myNew創建的新對象(一般情況下,構造方法不會返回新實例,但使用者可以選擇返回新實例來覆蓋new創建的對象)
return Object.prototype.toString.call(result) === '[object Object]' ? result : obj
}
// 測試:
function Foo(name) {
this.name = name
}
const newObj = myNew(Foo, 'zhangsan')
console.log(newObj) // Foo {name: "zhangsan"}
console.log(newObj instanceof Foo) // true
Object.create()
方法創建一個新對象,並使用現有的對象來提供新創建的對象的__proto__。
參考文檔:2萬字 | 前端基礎拾遺90問