實現一個new操作符的具體實現步驟:
- 首先函數接受不定量的參數,第一個參數爲構造函數,接下來的參數被構造函數使用
- 然後內部創建一個空對象 obj
- 因爲 obj 對象需要訪問到構造函數原型鏈上的屬性,所以我們通過 setPrototypeOf 將兩者聯繫起來。這段代碼等同於 obj.proto = Con.prototype
- 將 obj 綁定到構造函數上,並且傳入剩餘的參數
- 判斷構造函數返回值是否爲對象,如果爲對象就使用構造函數返回的值,否則使用 obj,這樣就實現了忽略構造函數返回的原始值
/**
* 創建一個new操作符
* @param {*} Con 構造函數
* @param {...any} args 往構造函數中傳的參數
*/
function createNew(con,...args){
let obj = {}; //創建一個對象,因爲new操作符會返回一個對象
obj.__proto__ = con.prototype; //將對象與構造函數原型鏈接起來
let res = con.apply(obj,args); //將構造函數中的this指向這個對象,並傳遞參數
if(res instanceof Object){ // 判斷構造函數返回值是否爲對象
return res;
}else{
return obj;
}
}
function foo(name, age) {
this.name = name;
this.age = age;
//console.log(this); //此時this已經發生變化了
}
var f = createNew(foo,'Chocolate',18);
console.log(f);
注意:
一、new操作符的幾個作用:
- new操作符返回一個對象,所以我們需要在內部創建一個對象
- 這個對象,也就是構造函數中的this,可以訪問到掛載在this上的任意屬性
- 這個對象可以訪問到構造函數原型鏈上的屬性,所以需要將對象與構造函數鏈接起來
- 返回原始值需要忽略,返回對象需要正常處理
二、new操作符的特點:
- new通過構造函數Test創建處理的實例可以訪問構造函數中的屬性也可以訪問構造函數原型鏈上的屬性,所以:通過new操作符,實例與構造函數通過原型鏈連接了起來
- 構造函數如果返回原始值,那麼這個返回值毫無意義
- 構造函數如果返回對象,那麼這個返回值會被正常的使用,導致new操作符沒有作用
學如逆水行舟,不進則退