在 weakmaps 中设置新值时我们会改变状态吗?

Do we change states when setting new values in weakmaps?

假设我们有以下代码:

const _timeStamp = new WeakMap();
const _running = new WeakMap();

export class Stopwatch {
  constructor() {
    _timeStamp.set(this, 0);
    _running.set(this, false);
  }

  start() {
    // start stopwatch
    _running.set(this, true)
    _timeStamp.set(this, Date.now())
  }

  stop() {
    // stop stopwatch
    _running.set(this, false);
    return (Date.now() - _timeStamp.get(this))/1000
  }
}

在这个例子中,我们试图使用 weakmaps 向最终用户隐藏一些信息。 根据调用的方法,我们更改两个 weakmaps 中的值。 当我们重新分配变量时,我们改变了状态。

let x = 0;
x = 10

编辑:


作为最佳实践,我们不应该在 JS 中改变对象或改变状态

但是,我们在更新 weakmaps 中的值时不会像在变量的情况下那样改变状态吗? 'best practice' 使用需要可重写的私有 props 是什么?

非常感谢任何澄清!

为了回答您关于 WeakMaps 的问题,我认为您是在谈论副作用。使用 Wea​​kMap 时,您可以想象设置值不会对用户空间产生副作用,因为 WeakMap 颠倒了项目和集合之间的通常关系。在 WeakMap 中,出于垃圾回收的原因,项目维护一个隐藏的 link 到集合(而不是集合维护对项目的引用),所以我们可以假装没有副作用。

但是,这个问题也与 JavaScript 中的隐私有关。

碰巧,JavaScript 一直提供一种出色的(据我所知是难以理解的——与 C# 等语言中的私有字段不同)强大的隐私机制:闭包。只是大多数开发人员来自基于 class 的面向对象背景,并花时间学习 "JavaScript way".

也就是说,用于将 classes 上的字段标记为私有的语法目前处于功能开发过程的 Stage 3 中,并且受转译器支持。

所以答案是:有多种方法可以确保隐私,具体取决于具体的用例和您的团队使用的代码风格。

使用 classes 的团队可能会使用 # private class field syntax

class MyClass {
   #myPrivateField = 'foo'
   bar(s) {
       return this.#myPrivateField + s
   }
}

使用函数的团队将使用 closures

function createObject() {
    let myPrivateVariable = 'foo'
    return {
        bar(s) {
            return myPrivateField + s
        }
    }
}

你可以吹毛求疵地说 bar 的函数对象是在每个实例的基础上创建的。在绝大多数情况下,这无关紧要。

Symbols 有时会被使用,尽管这些提供较少的隐私,因为它们可以通过反射查看。

function createObject() {    
    let secretSymbol = Symbol('secret')
    return ({
        [secretSymbol]: 'foo',
        bar(s) {
            return this[secretSymbol] + s
        }
    })
}

WeakMaps和模块也可以使用。有关详细信息,请参阅下面的 link。

请注意,您还可以使用带闭包的 class 来确保变量保持私有。

参见 also,