Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use private class fields in nodejs 12?

In the current release of nodejs i.e. 12.x.x, we can declare private class fields by the #some_varible notation. The # notation would make the variable private field for that particular class.

class Foo {
  #some_varible = 10;
}

I have the following Questions:

  • How to use this variable?
  • Is it safe to use such notations in a production app for declaring private class fields?
  • How does it work in background (in nodejs), when some class field is declared private?
like image 525
Rajan Sharma Avatar asked Aug 29 '19 10:08

Rajan Sharma


People also ask

Can I use private class fields?

Private fields are currently supported in Node. js 12, Chrome 74, and Babel. A quick recap of ES6 classes is useful before we look at how class fields are implemented. This article was updated in 2020.

How do I declare a private variable in node JS?

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.

What is the purpose of having fields in a class private?

Private instance fields The # is a part of the name itself. Private fields are accessible on the class constructor from inside the class declaration itself. They are used for declaration of field names as well as for accessing a field's value. It is a syntax error to refer to # names from out of scope.

Can we access private method from outside class JavaScript?

The private method of a class can only be accessible inside the class. The private methods cannot be called using the object outside of the class. If we try to access the private method outside the class, we'll get SyntaxError . Our private method can be declared by adding the # before the method name.


1 Answers

How to use this variable?

You can use it as a backing field for an accessor property:

class Foo {
  #some_variable = 10;
  
  get some_variable () {
    console.log('getting some_variable');
    return this.#some_variable;
  }
  
  set some_variable (value) {
    console.log('setting some_variable');
    this.#some_variable = value;
  }
}

let bar = new Foo();

console.log(bar.some_variable);
console.log(bar.some_variable = 42);

Or you can use it like a normal property, the main difference being that it can only be accessed from within the class { ... } scope, since it is private, and that the property is prefixed with a #.

Also note that this.#some_variable is not the same as this['#some_variable'], the latter of which refers to the string property, not the private field.

Is it safe to use such notations in a production app for declaring private class fields?

The answer is it depends.

With client-side JavaScript, you have no control over the executing environment, but you can transform new language features such as private class fields into functional equivalents relying only on syntax from older language specifications using Babel plugins.

In Node.js, you do have control over the executing environment, so to use new language features, just ensure you're using a version that supports the syntax.

How does it work in background (in nodejs), when some class field is declared private?

V8 implementation

Private fields use block-scoped symbols which are blacklisted from the reflection method Object.getOwnPropertySymbols().

native implementation

Here's what a transformed class emulating this implementation might look like:

let Foo;

{
  const some_variable = Symbol('#some_variable');

  {
    const getOwnPropertySymbolsImpl = Object.getOwnPropertySymbols;
    Object.getOwnPropertySymbols = function getOwnPropertySymbols () {
      return getOwnPropertySymbolsImpl.apply(this, arguments)
        .filter(symbol => symbol !== some_variable);
    };
  }

  Foo = class Foo {
    [some_variable] = 10;
  };
}

let bar = new Foo();
console.log(bar);

This produces a very similar-looking output to the native implementation:

polyfill implementation


Babel implementation

@babel/plugin-proposal-class-properties

Private fields are stored as a WeakMap where each entry is a class instance key and its respective private field property descriptor value.

Here's how Babel transforms the class we've been using as an example:

class Foo {
  constructor() {
    _some_variable.set(this, {
      writable: true,
      value: 10
    });
  }
}

var _some_variable = new WeakMap();

Note that while _some_variable is not block-scoped here, Babel will ensure that the name in the transformed output does not collide with any visible names in that scope, so the weak map is inaccessible from within the pre-compiled source.

like image 156
Patrick Roberts Avatar answered Oct 19 '22 01:10

Patrick Roberts