JavaScript Classes - Making variables private with WeakMap and still using "this" in other methods

504 views Asked by At

I am reading through the book "Learning JS DataStructs and Algorithms", and in the book it says that the "items" is public in the following class.

class Stack {
    constructor(){
      this.items = []
    }
 }

But, if I use a WeakMap then I can make items private again, only in the examples given they are not using the "this" like I would expect.

const items = new WeakMap();
class Stack {
    constructor(){
      items.set(this, []);
    }
}

and then it gives examples of code that does things like items.set or items.get to access things, and that seems fine, but I was wondering if I could just shorten access to the item.get(value) in the constructor on to the "this" like so:

const items = new WeakMap();
class Stack {
    constructor() {
        items.set(this, []);
        this.stack = items.get(this, []);

     push(item) {
         this.stack.push(item)
     }
}

Now, I can access the items.get() functionality with this.stack, but I am NOT sure if it makes it public again, and was wondering if anyone could help clear that up for me?

1

There are 1 answers

1
CertainPerformance On BEST ANSWER

Yes - any property of this is effectively public. So, if you have this.stack, and stack refers to an array, that array will be viewable and changeable from anything that has access to the instantiated object, which you probably don't want.

Note that even in the second code snippet, the use of the items WeakMap is not enough to make the data private - for example, anything that has access to both items and to an instantiated object can change the array for that item:

const items = new WeakMap();
class Stack {
  constructor() {
    items.set(this, []);
  }
}

const s = new Stack();
items.get(s).push('foo');
console.log(items.get(s));

To fix that, one option would be to put the whole thing inside an IIFE, with items scoped within the IIFE, and then return the class:

const Stack = (() => {
  const items = new WeakMap();
  return class Stack {
    constructor() {
      items.set(this, []);
    }
  };
})();
const s = new Stack();
// now, items can only be seen and modified through Stack's internal methods