在 ES6 中,如何覆盖 super class 中的私有方法?

In ES6, how to override a private method in a super class?

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

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

例如使用 Symbol...

/* A.js */

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

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

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

但是,我想知道如何在继承自 A 的 class 中覆盖 _privateMethod。例如,以下内容将不起作用:

/* B.js */

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

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

建议如何执行此操作?

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

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

您可以使用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());
}());

您已经有了正确答案,请查看此

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>")

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

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

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

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

...

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

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

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

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

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