Private class field in JavaScript

2.3k views Asked by At
class A {
  #a = 1;
  static #a = 2;
}

Results in

  • Uncaught SyntaxError: redeclaration of private name #a in Firefox
  • Uncaught SyntaxError: Identifier '#a' has already been declared in Chrome

While

class A {
  a = 1;
  static a = 2;
}

is valid in both Firefox and Chrome

AFAIK instance fields will be installed on the class instance while static fields will be installed on the class object itself. They are not conflicted. Why the former code is invalid?

3

There are 3 answers

6
Bergi On BEST ANSWER

Instance fields will be installed on the class instance while static fields will be installed on the class object itself. They are not conflicted.

They are, because in the expression x.#a the engine doesn't know whether x is a class object or a class instance. The meaning of the #a token should be static and not depend on the object, it needs to refer to the one or to the other but not to both.

Unlike normal string-keyed properties that are identified by the string value of the identifier (.a is the same as .a regardless of context), private fields have an identity (not unlike symbols) that is created with their declaration. Only one #a can exist per class definition, and in a different class the same #a syntax will refer to a different field.

0
Peter Pointer On

Use different variable names like a and b instead of a both times.

The variable cannot strictly be static and non-static at the same time I am guessing.

FYI - support for private class fields is here: https://caniuse.com/mdn-javascript_classes_private_class_fields

1
Vikram Kumar On

Any property declared in a class with # prefix is treated as private property. But there is no private properties concept in Javascript by design. However, we can mimic private properties by defining them outside the function and then using them inside the function. This way those properties are not accessible outside the module unless we export. So, the transpiled version for the above code will be like this.

var _a = /*#__PURE__*/new WeakMap();
var A = function A() {
   _classCallCheck(this, A);
  _a.set(this, {
    writable: true,
    value: 1
  });
};

As you can see the #a variable is transformed as _a and declared outside the function as WeakMap and being used inside the function.

So if you have another static property with the same name #a it tries to create another variable outside the function with the same name _a. Since it is private static property it will not be attached to the function. So the transpiled code will look like this.

var _a = /*#__PURE__*/new WeakMap();
var A = function A() {
   _classCallCheck(this, A);
  _a.set(this, {
    writable: true,
    value: 1
  });
};

var _a = {
  writable: true,
  value: 2
};

So as you can see it tries to create another variable with the same name and throws the error. This is the limitation of the javascript and can be easily avoided by giving a different name obviously.

The later case is valid because they are not private properties.