深入理解New操作符
前言
當我們對函數(shù)進行實例化時,需要用new操作符來實現(xiàn)。那么,對于它的底層實現(xiàn)原理你是否清楚呢?
原理分析
我們通過一個具體的例子來看下一個函數(shù)在new之后都能做些什么,如下所示:
function Person(name, age) {
this.name = name;
this.age = age;
this.height = "175cm";
this.bodyWeight = "65kg";
return "some anything";
}
Person.prototype.dailyExercise = "300 kcal";
Person.prototype.printBodyWeight = function() {
console.log(this.name + "體重為: " + this.bodyWeight);
};
接下來,我們用new關(guān)鍵字將Person函數(shù)進行實例化,我們發(fā)現(xiàn)實例化后,可以訪問到:
- 函數(shù)內(nèi)部的屬性
- 函數(shù)原型上的屬性
const person = new Person("神奇的程序員", "22");
console.log(person.age);
console.log(person.bodyWeight);
console.log(person.dailyExercise);
person.printBodyWeight();
眼尖的開發(fā)者可能已經(jīng)發(fā)現(xiàn)我們的構(gòu)造函數(shù)中返回了一個字符串,它是屬于基本類型,如果我們返回一個對象會發(fā)生什么?
function Person(name, age) {
return {
bodyWeight: this.bodyWeight
};
}
再次運行代碼后,我們發(fā)現(xiàn):
只能訪問我們在構(gòu)造函數(shù)中所返回的屬性。
構(gòu)造函數(shù)中聲明的其它屬性以及掛載在原型上的屬性均無法訪問。
實現(xiàn)思路
經(jīng)過前面的分析,我們知道了函數(shù)在new完之后會返回一個新的對象,這個對象上掛載了構(gòu)造函數(shù)內(nèi)的所有屬性以及函數(shù)原型上的所有屬性。
我們在實現(xiàn)的時候,也需要建立一個新的對象,這個對象上需要包含構(gòu)造函數(shù)里的屬性,因此我們可以使用apply方法來給此對象添加新屬性。
在深入理解原型鏈與繼承文章中,我們知道實例的 __proto__?屬性會指向構(gòu)造函數(shù)的prototype,建立起這樣的關(guān)系后,實例才可以訪問原型上的屬性。
有了這些知識點作為鋪墊后,我們就可以寫出這個模擬函數(shù)了,如下所示:
- 創(chuàng)建一個對象用來存儲構(gòu)造函數(shù)的屬性
- 從arguments中取出第一個參數(shù),這個參數(shù)便是調(diào)用時的構(gòu)造函數(shù)
- 將新對象的原型通過__proto__?指向構(gòu)造函數(shù)的prototype
- 通過apply方法改變構(gòu)造函數(shù)的this指向,從而實現(xiàn)將構(gòu)造函數(shù)內(nèi)部的屬性添加進新創(chuàng)建的對象中
- 判斷構(gòu)造函數(shù)是否有返回值
有返回值且其類型為一個對象或者一個函數(shù),則返回構(gòu)造函數(shù)的返回值
否則就返回我們新創(chuàng)建的對象
function instantiateFactory() {
const obj = {};
const Constructor = [].shift.call(arguments);
obj.__proto__ = Constructor.prototype;
const result = Constructor.apply(obj, arguments);
if (result && (typeof result == "object" || typeof result == "function")) {
return result;
}
return obj;
}
測試用例
我們用原理分析中的例子來驗證下我們實現(xiàn)的這個工廠函數(shù)能否正確執(zhí)行。
const factory = instantiateFactory(Person, "神奇的程序員", "22");
console.log(factory.age);
console.log(factory.bodyWeight);
console.log(factory.dailyExercise);
factory.printBodyWeight();
假設(shè)函數(shù)沒有返回值或者返回值是一個字符串類型時,執(zhí)行結(jié)果如下所示:
當函數(shù)的返回值是一個對象時,執(zhí)行結(jié)果如下所示: