简体   繁体   中英

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

I'm learning about classes in ES6...

I'd like to use private properties, in some form, so that only certain methods can be called from an instance of a class.

For example using Symbol...

/* A.js */

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

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

..._privateMethod cannot be called directly. So far so good.

However, I am wondering how to then go about overriding _privateMethod in a class that inherits from A. For example, the following will not work:

/* B.js */

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

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

How is it recommended to do this?

Calling Symbol('_privateMethod') again creates a new, distinct symbol (even if it has the same description). You are creating a different method with a different key, not overwriting the original one.

You will need to use the exact same symbol to define the method in the subclass. You can either get it from Object.getOwnPropertySymbols(A.prototype) or by exporting the _privatMethod symbol as a constant from A.js and importing it in B.js (together with the class A ). However, if you want to make the class extensible, I would recommend to simply not use symbols at all.

The reason why programming concepts are used in practice is because they provide some benefits to a developer, this includes encapsulation, too. If it provides more disadvantages than benefits, this means that it shouldn't be applied, or the way it was applied was wrong.

JavaScript doesn't have provide encapsulation as language feature. Symbol is an acceptable way to implement it, but it has its specificity that can make it unsuitable for the task.

A symbol that serves as an identifier for private (protected) member should always be exported together with a class it belongs to:

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

...

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

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

If this is not possible or practical, this means that a symbol is inappropriate choice for encapsulation, because it provides disadvantages without any real benefits.

Since information hiding doesn't serve security purposes in JavaScript (symbols are accessible with Object.getOwnPropertySymbols ), the alternative to encapsulation mechanism is the use of Hungarian notation and/or JSDoc annotations. They provide a developer with necessary information about public interface:

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

You can use the Object.getOwnPropertySymbols() function:

 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()); }()); 

you already has the right answer, check this

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM