How to get private properties names of a class in javascript?

1.3k Views Asked by At

Introduction

In order to get the properties of a class instance we can just use the Object.getOwnPropertyNames() method like in the following example

class People {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }    
  getProperties() {
    return Object.getOwnPropertyNames(this);
  }
}
console.log(new People("John", 20).getProperties())

This does work because the properties of the object are public. But in case the properties of the object are private this method doesn't work.

Problem

Imagine that you don't want user to modify the name and age properties directly outside a class method, so you make them private. However, you also want to have a method that makes a copy of an instance in another instance. Since the Object.getOwnPropertyNames() does not work for private properties, you cannot access to the keys in oder to make the clone():

class People {
  #name; #age;
  constructor(name, age) {
    this.#name = name;
    this.#age = age;
  }
  clone(o) {
    Object.getOwnPropertyNames(this).forEach(key => this[key] = o[key]);
  }
  getName() { return this.#name }
}

p1 = new People("John", 20);
p2 = new People("", 0);

p2.clone(p1);   // Now p2 should have the same properties of p1

console.log(p2.getName());      // Prints "" and should print "John"

Question

Is there a way to access private properties names of a class from inside a class method?

2

There are 2 best solutions below

8
On

Yes. You can use something called WeakMaps. You would do something like this:

const _name = new WeakMap();
const _age = new WeakMap();

class Person {
    constructor(name, age) {
        _name.set(this, name);
        _age.set(this, age);
    }
}

As you can see, we use the set method to set the value of a weakMap for a specific class.

Now, to access this value in another method, you use the get method:

const _name = new WeakMap();
const _age = new WeakMap();

class Person {
    constructor(name, age) {
        _name.set(this, name);
        _age.set(this, age);
    }

    getName() {
        return _name.get(this);
    }
}

const bob = new Person('Bob', 35); // You will not be able to access the name property by typing "bob.name".
console.log(bob.getName());

The get method will allow you to access the value of that weakMap for the class mentioned.

For more information about WeakMaps click here

1
On

Just implement the method returning needed parameters:

getParameters(){
    return { name: this.#name, age: this.#age };
}    

and use it in the clone() method as follows:

clone(o) {
   const { name, age } = o.getParameters();
   this.name = name;
   this.age = age;
}

So you only access object's private parameters by it's methods. If you want a more generic approach, without listing all the parameters, you can use Object.entries() method in getParameters() method.