JavaScript 中的私有类字段

问题描述

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

结果

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

虽然

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

在 Firefox 和 Chrome 中都有效

AFAIK 实例字段将安装在类实例上,而静态字段将安装在类对象本身上。它们并不冲突。为什么以前的代码无效?

解决方法

实例字段将安装在类实例上,而静态字段将安装在类对象本身上。它们并不冲突。

它们是,因为在表达式 x.#a 中,引擎不知道 x 是类对象还是类实例。 #a 标记的含义应该是静态的,不依赖于对象,它需要引用一个或另一个而不是两个。

与由标识符的字符串值标识的普通字符串键属性不同(.a.a 相同,无论上下文如何),私有字段具有一个标识(与符号不同)是用他们的声明创建的。每个 #a 定义只能存在一个 class,并且在不同的类中,相同的 #a 语法将引用不同的字段。

,

在带有 # 前缀的类中声明的任何属性都被视为私有属性。但是在 Javascript 中设计上没有私有属性的概念。但是,我们可以通过在函数外部定义私有属性然后在函数内部使用它们来模拟私有属性。这样,除非我们导出,否则无法在模块外部访问这些属性。因此,上述代码的转译版本将是这样的。

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

如您所见,#a 变量被转换为 _a 并在函数外部声明为 WeakMap 并在函数内部使用。

因此,如果您有另一个同名的静态属性 #a,它会尝试在函数外部创建另一个同名 _a 的变量。由于它是私有静态属性,因此不会附加到函数。所以转译后的代码看起来像这样。

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

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

如您所见,它尝试创建另一个具有相同名称的变量并引发错误。这是 javascript 的限制,可以很容易地通过给一个不同的名称来避免。

后一种情况是有效的,因为它们不是私有财产。

,

两次使用不同的变量名称,例如 ab 而不是 a

我猜这个变量不能同时是静态和非静态的。

仅供参考 - 对私有类字段的支持在这里:https://caniuse.com/mdn-javascript_classes_private_class_fields

,

我认为我们可以定义同名的公共属性和公共静态属性,这是一个尚未修复的错误。我们需要记住最近在 JS 中实现了私有字段,所以在实现过程中作者写得更好。