為啥要用new: 在javascript中, 通過new可以產生原物件的一個例項物件,而這個例項物件繼承了原物件的屬性和方法。
new操作符幹了什麼:
- 建立一個新物件。
- 新物件隱式原型連結到建構函式顯式原型。
- 執行建構函式並將建構函式作用域指向新物件。
- 返回新物件。
new的過程中遇到的坑一:
我們看到:new Function
返回的是一個函式,new Object
返回的是一個物件,那麼什麼是普通物件什麼是函式物件?
通過查詢資料發現有這麼一句話:凡是通過 new Function()
建立的物件都是函式物件,其他的都是普通物件。
new的過程中遇到的坑二:
我們看到new一個普通物件報錯,new一個函式物件才可以,對於這個結果很好奇為什麼?於是又查資料。
原型物件:
1).顯式原型: 每個函式物件都有prototype屬性,稱為顯式原型
2).隱式原型: 每個普通物件都有_proto_屬性,指向的是相對應的建構函式的prototype,稱為隱式原型
複製程式碼
是不是可以這麼理解,new一個普通物件,因為只有函式物件才有prototype
屬性,所以普通物件無法通new來建立一個新物件。只有通過函式物件來用new建立一個新的普通物件。
分析上面步驟的具體內容:
- new就是根據一個a(函式)物件建立了一個新的b(普通)物件。
- b屬於普通物件,那麼就有
__proto__
屬性,普通物件的__proto__
屬性指向他的建構函式(函式物件)的prototype
,所以a是b的建構函式,b是a的例項物件。 - 通過執行建構函式給b物件新增屬性,建構函式的this指向b物件。
具體實現步驟:
function _new (fn) {
var obj = {
__proto__ : fn.prototype,
};
var res = fn.call(obj);
return Object.prototype.toString.call(res) === "[object Object]" ? res : obj;
}
複製程式碼
我們來執行一下程式碼:
可以看到我們實現了new操作符所幹的事。 但是有這種情況:var o3 = new fun ('tom');
,而且如果建構函式包含好幾個屬性,在new的過程中,有可能會傳入多個引數。
我們需要改造一下:
function _new (fn) {
return function () { // 返回一個函式,呼叫此函式時傳入的引數達到new帶引數的目的。
var obj = {
__proto__ : fn.prototype,
};
var res = fn.apply(obj, arguments);
return Object.prototype.toString.call(res) === "[object Object]" ? res : obj;
}
}
複製程式碼
我們再來執行一下程式碼:
雖然沒有像new那麼簡結,但是也算是實現了我們想要的。當然使用閉包的方式會有記憶體洩漏的風險!所以我們還可以改造一下:
function _new () {
var fn = [].shift.call(arguments);
//var ags = [].prototype.slice.call(arguments, 1);
var obj = {
__proto__ : fn.prototype,
};
var res = fn.apply(obj, arguments);
return Object.prototype.toString.call(res) === "[object Object]" ? res : obj;
}
複製程式碼
完美!
如果上面分析有誤,請及時在評論區指正,謝謝。