How to inherit a private member in JavaScript? - javascript

is there a way in JavaScript to inherit private members from a base class to a sub class?
I want to achieve something like this:
function BaseClass() {
var privateProperty = "private";
this.publicProperty = "public";
}
SubClass.prototype = new BaseClass();
SubClass.prototype.constructor = SubClass;
function SubClass() {
alert( this.publicProperty ); // This works perfectly well
alert( this.privateProperty ); // This doesn't work, because the property is not inherited
}
How can I achieve a class-like simulation, like in other oop-languages (eg. C++) where I can inherit private (protected) properties?
Thank you,
David Schreiber

Using Douglas Crockfords power constructor pattern (link is to a video), you can achieve protected variables like this:
function baseclass(secret) {
secret = secret || {};
secret.privateProperty = "private";
return {
publicProperty: "public"
};
}
function subclass() {
var secret = {}, self = baseclass(secret);
alert(self.publicProperty);
alert(secret.privateProperty);
return self;
}
Note: With the power constructor pattern, you don't use new. Instead, just say var new_object = subclass();.

Mark your private variables with some kind of markup like a leading underscore _
This way you know it's a private variable (although technically it isn't)
this._privateProperty = "private";
alert( this._privateProperty )

This isn't possible. And that isn't really a private property - it's simply a regular variable that's only available in the scope in which it was defined.

That can't be done, but you could delete the property from the class prototype so that it is not inherited:
SubClass.prototype.privateProperty = undefined;
That way it won't be inherited, but you need to do that for every "private" property in your base class.

Just for reference if someone finds that today (October 2019)
We can implement private properties in javascript using WeakMap()
const _privateProperty = new WeakMap();
class BaseClass {
constructor(){
this.publicProperty = 'public';
_privateProperty.set(this, 'private');
}
}
module.exports = BaseClass;
Inherits the BaseClass
const BaseClass = require('./BaseClass')
class ChildClass extends BaseClass{
constructor(){
super()
}
}
This way your child class will inherit all the public properties from the BaseClass but the private ones.
Now, I am not sure whether one should take this approach but you can read the private properties from your parent class through your child class this way:
const _privateProperty = new WeakMap();
class BaseClass {
constructor(){
this.publicProperty = 'public';
_privateProperty.set(this, 'private');
}
//Public method
readProperties(){
const property.private = _privateProperty.get(this);
return property;
}
}
module.exports = BaseClass;
Child Class
const BaseClass = require('./BaseClass')
class ChildClass extends BaseClass{
constructor(){
super()
}
//Public Method
showProperties(){
super.readProperties().private
}
}
const properties = new ChildClass()
properties.showProperties()

Related

Accessing protected fields of base class from derived (ES2019 private class)

I'd like to access private fields of base class from derived classes without making them public (what is called 'protected' in other languages).
Consider the following class:
class Animal {
#privateProp;
constructor() {
this.#privateProp = 12;
}
}
Now the extending class:
class Cat extends Animal {
constructor() {
super();
}
doIt() {
console.log(this.#privateProp) // 1 below
console.log(super.#privateProp) // 2 below
}
}
I'd like to execute as if it was protected:
new Cat().doIt();
But gets (respectively):
Uncaught SyntaxError: Private field '#privateProp' must be declared in an enclosing class
Uncaught SyntaxError: Unexpected private field
Notice that this code would work perfectly when privateProp becomes public, But I want to achieve a protected like behavior and get access to the 'private' fields like any language that support inheritance.
Any help will be appreciated.
you can create a private property with getter and setter methods
having restricted access by checking if the constructor is not of the
parent class itself.
class Animal {
#privateProp = 12;
set Prop(val) {
if (this.constructor.name !== 'Animal')
return this.#privateProp = val;
throw new Error('Cannot Access Protected property');
}
get Prop() {
if (this.constructor.name !== 'Animal')
return this.#privateProp;
throw new Error('Cannot Access Protected property');
}
}
class Cat extends Animal {
get Prop() {
return super.Prop;
}
set Prop(val) {
super.Prop = val
}
}
let cat = new Cat();
console.log(cat.Prop)
cat.Prop = 22
console.log(cat.Prop)
console.log(new Animal().Prop);
Fields are private in a similar way to how variables are block-scoped; if a property is private to a certain class, it may only be referenced inside that class. If you extend the class, it won't be visible in the derived class.
You could make a getter/setter on the superclass, if you want to be able to do stuff with it from the subclass:
class Animal {
#privateProp = 12;
setProp(val) {
this.#privateProp = val;
}
getProp() {
return this.#privateProp;
}
}
class Cat extends Animal {
doIt() {
console.log(this.getProp());
}
}
new Cat().doIt();
Another way is to define the "private" field as a WeakMap scoped only to the class declarations instead:
const { Animal, Cat } = (() => {
const privateProps = new WeakMap();
class Animal {
constructor() {
privateProps.set(this, 12);
}
}
class Cat extends Animal {
doIt() {
console.log(privateProps.get(this));
}
}
return { Animal, Cat };
})();
new Cat().doIt();

Class Inheritance for members

I have an Octree class. A key feature of an Octree is that it can create its own children.
class Octree {
...
createChildren(){
...
/* for each of the 8 new children*/
this.children.push(new Octree(/*someargs*/))
...
}
}
Now I want to inherit off of the Octree class, however, I also want the children to become the inherited class. For example class LODWorldTree extends Octree, to additionally contain some renderer data for a game. However, if I call LODWorldTree.createChildren(), then LODWorldTree.children will be an array of Octrees instead of LODWorldTrees.
What is the best way to fix this problem? While writing this it occured to I could store Octree.myClass = /*some inherited class*/, and manually set this variable for all classes that inherit from Octree. Is there a better way to do something like this? Maybe with this.prototype?
You can utilize the fact that each object has a reference to it's own constructor via the prototype:
class A {
constructor() {
this.val = 1;
this.children = [];
this.typeName = `I'm A`;
}
addSelfChild() {
this.children.push(new this.constructor(this.val + 1));
}
}
let a = new A(1);
a.addSelfChild();
a.addSelfChild();
console.dir(a);
class B extends A {
constructor(val) {
super(val);
this.typeName = `I'm B`;
}
}
let b = new B(1);
b.addSelfChild();
b.addSelfChild();
console.dir(b);
Try to use constructor attribute:
this.children.push(new this.constructor(/*someargs*/));
this.constructor is the reference for constructor for current object, so invoking it will produce new instance of the same class

JavaScript: How to detect ES6 class has its own constructor?

How to detect whether EcmaScript class has its own constructor?
See code snippet below.
class Person {
constructor(name, age) { // <- Own constructor
this._name = name;
this._age = age;
}
}
class Manager extends Person {
// This class does not have it's own constructor
}
It seems there is no clear way to do this check.
Thank you all for time and help.
It's not bulletproof, but you could convert the constructor to a string, and see if it contains the word constructor( or something similar
function hasOwnConstructor(instance) {
var str = instance.constructor.toString();
return /class(.*?[^\{])\{([\s\n\r\t]+)?(constructor[\s]+?\()/.test(str);
}
class thing1 {
method() { return this; }
}
class thing2 {
constructor(argument) { return this; }
}
var ins1 = new thing1();
var ins2 = new thing2();
console.log( hasOwnConstructor(ins1) ); // false
console.log( hasOwnConstructor(ins2) ); // true
False positives could still be possible, but the regex makes the check quite strict, so it's not very plausable.
Inspect the constructor function.
class Example {
constructor(prop1, prop2) {
this.prop1 = prop1;
this.prop2 = prop2;
}
}
You can pass parameters to your class via the constructor function that establishes properties which can be globally referenced when creating a new instance.
This line would pass int 1 and "test" as values to prop1 and prop2:
const exampleVar = new Example(1, "test");
and might render something like:
<Example prop1=1 prop2="test" />
Hope this helps. If it has a constructor function, there is a constructor, if it does not have the constructor function, then there is no constructor.

Is there a way to discover if a javascript 6 class defines its own constructor?

Is there any way to determine if a subclass implements a constructor from within a static method (in a base class)?
I'm trying to write a static create method (that acts like the new keyword) that by default works by passing attribute values as a properties object:
class Person extends Class {
greet() { return 'hello from ' + this.name; }
}
var p = Person.create({name: 'world'}; // create a new Person object and set its `name` property to `'world'`
console.log(p.greet()); // => "hello from world"
but hands off to the class' constructor if it has one:
class Person2 extends Class {
constructor(name) {
super();
this.name = name;
}
greet() { return 'hello from ' + this.name; }
}
var p = Person2.create('world');
console.log(p.greet()); // => "hello from world"
I'm stuck at finding out if the subclass defines its own constructor..
class Class {
static create(...args) {
let has_ctor = ?? // true iff the current subclass defines a constructor..
if (has_ctor) {
// let the constructor handle everything
return new this(...args);
} else {
// assume that `args` contains exactly 1 pojo that defines instance variables to be overridden..
var instance = new this();
let props = args[0];
for (let prop in props) instance[prop] = props[prop];
return instance;
}
}
}
is this even possible?
Seems like it would be much easier to do
class Class {
static create(...args) {
// let the constructor handle everything
return new this(...args);
}
constructor(props){
Object.assign(this, props);
}
}
then if things override the constructor, then can choose to pass props to super() or to assign them manually themselves.
Just to answer your original question
Is there a way to discover if a javascript 6 class defines its own constructor?
No, there is not. Every class does have its own constructor, because a "class" basically is just the constructor function.
If a class definition does not include a constructor method, then it is automatically supplied by the language (see ยง14.5.14); either as
constructor(...args){ super (...args);}
if there is a super class or as
constructor(){ }
if there is none. The result is not distinguishable from a class where such a constructor was explicitly declared.

Get name of derived constructor in Javascript

Is it possible to get the name of the derived "class" in the following example? I'd like to somehow have the output be "ChildClass", but instead it's "ParentClass".
function ParentClass() { this.name = 'Bob' }
function ChildClass() { this.name = 'Fred' }
ChildClass.prototype = Object.create(ParentClass.prototype);
var child_instance = new ChildClass()
console.log('ChildClass type:', child_instance.constructor.name)
I realize I can do this.my_type = 'ChildClass' in the ChildClass constructor, but I have many classes that extend ParentClass and doing this everywhere would be inconvenient.
The problem in your case is that you're overwriting the prototype property of ChildClass but you're not reseting the constructor property on the new prototype. You need to add one extra line:
function ParentClass() {
this.name = "Bob";
}
function ChildClass() {
this.name = "Fred";
}
ChildClass.prototype = Object.create(ParentClass.prototype);
ChildClass.prototype.constructor = ChildClass; // add this line to your code
Now your code will work as expected. The following answer explains why your original code didn't work: https://stackoverflow.com/a/8096017/783743
Personally I don't like writing "classes" like this with the constructor and the prototype dangling separately. It's just too tedious to type, incoherent, a pain on the eyes and difficult to maintain. Hence I use the following utility function to create classes:
function defclass(base, body) {
var uber = base.prototype;
var prototype = Object.create(uber);
var constructor = (body.call(prototype, uber), prototype.constructor);
constructor.prototype = prototype;
return constructor;
}
Now you can create classes as follows:
var ParentClass = defclass(Object, function () {
this.constructor = function () {
this.name = "Bob";
};
});
var ChildClass = defclass(ParentClass, function () {
this.constructor = function () {
this.name = "Fred";
};
});
This method has several advantages:
Inheritance and class definition have been combined into one.
The constructor is just another prototype method.
Everything is nicely encapsulated within a single closure.
Calling base class prototype methods is easy.
You can create private static functions easily.
Hope that helps.

Categories