理解new和實現一個new

爲啥要用new: 在javascript中, 經過new能夠產生原對象的一個實例對象,而這個實例對象繼承了原對象的屬性和方法。javascript

new操做符幹了什麼:java

  1. 建立一個新對象。
  2. 新對象隱式原型連接到構造函數顯式原型。
  3. 執行構造函數並將構造函數做用域指向新對象。
  4. 返回新對象。

new的過程當中遇到的坑一:bash

咱們看到: new Function返回的是一個函數, new Object返回的是一個對象,那麼什麼是普通對象什麼是函數對象?

經過查找資料發現有這麼一句話:凡是經過 new Function() 建立的對象都是函數對象,其餘的都是普通對象。閉包

new的過程當中遇到的坑二:app

咱們看到new一個普通對象報錯,new一個函數對象才能夠,對於這個結果很好奇爲何?因而又查資料。函數

原型對象:ui

1).顯式原型: 每一個函數對象都有prototype屬性,稱爲顯式原型
2).隱式原型: 每一個普通對象都有_proto_屬性,指向的是相對應的構造函數的prototype,稱爲隱式原型
複製代碼

是否是能夠這麼理解,new一個普通對象,由於只有函數對象纔有prototype屬性,因此普通對象沒法通new來建立一個新對象。只有經過函數對象來用new建立一個新的普通對象。this

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

  1. new就是根據一個a(函數)對象建立了一個新的b(普通)對象。
  2. b屬於普通對象,那麼就有__proto__屬性,普通對象的__proto__屬性指向他的構造函數(函數對象)的prototype,因此a是b的構造函數,b是a的實例對象。
  3. 經過執行構造函數給b對象添加屬性,構造函數的this指向b對象。

具體實現步驟:prototype

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;
}
複製代碼

完美! 若是上面分析有誤,請及時在評論區指正,謝謝。
相關文章
相關標籤/搜索