在很多面試中都會遇到這樣一道面試題:如何實現一個new?
實現一個new的簡單版本,其實就只有三步。話不多說,直接來。
首先我們需要一個構造函數,根據這個構造函數new 一個對象並打印在控制檯中來做參考。
function F(){
this.name = '我是一個構造函數';
};
console.log(new F());
在控制檯執行代碼會輸出一個對象
接下來我們用三步實現一個一模一樣的對象,每一步我們都打印一下,對比new生成的對象。
第一步:創建一個空對象
const obj = {};
console.log(obj);
第一步執行後我們有了一個{}(對象)還有一個__proto__ (原型),只不過我們的__proto__和new的__proto__明顯是不一樣的,所以接下來要讓它們變成一樣的!
第二步:改變空對象的原型鏈
obj.__proto__ = F.prototype;
console.log(obj);
與new的對比
這一步執行後基本就與new的對象有了同一個外殼了,最後只要把構造函數裏面的代碼整到obj中,就大功告成了。
obj.proto = F.prototype
對這一句有疑問的話,可以認真再理解一下原型鏈
第三步:繼承構造函數的屬性與方法
F.call(obj);
console.log(obj);
與new的對比
到這裏我們就完整創造出一個一模一樣的對象了。
這裏需要知道call都做了啥?
總結一下
function F(){
this.name = '我是一個構造函數';
};
// 實現new的三行代碼
const obj = {};
obj.__proto__ = F.prototype;
F.call(obj);
假設F函數有傳參數,我們也可以將三行代碼寫成一個函數,傳遞一個name參數,這樣我們就封裝好了一個簡單的類似new語法糖的方法。
const createObject = (name) => {
const obj = {};
obj.__proto__ = F.prototype;
F.call(obj,name);
return obj
}
再進一步假設F函數也要作爲一個參數傳遞到方法中
就可以改造成這樣
const createObject = (fn,name) => {
const obj = {};
obj.__proto__ = fn.prototype;
fn.call(obj,name);
return obj
}
假設參數不只一個name呢?這個可以思考一下,其實也不難。
new其實也是類似封裝的作用,可以讓我們快速的生成一個在原型鏈生態中的對象,沒有它js也可以繼續存在,我們可以通過自己的封裝。
對比java,沒有了new 它還能存在嗎?所以js只是有面向對象的編程實現,但是它本身並不是一門面向對象的語言。
文中如有紕漏,請在評論中指出。
最近開始準備面試了 預計7月初就開始投簡歷了
最近會更新一些刷面試的文章
後面面試了也會出一些面經
文章也發佈到了掘金
來點個贊啊哈哈