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
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...