參考源:該問答串的所有人
連接:https://www.zhihu.com/question/36440948
來源:知乎
由MDN的解釋會經過四步
- 創建一個空的簡單JavaScript對象(即 {});
- 鏈接該對象(即設置該對象的構造函數)到另一個對象;
- 將步驟1新創建的對像作為 this 的上下文;
- 如果該函數沒有返回對象,則返回 this。
看起來有夠文謅謅,我們來用自己的代碼描寫看看
function Foo() {}
var instance = new Foo()
恩就是創建實例,那裡面到底發生甚麼呢
function Foo() {}
let realInstance = new Foo()
console.log(realInstance);
function newInstance(constructor) {
let obj = {}
obj.__proto__ = constructor.prototype
return obj
}
let testInstance = newInstance(Foo)
console.log(testInstance);
看一下打印的樣子
感覺沒啥毛病,可是如果我們這樣
function Foo(obj) {
this.name = obj.name
this.age = obj.age
}
let realInstance = new Foo({
name: 'Mike',
age: 5
})
console.log(realInstance);
function newInstance(constructor) {
let obj = {}
obj.__proto__ = constructor.prototype
return obj
}
let testInstance = newInstance(Foo)
console.log(testInstance);
所以我們現在要解決我們創造的new沒辦法賦予實例特性
為啥要綁定this呢?
因為函數在定義時使用到了this,我們必須把this綁定給obj
其實要解決就是執行
function Foo(obj) {
this.name = obj.name
this.age = obj.age
}
let realInstance = new Foo({
name: 'Mike',
age: 5
})
console.log(realInstance);
function newInstance(constructor, argInFoo) {
let obj = {}
obj.__proto__ = constructor.prototype
constructor.call(obj, argInFoo)
return obj
}
let testInstance = newInstance(Foo, {
name: 'Mike',
age: 5
})
console.log(testInstance);
現在看起來又更完善了!!但是我們如果去檢查instanceof 的話呢?
console.log(testInstance instanceof Foo);
可以完全沒毛病!! 所以我們成功模擬了new!!!
先來看看我們的代碼
function newInstance(constructor, argObj) {
let obj = {}
obj.__proto__ = constructor.prototype
constructor.call(obj, argObj)
return obj
}
我們可以發現我們是假設創建實例的構造函數只能傳入一個obj 這會導致我們創建實例沒那麼自由,比方說這樣
// 定義了另一個構造函數Bar
function Bar(name, age) {
this.name = name
this.age = age
}
let realInstance = new Bar('Mike', 5)
console.log(realInstance);
function newInstance(constructor, argObj) {
let obj = {}
obj.__proto__ = constructor.prototype
constructor.call(obj, argObj)
return obj
}
let testInstance = newInstance(Bar, 'Mike', 5)
console.log(testInstance);
明明我們正確使用,但創建了卻和真的實例不一樣
所以我們的目標是甚麼?
不管Foo定義長怎樣,只要我們正確傳遞參數就可以創建實例
因此我們要這樣去定義
// 這裡用到了rest參數,讓所有剩餘參數都傳入
function newInstance(constructor, ...resArg) {
let obj = {}
obj.__proto__ = constructor.prototype
// 因為resArg會被當成數組,所以我們改用apply會方便超多
constructor.apply(obj, argObj)
return obj
}
好了這樣我們真的完成了全部!!