JavaScript 新語法詳解:Class 的私有屬性與私有方法

来源:https://www.cnblogs.com/fundebug/archive/2019/04/23/10754650.html
-Advertisement-
Play Games

譯者按: 為什麼偏要用 符號? 原文 : "JavaScript's new private class fields" 譯者 : "Fundebug" 本文采用意譯,版權歸原作者所有 "proposal class fields" 與 "proposal private methods" 定義了 ...


譯者按: 為什麼偏要用 # 符號?

本文采用意譯,版權歸原作者所有

proposal-class-fieldsproposal-private-methods定義了 Class 的私有屬性以及私有方法,這 2 個提案已經處於 Stage 3,這就意味著它們已經基本確定下來了,等待被加入到新的 ECMAScript 版本中。事實上,最新的 Chrome 已經支持了 Class 私有屬性。

那麼,對於 Class 的私有屬性與私有方法,它們究竟是什麼呢?它們是怎樣工作的?為什麼要使用#符號來定義呢?

Class 的私有屬性語法如下:

class Point {
    #x;
    #y;

    constructor(x, y) {
        this.#x = x;
        this.#y = y;
    }

    equals(point) {
        return this.#x === point.#x && this.#y === point.#y;
    }
}

我們可以將其語法理解為 2 個部分:

  • 定義 Class 私有屬性
  • 引用 Class 私有屬性

定義 Class 私有屬性

私有屬性與公共屬性的定義方式幾乎是一樣的,只是需要在屬性名稱前面添加#符號:

class Foo {
    publicFieldName = 1;
    #privateFieldName = 2;
}

定義私有屬性的時候也可以不用賦值:

class Foo {
    #privateFieldName;
}

引用 Class 私有屬性

引用私有屬性也只需要使用#就好了。

class Foo {
    publicFieldName = 1;
    #privateFieldName = 2;
    add() {
        return this.publicFieldName + this.#privateFieldName;
    }
}

其中,this.#可以簡化,去掉 this 也沒問題,下麵兩種寫法是等價的:

method() {
  #privateFieldName;
}
method() {
  this.#privateFieldName;
}

在 Class 定義中引用 Class 實例的私有屬性

對於私有屬性,我們是不可以直接通過 Class 實例來引用的,這也是私有屬性的本來含義。但是有一種情況除外,在 Class 定義中,我們可以引用 Class 實例的私有屬性:

class Foo {
    #privateValue = 42;
    static getPrivateValue(foo) {
        return foo.#privateValue;
    }
}

Foo.getPrivateValue(new Foo()); // >> 42

其中,fooFoo的實例,在 Class 定義中,我們可以通過 foo 來引用私有屬性#privateValue

Class 的私有方法

Class 的私有屬性是提案proposal-class-fields的一部分,這個提案只關註 Class 的屬性,它並沒有對 Class 的方法進行任何修改。而 Class 的私有方法是提案proposal-class-fields的一部分。

Class 的私有方法語法如下:

class Foo {
    constructor() {
        this.#method();
    }
    #method() {
        // ...
    }
}

我們也可以將函數賦值給私有屬性:

class Foo {
    constructor() {
        this.#method();
    }

    #method = () => {
        // ...
    };
}

封裝(隱藏)私有屬性

我們不能直接通過 Class 實例引用私有屬性,我們只能在 Class 定義中引用它們:

class Foo {
  #bar;
  method() {
    this.#bar; // Works
  }
}
let foo = new Foo();
foo.#bar; // Invalid!

另外,要做到真正的私有的話,我們應該無法檢測這個私有屬性是否存在,因此,我們需要允許定義同名的公共屬性:

class Foo {
    bar = 1; // public bar
    #bar = 2; // private bar
}

如果我們不允許公共屬性與私有屬性同名,我們則可以通過給同名的公共屬性複製監測該私有屬性是否存在:

foo.bar = 1; // Error: `bar` is private! (報錯,說明私有屬性存在)

不報錯也行:

foo.bar = 1;
foo.bar; // `undefined` (賦值失敗,說明私有屬性存在)

對於 subclass 應該同樣如此,它也允許公共屬性與私有屬性同名:

class Foo {
    #fieldName = 1;
}

class Bar extends Foo {
    fieldName = 2; // Works!
}

關於 Class 私有屬性的封裝,可以參考Why is encapsulation a goal of this proposal?

為什麼使用#符號?

很多人都有一個疑問,為什麼 JS 不能學習其他語言,使用private來定義私有屬性和私有方法?為什麼要使用奇怪的#符號?

使用 private 的話,代碼要舒服很多:

class Foo {
  private value;

  equals(foo) {
    return this.value === foo.value;
  }
}

為什麼不使用 private 來定義私有屬性?

很多語言使用 private 來定義私用屬性,如下:

class EnterpriseFoo {
  public bar;
  private baz;
  method() {
    this.bar;
    this.baz;
  }
}

對於這些語言屬性,私用屬性和公共屬性的引用方式是相同的,因此他們可以使用 private 來定義私有屬性。

但是,對於 JavaScript 來說,我們不能使用 this.field 來引用私有屬性(我接下來會解釋原因),我們需要在語法層面上區分私有屬性和公共屬性。在定義和引用私有屬性的時候,使用#符號,私有屬性與公共屬性可以很好地區分開來。

為什麼引用私有屬性的時候需要#符號?

引用私有屬性的時候,我們需要this.#field,而不是this.field,原因如下:

  • 因為我們需要封裝私有屬性,我們需要允許公共屬性與私有屬性同名,因此私有屬性與公共屬性的引用方式必須不一樣。這一點我們在前文已經詳述。
  • 公共屬性可以通過this.field以及this['field']來引用,但是私有屬性不能支持this['field']這種方式,否則會破壞私有屬性的隱私性,示例如下:
class Dict extends null {
    #data = something_secret;
    add(key, value) {
        this[key] = value;
    }
    get(key) {
        return this[key];
    }
}

new Dict().get("#data"); // 返回私有屬性

因此,私有屬性與公共屬性的引用方式必須不一樣,否則會破壞this['field']語法。

  • 私有屬性與公共屬性的引用方式一樣的話,會導致我們每次都需要去檢查屬性是公共的還是私有的,這會造成嚴重的性能問題。

這篇文章遵循Creative Commons Attribution 4.0 International License

參考

關於Fundebug

Fundebug專註於JavaScript、微信小程式、微信小游戲、支付寶小程式、React Native、Node.js和Java線上應用實時BUG監控。 自從2016年雙十一正式上線,Fundebug累計處理了10億+錯誤事件,付費客戶有Google、360、金山軟體、百姓網等眾多品牌企業。歡迎大家免費試用

版權聲明

轉載時請註明作者Fundebug以及本文地址:
[https://blog.fundebug.com/2019/04/23/javascript-class-private-field-and-private-method/


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

-Advertisement-
Play Games
更多相關文章
  • 最近公司有需求要做一些可視化的功能。之前一直都是用Echarts做的,但是Echarts現在滿足不了我們的需求,經過多方請教,查找發現只有D3可以滿足我們的需求,而且可以完美的適用到react框架中。第一次接觸到D3,發現這些圖標的可交互性非常豐富,而且動畫流暢簡潔。 所以,打算學習D3並且應用到項 ...
  • 今天練習一個小demo, 從本地讀取圖片, 然後實現類似淘寶放大鏡的效果, 再加兩個需求 1 .可以調節縮放比例,預設放大兩倍 2 . 圖片寬高自適應, 不固定寬高 話不多說先看效果: 原理:1, 右側放大區域的大小等於左側半透明滑塊大小乘以縮放倍數 2, 右側放大區域圖片的原始尺寸要和 左側圖片一 ...
  • <html><body> <h3>js控制文件上傳數量</h3> <form action="" enctype="multipart/form-data"> <input type="file" name="file" multiple="multiple" onchange="fileCount ...
  • 一、什麼是小程式? 基於微信的可以為用戶提供一些服務的web項目,利用微信提供的介面可以讓所有開發者使用到微信的原生能力,去完成一些之前做不到或者難以做到的事情。 二、小程式開發工具以及語言? 小程式需要用到微信提供的小程式開發工具,​小程式的主要開發語言是 JavaScript 。 三、小程式與普 ...
  • 項目中經常遇到要選擇城市。用到三級聯動的方式 微信小程式的 組件 是三級聯動的,但是無法自定義,這讓我們心痛不已,值得我們欣慰的 picker view 組件是可以自定義添加多個選項,但還是無法聯動。既然這樣那就自己寫一個聯動。 做到如下圖所示: 分為動態獲取地址 引用靜態文件獲取地址 <! mor ...
  • 轉自:https://www.cnblogs.com/kidsitcn/p/7182274.html 比例尺函數是這樣的javascript函數: 接收通常是數字,日期,類別等data輸入並且: 返回一個代表可視化元素的值,比如坐標,顏色,長度或者半徑等 比例尺通常用於變換(或者說映射)抽象的數據值 ...
  • 做法就是使用iframe標簽 1.text,pdf的文件預覽 <iframe class="filename" :src="文件的地址" width='100%' height='600' frameborder='1' ></iframe> 2.doc,xls,ppt等office的預覽 <ifr ...
  • 一、對象的擴展 1.1對象屬性名錶達式 ES6可以在JSON中使用[]包裹一個key的名字。此時這個key將用表達式作為屬性名(被當做變數求值),這個key值必須是字元串。 1.2 Object.assign()方法 該方法用於對象的合併,將源對象的所有可枚舉的屬性,複製到目標對象。 Object. ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...