[toc]javascript
new
操做符經過執行自定義構造函數或者js內置構造函數,從而生成一個實例對象。java
mdn上把內部操做大概分爲4步:面試
- 建立一個空的簡單JavaScript對象(即{ } );
- 連接該對象(即設置該對象的構造函數)到另外一個對象 ;
- 將步驟1新建立的對象做爲this的上下文 ;
- 若是該函數沒有返回對象,則返回this。
經過一個簡單的demo感覺下上面的步驟segmentfault
function Person (name){ this.name = name } let p = new Person('jack'); console.log(`p:`, p); // { name: 'jack' } console.log(`p.__proto__===Person.prototype:`,p.__proto__===Person.prototype); //true
能夠看到new操做符執行Person構造函數後,返回了一個內部建立的新對象,而且以這個對象爲上線文環境執行了一遍Person函數,最後將其返回,同時對象p的原型屬性指向構造函數的原型,這樣也就保證了實例可以訪問在構造函數原型中定義的屬性和方法。數組
上面的demo中構造函數是沒有返回值的,若是說構造函數有返回值呢,以下app
function Person (name){ this.name = name; return {age: 18} } let p = new Person('jack'); console.log(`p:`, p); // { age: 18 }
若是構造函數最後返回了一個對象,就會直接將其返回,而不是內部建立的新對象。函數
通過測試發現,除了返回對象,若是返回其餘類型,只要最後返回的類型爲引用類型object
或者function
(Function
,Object
,Array
,Date
,Error
,Regexp
,要排除null
,由於typeof null === 'object'
)就會直接將其返回,而其餘基本類型都會返回內部新建立的對象。post
這裏咱們嘗試經過封裝一個myNew
方法模擬new操做符的主要功能:接受若干參數,第一個參數爲構造函數ctr
,其他爲構造器所需參數,myNew(ctr, arg1, arg2,...)
測試
這裏的第一步把mdn中的一、2步放在了一塊兒:建立一個新對象,並將其__proto__
屬性指向構造函數的prototype
屬性this
function myNew(ctr) { let obj = Object.create(ctr.prototype); }
也可使用以下方法
function myNew (ctr){ let obj = {}; obj.__proto__ = ctr.prototype; }
獲取到參數以後,之內部新建立的對象obj
爲上線文執行構造函數,做用是爲obj
賦值
function myNew(ctr) { let obj = Object.create(ctr.prototype); const args = [].slice.call(arguments, 1); let result = ctr.apply(obj, args); console.log(`obj:`,obj); }
上面的const args = [].slice.call(arguments, 1);
用於將arguments
類數組轉爲數組並獲取參數,也能夠經過Array.form(arguments).slice(1)
或者[...arguments].slice(1)
實現。
對執行構造函數後的返回值result
作兼容處理。
若是構造函數最終返回對象、函數、數組、日期等其餘引用類型及Symbol,會將其直接返回,其餘基本類型及null
、undefined
會返回內部新建立的對象實例。
function myNew(ctr) { let obj = Object.create(ctr.prototype); const args = [].slice.call(arguments, 1); let result = ctr.apply(obj, args); var isObj = (typeof result === 'object' && result !== null); var isFn = typeof result === 'function'; return (isObj || isFn) ? result : obj; }
最後,簡單測試一下
沒有返回值
function Person(name) { this.name = name; } let p = myNew(Person,'jack'); console.log(`p:`,p);
有返回值
function Person(name) { this.name = name; return {age: 33} } let p = myNew(Person,'jack'); console.log(`p:`,p);