0

Suppose we've the following code:

const _timeStamp = new WeakMap();
const _running = new WeakMap();

export class Stopwatch {
  constructor() {
    _timeStamp.set(this, 0);
    _running.set(this, false);
  }

  start() {
    // start stopwatch
    _running.set(this, true)
    _timeStamp.set(this, Date.now())
  }

  stop() {
    // stop stopwatch
    _running.set(this, false);
    return (Date.now() - _timeStamp.get(this))/1000
  }
}

In this example we're trying to hide some information from the end-user using weakmaps. Depending on which method is called, we change the values in both weakmaps. When we reassign variables, we change states.

let x = 0;
x = 10

EDIT:


As a best practice we shouldn't mutate objects or change states in JS

However, don't we change states when updating values in weakmaps like as we do in case of variables? What's the 'best practice' when using private props that need to be rewritable?

Any clarification is well appreciated!

PieterT2000
  • 85
  • 10
  • Isn't `x=10` a state change too? Also ignore "best practices". – Jonas Wilms Feb 21 '20 at 14:33
  • Please read my updated question. It's indeed a state change like I pointed out. – PieterT2000 Feb 21 '20 at 14:35
  • Yes. It is. So who is saying that variable assignments are a bad practice? "As a best practice we shouldn't mutate objects or change states in JS" does make zero sense without context – Jonas Wilms Feb 21 '20 at 14:37
  • @PieterT2000 Please can you provide some more context or explanation? It seems unusual to me to use a WeakMap to store variable values in this way. I would probably expect instance variables to be used. – Ben Aston Feb 21 '20 at 14:38
  • 1
    @Ben This is a very simplified code example. In the real code I am using weakmaps to store private variables, with the purpose of making them inaccessible to the end-user. (abstraction) I was just wondering if it is right to use weakmaps when you have to update their values throughout the program like in the example above. – PieterT2000 Feb 21 '20 at 14:44
  • There are also private class properties ... – Jonas Wilms Feb 21 '20 at 14:45
  • @JonasWilms Alright, so you rather would advise using those? (note that I don't want to use them in the constructor to save memory) – PieterT2000 Feb 21 '20 at 14:46
  • Take your profiler and have a look at the memory that a weakmap allocates. Also have a look at the size of a class instance with private properties. Make your judgement about "saving memory" – Jonas Wilms Feb 21 '20 at 14:48
  • As far as I know, the best privacy in JavaScript is afforded by controlling scope (ie. exposing scoped variables to the code you want using closures). If your transpiler supports it, there is a Stage 3 syntax for private variables using classes too. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Class_fields#Private_fields – Ben Aston Feb 21 '20 at 14:52
  • Is this question specifically about WeakMaps, or about a good way to implement private variables in JS? – Ben Aston Feb 21 '20 at 14:58
  • @Ben, thanks for providing the MDN resource. Actually, it's both. I am really curious what's the best way to deal with private properties in OOP JS. – PieterT2000 Feb 21 '20 at 15:00
  • There are multiple ways, depending on the precise use case and the style of code your team is following. Teams using classes will probably use the `#` private class field syntax. Team using functions will use closures. Symbols will sometimes be used, although these offer lesser privacy. – Ben Aston Feb 21 '20 at 15:03
  • @Ben, thanks! I've updated my question so you can now go ahead and submit your comment as an answer? – PieterT2000 Feb 21 '20 at 15:08

1 Answers1

1

To answer your question about WeakMaps, I think you are talking about side effects. When using a WeakMap you can imagine that there is no userland side effect to setting a value because WeakMaps invert the usual relationship between item and collection. In a WeakMap, for reasons of garbage collection, the item maintains a hidden link to the collection (rather than the collection maintaining a reference to the item), so we can pretend there is no side-effect.

But, this question is also about privacy in JavaScript.

As it happens, JavaScript has always supplied an outstanding (and impenetrable as far as I know - unlike private fields in languages like C#) mechanism for robust privacy: closures. It's just that most developers come from a class-based object-orientation background and take time to learn the "JavaScript way".

That said, syntax for marking fields on classes as private is currently at Stage 3 of the feature development process, and is supported by transpilers.

So the answer is: there are multiple ways to ensure privacy, depending on the precise use case and the style of code your team is using.

Teams using classes will probably use the # private class field syntax.

class MyClass {
   #myPrivateField = 'foo'
   bar(s) {
       return this.#myPrivateField + s
   }
}

Teams using functions will use closures.

function createObject() {
    let myPrivateVariable = 'foo'
    return {
        bar(s) {
            return myPrivateField + s
        }
    }
}

You can nit-pick this and say that the function-object for bar is created on a per-instance basis. In the vast majority of cases this won't matter.

Symbols will sometimes be used, although these offer lesser privacy because they can be viewed by reflection.

function createObject() {    
    let secretSymbol = Symbol('secret')
    return ({
        [secretSymbol]: 'foo',
        bar(s) {
            return this[secretSymbol] + s
        }
    })
}

WeakMaps and modules can also be used. For more details see the links below.

Note that you could also use a class with a closure to ensure a variable remained private.

See also, and.

Ben Aston
  • 45,997
  • 54
  • 176
  • 303