理解new和實現一個new

suydCao發表於2018-11-17

為啥要用new: 在javascript中, 通過new可以產生原物件的一個例項物件,而這個例項物件繼承了原物件的屬性和方法。

new操作符幹了什麼:

  1. 建立一個新物件。
  2. 新物件隱式原型連結到建構函式顯式原型。
  3. 執行建構函式並將建構函式作用域指向新物件。
  4. 返回新物件。

new的過程中遇到的坑一:

理解new和實現一個new
我們看到:new Function返回的是一個函式,new Object返回的是一個物件,那麼什麼是普通物件什麼是函式物件?

通過查詢資料發現有這麼一句話:凡是通過 new Function() 建立的物件都是函式物件,其他的都是普通物件。

new的過程中遇到的坑二:

理解new和實現一個new

我們看到new一個普通物件報錯,new一個函式物件才可以,對於這個結果很好奇為什麼?於是又查資料。

原型物件:

1).顯式原型: 每個函式物件都有prototype屬性,稱為顯式原型
2).隱式原型: 每個普通物件都有_proto_屬性,指向的是相對應的建構函式的prototype,稱為隱式原型
複製程式碼

是不是可以這麼理解,new一個普通物件,因為只有函式物件才有prototype屬性,所以普通物件無法通new來建立一個新物件。只有通過函式物件來用new建立一個新的普通物件。

分析上面步驟的具體內容:

  1. new就是根據一個a(函式)物件建立了一個新的b(普通)物件。
  2. b屬於普通物件,那麼就有__proto__屬性,普通物件的__proto__屬性指向他的建構函式(函式物件)的prototype,所以a是b的建構函式,b是a的例項物件。
  3. 通過執行建構函式給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和實現一個new
可以看到我們實現了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和實現一個new
雖然沒有像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;
}
複製程式碼

理解new和實現一個new
完美! 如果上面分析有誤,請及時在評論區指正,謝謝。

相關文章