JS中new的實現原理及重寫

来源:https://www.cnblogs.com/ronaldo9ph/archive/2020/02/19/12331716.html
-Advertisement-
Play Games

提到new,肯定會和類和實例聯繫起來,如: function Func() { let x = 100; this.num = x + } let f = new Func(); 上面的代碼,我們首先創建了一個函數,如果是用面向對象的說法就是創建了一個Function類的實例,如果直接執行這個函數, ...


提到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

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Kotlin Tutorials系列文章 想寫一個有實用價值的Kotlin筆記, 讓一線開發一看就懂, 看完就能上手. 當然官方文檔更有參考價值了. 這個系列相對於官方文檔的大而全來說, 最主要優勢是: 自己寫的比較親切(??). 有一些自己的思路和二次梳理. 可以作為一個側面參考. 這個flag立 ...
  • 一、透視屬性 1.什麼是透視 透視簡單來說就是近大遠小 2.​註意點:一定要註意,透視屬性必須添加到需要呈現近大遠小效果的​元素的父元素。 3.​格式:perspective:數字px; 這裡的數字代表透視的大小距離。 <!DOCTYPE html> <html lang="en"> <head> ...
  • 常見的CSS3選擇器包含:常用基本、屬性、偽類、層級(組合)選擇器,具體使用情況建議先閱讀css選擇器四大類:基本、組合、屬性、偽類對於選擇器的使用有一個基本瞭解,選擇器的作用在於通過它找到元素,並且給它添加屬性樣式。 常用的選擇器有:標簽、id、類、關聯(通過父集找到子集)組合選擇器,註意html... ...
  • 二進位和八進位數值表示法 ES6提供了二進位和八進位數值的新寫法,分別首碼 0b(或0B)、 0o(或0O)然後跟上二進位、八進位值即可。 二進位(Binary)表示法新寫法:首碼 0b 或 0B。 let binary = 0b010101; // 21 let binary2 = 0B01011 ...
  • 點擊添加群聊 今天在整理百度雲盤裡的資源,這幾年累計了不少軟體和教程。 在這特殊的時期里,先給大家分享一波。圖片里的文件夾就是目錄, 加入群聊免費領取 好資源就是要大家一起共用, 你們也不用到處在網上找資源, 或者幫別人轉發到朋友圈才能得到。 只要是我有的,而你也剛好需要,那我願意和你分享。 除了軟 ...
  • 變數提升 聲明的變數會提升到函數或全局作用域頂部 簡單例子 函數提升 函數寫法:函數表達式、函數聲明、Function構造函數(這種不推薦).其中函數表達式不會 函數提升 , 函數聲明 會函數提升。 我們都知道程式在執行時是從上往下執行的,而這裡 在定義之前就調用了為什麼不報錯? 實例一 值為多少? ...
  • 1、首先是設計稿 2、然後使用PxCook進行尺寸標註 3、字體信息去PS里看 4、首頁框架代碼編寫 index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>index</title> <lin ...
  • var eleLink = document.createElement('a'); eleLink.href = "/wordpress/?p=9227"; console.log(eleLink.href); ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...