zoukankan      html  css  js  c++  java
  • JavaScript 新语法详解:Class 的私有属性与私有方法

    译者按: 为什么偏要用 # 符号?

    本文采用意译,版权归原作者所有

    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/

  • 相关阅读:
    Algebra, Topology, Differential Calculus, and Optimization Theory For Computer Science and Machine Learning 第50章 读书笔记(待更新)
    Algebra, Topology, Differential Calculus, and Optimization Theory For Computer Science and Machine Learning 第49章 读书笔记(待更新)
    Algebra, Topology, Differential Calculus, and Optimization Theory For Computer Science and Machine Learning 第48章 读书笔记(待更新)
    Spring Boot 中使用 Quartz 实现任务调度
    实战 FastDFS Java 客户端上传文件
    分布式文件系统之 FastDFS
    Java 持久层框架之 MyBatis
    C语言实现贪吃蛇
    [转载]分享三篇非常好的学习心得
    selenium加载cookie报错问题:selenium.common.exceptions.InvalidCookieDomainException: Message: invalid cookie domain
  • 原文地址:https://www.cnblogs.com/fundebug/p/10754650.html
Copyright © 2011-2022 走看看