从每个实例都有一个私有闭包的模块导出一个 class,但它的原型链仍然可以扩展?

Export a class from a module where each instance has a private closure, but it's prototype chain can still be extended?

f.e。假设我有

function foo() {
  var privateVariable = "foo"
  return class Foo {
    constructor() {
      // do something with privateVariable
    }
  }
}
export default foo

所以我将导出 returns 和 class 的函数,然后 class 的每个实例都会有一个闭包,从函数被调用以获取 class.然后我可以做

import foo from "Foo"
var instance = new (foo())()

每个实例都由返回的 class 构成,因此每个实例的原型都有一个私有闭包(是的,这不是最有效的,因为每次都会返回一个新的 class 定义)。问题是扩展 class 意味着从 Foo 扩展的每个实例将共享一个闭包,f.e.

var Foo = foo() // get a new class definition
class Bar extends Foo {
  // ...
}

现在每次我创建 new Bar() 时它的原型都是 Foo,但是每个 class 扩展 Foo 原型将共享相同的私有闭包(基本上私有变量现在是 static) 因为不是每次都获取新的 Foo 定义。

我如何使 Foo 可扩展以便每个 new Bar() 的 Foo 原型都有一个私有闭包?

编辑 2015 年 2 月 7 日 12:53am: 有趣的是,我想出了自己的解决方案,这恰好类似于使用 Wea​​kMap 的公认答案,除了这只是一张地图,并不弱:

//
// --- PrivateManager.js
//
function PrivateManager() { // singleton
    this.instances = []
    this.instanceData = {}
    this.currentId = 0
}
PrivateManager.prototype.__register = function(instance, instanceDatum) {
    if (this.instances.indexOf(instance) === -1) {
        this.instances[this.currentId] = instance
        this.instanceData[this.currentId] = instanceDatum
        this.currentId++
    }
}
PrivateManager.prototype.__getMethod = function(desiredMethod) {
    return this[desiredMethod]
}

//
// --- Person.js
//
function PersonPrivateManager() {
    var mngr = this
    this.getName = function() {
        return mngr.instanceData[mngr.instances.indexOf(this)].name
    }
}
PersonPrivateManager.prototype = new PrivateManager()

var privateMngr = new PersonPrivateManager()
function Person(name) {
    privateMngr.__register(this, {
        name: name
    })
}
Person.prototype.getName = privateMngr.__getMethod("getName")

//
// --- app.js
//
var person1 = new Person('Bentra')
console.log(person1.getName()) // Bentra
console.log(person1.name) // undefined

var person2 = new Person('Amadar')
console.log(person2.getName()) // Amadar
console.log(person2.name) // undefined

console.log(person1.getName === person2.getName) // true, references to the same function, no memory waste as far as duplicate functions go.

缺点是它不会像 WeakMap 那样自动进行垃圾回收。这是一个冲动的解决方案。它可以被修改以模仿 WeakMap 的清洁器 API,减去垃圾收集。

WeakMap 放入 Foo 的模块顶级范围,并将私有变量分配给以实例为键的弱映射。 这样只有在该模块中定义的函数才能访问它,使其有效地私有化。

为您的 Bar 类 做同样奇怪的事情:

import foo from "Foo"
function bar() {
  var Foo = foo();
  return class Bar extends Foo {
    constructor() {
    }
  }
}
export default bar