在ES6中,如何覆盖超类中的私有方法?

时间:2018-01-29 20:13:37

标签: javascript ecmascript-6 symbols es6-class

我正在学习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 */

如何建议这样做?

4 个答案:

答案 0 :(得分:3)

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

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

答案 1 :(得分:2)

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

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

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

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() {/*...*/}
    /*...*/
}

答案 2 :(得分:0)

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

答案 3 :(得分:0)

你已经有了正确的答案,请查看

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