Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to achieve privacy for value saved in `this` in constructor function?

Tags:

javascript

What options do I have to achieve privacy on values I need to save in this in a constructor function? For example, a simple Stack implementation:

function Stack(){
  this._stack = {}
  this._counter = 0
}

Stack.prototype.push = function (item){
  this._stack[this._counter++] = item
  return this
}

Stack.prototype.pop = function (){
  Reflect.deleteProperty(this._stack, --this._counter);
  return this
}

Stack.prototype.peek = function (){
  return this._stack[this._counter - 1]
}

Stack.prototype.length = function (){
  return Object.values(this._stack).length
}

If these methods are not defined as prototype methods, I can easily private them like this:

function Stack(){
  let _stack = {}
  let _counter = 0

  this.push = function (item){
    _stack[_counter++] = item
    return this
  }

  this.pop = function (){
    Reflect.deleteProperty(_stack, --_counter);
    return this
  }

  this.peek = function (){
    return _stack[_counter - 1]
  }

  this.length = function (){
    return Object.values(_stack).length
  }
}

This way _stack and _counter are not exposed, but then these methods are not on prototype chain.

Is it possible to achieve privacy, while the protected values are saved in this?

like image 270
John Winston Avatar asked Mar 19 '21 02:03

John Winston


People also ask

How do you make a variable private in JavaScript?

Alternatively, we may also use the “this” keyword to make method (function) calls to stick to the main method itself which thus makes the variables private. The main idea for using the “this” keyword is just to make things directly visible that is making methods directly accessible.

How do you make a property method private in ES6?

Short answer, no, there is no native support for private properties with ES6 classes. But you could mimic that behaviour by not attaching the new properties to the object, but keeping them inside a class constructor, and use getters and setters to reach the hidden properties.

Why do we use constructors in JavaScript?

A constructor enables you to provide any custom initialization that must be done before any other methods can be called on an instantiated object. The ValidationError class doesn't need an explicit constructor, because it doesn't need to do any custom initialization.

Are JavaScript variables private?

In its current state, there is no “direct” way to create a private variable in JavaScript.


2 Answers

This answer does not create private properties. However if the intent of the question is to prevent a user from accidentally accessing "private" properties or to prevent property conflict you can use symbols.

A property conflict happens when your function expects property A, while a library (or any other code) also expects property A but for another purpose.

const Stack = (function () {
  const stack = Symbol("_stack");
  const counter = Symbol("_counter");

  function Stack() {
    this[stack] = {};
    this[counter] = 0;
  }

  Stack.prototype.push = function (item) {
    this[stack][this[counter]++] = item;
    return this;
  };

  Stack.prototype.pop = function () {
    Reflect.deleteProperty(this[stack], --this[counter]);
    return this;
  };

  Stack.prototype.peek = function () {
    return this[stack][this[counter] - 1];
  };

  Stack.prototype.length = function () {
    return Object.values(this[stack]).length;
  };
  
  return Stack;
})();

The above code does not prevent a user from accessing the properties, but makes it somewhat hard. You could still access them using the following code:

const stack = new Stack();
const [_stack, _counter] = Object.getOwnPropertySymbols(stack);
stack[_stack]   // gives access to the stack
stack[_counter] // gives access to the counter

Symbol properties are excluded from a lot of common functions like Object.keys(), Object.values(), Object.entries(), and also from for...in loops.

like image 97
3limin4t0r Avatar answered Oct 31 '22 14:10

3limin4t0r


Here is an example of using private fields. You can make them static with the static keyword, but that is not necessary in this example.

class test {
    #lol = 29;
    #mas = 15;
    constructor() {
        this.#lol++;
        this.#mas--;
        return {
            value: this.#lol - this.#mas
        };
    }
};
console.log(new test().value); // --> 16
like image 35
quicVO Avatar answered Oct 31 '22 15:10

quicVO