關鍵字new在調用構造函數的時候實際上進行了如下的幾個步驟:
- 創建一個新的對象
- 將構造函數的作用域賦值給這個新的對象(因此this指向了這個新的對象)
- 執行構造函數中的代碼(為這個新對象添加屬性)
- 返回新對象
我們寫一個函數,命名為objectFactory,來模擬new的效果,使用的時候像下面這樣:
function Person () {
……
}
// 使用 new
var student = new Person(……);
// 使用 objectFactory
var student = objectFactory(Person, ……)
接下來,我們按照new調用構造函數的四個步驟來實現objectFactory:
function objectFactory() {
// 創建一個新的對象
const obj = {}
// 獲取第一個參數,arguments是類數組,不可直接調用shift方法
//此外因為 shift 會修改原數組,所以 arguments 會被去除第一個參數
const Constructor = [].shift.call(arguments)
// 將obj的原型指向構造函數的原型對象,這樣obj就可以訪問構造函數原型上的屬性
obj.__proto__ = Constructor.prototype
// 將構造函數的this指向obj,這樣obj就可以訪問到構造函數中的屬性
Constructor.apply(obj, arguments);
// 返回 obj
return obj;
}
如果構造函數中返回了一個對象,則在實例中只能訪問到返回的對象中的屬性。
所以我們還需要判斷返回的值是不是一個對象,如果是一個對象,我們就返回這個對象,如果沒有,我們該返回什么就返回什么。
function objectFactory() {
const obj = {}
const Constructor = [].shift.call(arguments)
obj.__proto__ = Constructor.prototype
const res = Constructor.apply(obj, arguments);
return typeof res === 'object' ? res : obj;
}