12

nodejs的当前版本中, 12.x.x,我们可以通过符号声明private类字段。#some_varible#符号将使该特定类的变量私有字段。

class Foo {
  #some_varible = 10;
}

我有以下问题:

  • 如何使用这个变量?
  • 在生产应用程序中使用此类符号来声明私有类字段是否安全?
  • 当某些类字段被声明为私有时,它如何在后台(在 nodejs 中)工作?
4

1 回答 1

10

如何使用这个变量?

您可以将其用作访问器属性的支持字段:

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);

或者您可以像普通属性一样使用它,主要区别在于它只能从范围内访问class { ... },因为它是私有的,并且该属性以 . 为前缀#

另请注意,this.#some_variable一样this['#some_variable'],后者指的是字符串属性,而不是私有字段。

在生产应用程序中使用此类符号来声明私有类字段是否安全?

答案是视情况而定

使用客户端 JavaScript,您无法控制执行环境,但您可以使用Babel 插件将新语言功能(例如私有类字段)转换为仅依赖于旧语言规范中的语法的功能等效项。

在 Node.js 中,您确实可以控制执行环境,因此要使用新的语言功能,只需确保您使用的是支持语法的版本

当某些类字段被声明为私有时,它如何在后台(在 nodejs 中)工作?

V8 实现

私有字段使用从反射方法中列入黑名单的块范围符号Object.getOwnPropertySymbols()

本机实现

下面是模拟此实现的转换类可能的样子:

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);

这会产生与本机实现非常相似的输出:

polyfill 实现


通天塔实现

@babel/plugin-proposal-class-properties

私有字段存储为WeakMap其中每个条目是类实例键及其各自的私有字段属性描述符值。

以下是 Babel 如何转换我们一直使用的类作为示例:

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

var _some_variable = new WeakMap();

请注意,虽然_some_variable这里不是块作用域,但 Babel 将确保转换后的输出中的名称不会与该作用域中的任何可见名称冲突,因此无法从预编译源中访问弱映射。

于 2019-09-18T16:57:00.610 回答