提到new,肯定會和類和實體聯系起來,如:
function Func() { let x = 100; this.num = x + } let f = new Func();
上面的代碼,我們首先創建了一個函式,如果是用面向物件的說法就是創建了一個Function類的實體,如果直接執行這個函式,那它就是一個普通的函式,如果用new執行,則這個函式被稱為一個自定義的類,
如果是一個普通函式執行,他會如下做幾件事:
·形成一個全新的執行背景關系EC(Execution Context 執行環境)
·形成一個AO(Activation Object 活動物件)變數物件,初始化arguments和形參賦值
·初始化作用域鏈
·代碼執行
如果是new函式執行,它既有普通函式執行的一面,也有自己獨有的東西:
·默認創建一個物件,而這個物件就是當前類的實體
·宣告其this指向,讓其指向這個新創建的實體
·不論其是否寫return,都會把新創建的實體回傳,這里有個特殊點,如果用戶自己回傳內容,且回傳的是一個參考型別值,則會把默認回傳的實體給覆寫掉,此時回傳的值就不再是類的實體了
console.log(f); //=>{num:200} //f是Func這個類的實體 //相當于給創建的實體物件新增一個num的屬性 obj.num=200 (因為具備普通函式執行的一面,所以只有this.xxx=xxx才和創建的實體有關系,此案例中的x只是AO中的私有變數) console.log(f instanceof Func); //=>TRUE instanceof用來檢測某一個實體是否屬于這個類
每一次new出來的都是一個新的實體物件
console.log(f === f2); //=>false
既然知道了new都做了什么事情,我們重新一下new:
/* * 內置NEW的實作原理 * @params * Func:操作的那個類 * ARGS:NEW類的時候傳遞的實參集合 * @return * 實體或者自己回傳的物件 */ function _new(Func, ...args) { //默認創建一個實體物件(而且是屬于當前這個類的一個實體) let obj = {}; //也會把類當做普通函式執行 //執行的時候要保證函式中的this指向創建的實體 let result = Func.call(obj, ...args); //若客戶自己回傳參考值,則以自己回傳的為主,否則回傳創建的實體 if ((result !== null && typeof result === "object") || (typeof result === "function")) { return result; } return obj; }
我們試一下:
let f3 = _new(Func); console.log(f3); // =>{num: 200}
我們繼續測驗:
Func.prototype.log = function () { console.log('ok'); } let f4 = _new(Func); f4.log(); //=>Uncaught TypeError: f4.log is not a function
也就是說,Func原型上的方法其實體沒法呼叫,我們還需要修改:
/* * 內置NEW的實作原理 * @params * Func:操作的那個類 * ARGS:NEW類的時候傳遞的實參集合 * @return * 實體或者自己回傳的物件 */ function _new(Func, ...args) { //默認創建一個實體物件(而且是屬于當前這個類的一個實體) // let obj = {}; let obj = Object.create(Func.prototype); //也會把類當做普通函式執行 //執行的時候要保證函式中的this指向創建的實體 let result = Func.call(obj, ...args); //若客戶自己回傳參考值,則以自己回傳的為主,否則回傳創建的實體 if ((result !== null && typeof result === "object") || (typeof result === "function")) { return result; } return obj; }
這樣應該就可以了,
let f6 = _new(Func); f6.log(); //=>ok
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/148153.html
標籤:JavaScript
上一篇:Vue中的$Bus使用
下一篇:url相對路徑變成絕對路徑
