【问题标题】:In ES6, how to override a private method in a super class?在 ES6 中,如何覆盖超类中的私有方法?
【发布时间】:2018-07-08 14:54:30
【问题描述】:

我正在学习 ES6 中的类...

我想以某种形式使用私有属性,以便只能从类的实例调用某些方法。

例如使用符号...

/* A.js */

const _privateMethod = Symbol('_privateMethod')
class A {
    [_privateMethod]() {
        return 'yup'
    }
    do() {
        return this[_privateMethod]()
    }
}

const a = new A()
a.do() /* yup */

..._privateMethod 不能直接调用。到目前为止一切顺利。

但是,我想知道如何在从 A 继承的类中重写 _privateMethod。例如,以下内容将不起作用:

/* B.js */

const _privateMethod = Symbol('_privateMethod')
class B extends A {
    [_privateMethod]() {
        return 'nope'
    }
}

const b = new B()
b.do() /* yup */

建议如何执行此操作?

【问题讨论】:

  • [_privateMethod] 仍然可以直接调用。您想将方法设为私有的原因是什么?
  • @Cruiser 我看不出这个问题(关于如何覆盖由符号标识的类方法)与您建议的副本有什么相似之处
  • 请注意,您并没有真正的私有方法。例如,您可以使用a [ Object.getOwnPropertySymbols(Object.getPrototypeOf(a))[0] ]() 从另一个无法直接访问_privateMethod 的文件中调用a[_privateMethod]
  • OOP 最佳实践是为了帮助开发人员,而不是被虔诚地观察并在脚下开枪。如果好处不清楚,那就不值得了。

标签: javascript ecmascript-6 symbols es6-class


【解决方案1】:

再次调用Symbol('_privateMethod') 会创建一个新的、不同的符号(即使它具有相同的描述)。您正在使用不同的密钥创建不同的方法,而不是覆盖原来的方法。

您将需要使用确切的相同 符号来定义子类中的方法。您可以从 Object.getOwnPropertySymbols(A.prototype) 获取它,也可以通过将 _privatMethod 符号作为常量从 A.js 导出并将其导入 B.js(与 class A 一起)。但是,如果你想让类可扩展,我建议根本不使用符号。

【讨论】:

  • 谢谢,这很有道理! (我开始认为使用所有公共方法更简单,下划线表示命名约定)
【解决方案2】:

在实践中使用编程概念的原因是因为它们为开发人员提供了一些好处,这也包括封装。如果它的弊大于利,这意味着它不应该被应用,或者它的应用方式是错误的。

JavaScript 没有提供封装作为语言特性。 Symbol 是一种可接受的实现方式,但它的特殊性可能使其不适合该任务。

作为私有(受保护)成员标识符的符号应始终与其所属的类一起导出:

export const _privateMethod = Symbol('_privateMethod');
export class A {
    [_privateMethod]() {/*...*/}
    /*...*/
}

...

import { _privateMethod, A } from './a';

class B extends A {
    [_privateMethod]() {/*...*/}
}

如果这不可能或不切实际,这意味着符号不适合封装,因为它提供了缺点而没有任何实际好处。

由于信息隐藏在 JavaScript 中不用于安全目的(符号可通过 Object.getOwnPropertySymbols 访问),封装机制的替代方法是使用匈牙利符号和/或 JSDoc 注释。它们为开发人员提供了有关公共接口的必要信息:

export class A {
    /** @protected */
    _privateMethod() {/*...*/}
    /*...*/
}

【讨论】:

    【解决方案3】:

    你可以使用Object.getOwnPropertySymbols()函数:

    const A = (function() {
      const _privateMethod = Symbol('_privateMethod')
      return class A {
          [_privateMethod]() {
              return 'yup'
          }
          do() {
              return this[_privateMethod]()
          }
      }
    }());
    
    (function() {
      const _privateMethod = Object.getOwnPropertySymbols(A.prototype)
        .find(x => x.toString() === 'Symbol(_privateMethod)')
      class B extends A {
          [_privateMethod]() {
              return 'nope'
          }
      }
      
      const b = new B()
      console.log(b.do());
    }());

    【讨论】:

      【解决方案4】:

      你已经有了正确的答案,检查一下

      const _privateMethod = Symbol('_privateMethod')
      class A {
          [_privateMethod]() {
              return 'yup'
          }
          do() {
              return this[_privateMethod]()
          }
      }
      
      const a = new A()
      document.write(a.do()+ "<br><br>" )
      
      class B extends A {
          [_privateMethod]() {
              return 'nope'
          }
      }
      
      const b = new B()
      document.write(b.do()+ "<br><br>")

      【讨论】:

        猜你喜欢
        • 2013-01-15
        • 2015-08-03
        • 2016-02-28
        • 2012-08-12
        • 2021-12-25
        • 2011-05-25
        • 1970-01-01
        • 2013-03-10
        • 2023-04-09
        相关资源
        最近更新 更多