當我們用new運算符new一個構造函數產生一個實例時,比如說: var obj = new Func 時,其背后的步驟是這樣的:
1:創建一個繼承自 Func.prototype 的新對象;
2:執行構造函數 Func ,執行的時候,相應的傳參會被傳入,同時上下文(this)會被指定為第一步創建的新實例;
3:如果構造函數返回了一個“對象”,那么這個對象會取代步驟1中new出來的實例被返回。如果構造函數沒有返回對象,那么new出來的結果為步驟1創建的對象。
注意:new Func 等同於new Func(),只能用在不傳遞任何參數的情況。
按照上述原理,寫一段代碼模擬new運算符的實現原理:
//new運算符原理實現 var new1 = function(fun){ var newObj = Object.create(fun.prototype); var returnObj = fun.call(newObj); if(typeof returnObj === 'object'){ return returnObj }else{ return newObj } }
其中 var newObj = Object.create(fun.prototype) 的意思是:創建一個新對象newObj,並讓 newObj.__proto__ 指向 fun,即 newObj.__proto__ === fun 返回true。
測試一下~
var strObj = new1(String); alert(strObj instanceof String); //true alert(strObj.__proto__.constructor === String); //true
可以看到,new1函數的運行效果和new運算符是一樣的。我們繼續給String的原型上添加一個方法,看看new1函數得到的strObj能否繼承到這個方法:
String.prototype.defineByN = function(){ alert("我是自定義方法"); } strObj.defineByN(); //彈出“我是自定義方法”
可以看到new1函數得到的strObj繼承了到這個方法。