【问题标题】:Javascript overriding parents get methodJavascript覆盖父母的get方法
【发布时间】:2019-07-16 18:45:33
【问题描述】:
// Garbage collection friendly list.
class GCFList extends Array {
  size;

  constructor(initSize = 0) {
    super(initSize);
    this.size = initSize;
  }
  push(content){
    this[this.size] = content;
    this.size++;
  }
  pop(){
    this.size--;
    let returnContent = this[this.size];
    this[this.size] = null;
    return returnContent;
  }
  get length(){
    return this.size;
  }
  set length(newLength){

  }
}

var l = new GCFList();
l.push(2);
l.pop();
console.log(l.length);
console.log("Expecting 0, but getting 1");

我正在制作一个垃圾回收友好的数组列表。我想将它用作普通数组。当我尝试覆盖长度 getter 方法时,它似乎仍在访问父级(数组)长度。当我调用 l.length 时,我该如何做到这一点,我得到 l 的大小?

【问题讨论】:

  • 内置数组已经非常适合 GC。是什么让您认为您可以改进这一点?
  • length of arrays 是“特殊的”(就像许多 JS 的东西一样......)你想在这里完成什么?与标准阵列相比,这有什么优势?我还没有看到任何有价值的东西。
  • 你在哪里运行你的代码?铬合金?火狐?转译 JS?
  • @TheWitness 为什么重要? AFAIK 他们将以几乎相同的方式实现Array
  • @Bergi 我正在用 Javascript 制作游戏。数组的大小发生了根本性的变化。如果我首先将数组的大小增加到一个巨大的大小,然后再增加到 0,我担心列表会首先保留大量堆内存,然后它会释放。当垃圾收集器进行收集时,释放的堆内存将累积并导致峰值延迟。在我的方法中,列表只会增加保留内存而不会减少,导致堆内存保留和释放仅在程序开始时发生。

标签: javascript arrays inheritance overriding


【解决方案1】:

您不能覆盖数组的.length 行为。它不是一个 getter/setter(即使它的行为像一个),也不是从 Array.prototype 继承的。每个数组实例都有自己的 .length 数据属性,它会影响 GCFList.prototype 上的 getter/setter。

【讨论】:

    【解决方案2】:

    除了你不能真正比 JS Array 更高效(它们是稀疏等)的问题之外,你正在扩展 Array,并且数组的 length 属性不可配置:

    Object.getOwnPropertyDescriptor(l, 'length')
    // {value: 1, writable: true, enumerable: false, configurable: false}
    

    意思是you can't change that property

    【讨论】:

      【解决方案3】:

      (下面的解决方案与问题间接相关,但同时太长无法发表评论。)

      如您所见,扩展 Array 可能会出现问题。它可能是 JavaScript 必须提供的最好的集合,但它是独立的。我想建议如下:

      (是的,我相信您在问题中寻找的结构是堆栈。)

      class Stack {
          constructor(size) {
              this.size = size;
              this.head = -1;
              this.stack = Array.from({ length: size }, () => undefined);
          }
      
          push(item) {
              if (this.head + 1 == this.size) {
                  // if you prefer, this might silently fail but I chose to be explicit
                  throw new Error('Stack full!'); 
              }
      
              this.head += 1;
              this.stack[this.head] = value;
      
              return this; // so it can be chained and `this.push(1).push(2)` will be possible
          }
      
          pop() {
              if (this.head == -1) {
                  // if you prefer, this might silently fail but I chose to be explicit
                  throw new Error('Stack empty!'); 
              }
      
      
              const popped = this.stack[this.head];
              // this is theoretically optional but in case of objects we’ll get rid of reference, 
              // hence allowing for garbage collection
              this.stack[this.head] = undefined; 
              this.head -= 1;
              return popped;
          }
      
          get length() {
              // I put this here as it was in your example 
              // but either having `lenght` property or reading from `string` is actually enough
              return this.size;
          }
      
          set length(size) {
              if (size > this.size) {
                  for (let i = this.size; i < size; i++) {
                      this.stack.push(undefined);
                  }
              } else if (size < this.size) {
                  if (this.head > size) {
                      this.head = size - 1; // set it at the end of shorter stack if head would be oustide
                  }
                  for (let i = this.size; i > size; i--) {
                      this.stack.pop();
                  }
              }
          }
      }
      

      这为您提供了一个固定长度的“数组”,如果您尝试扩展它,它将失败。我在某处读到,为了游戏的目的,不改变长度的数组效果更好。无论如何,您已经进行了分析。另外,因此我不建议使用不可变结构,因为这会占用内存。

      您可能需要的可能方法是peek,它允许查看当前值而不弹出它。

      这是我刚刚编写的概念证明,因此如果您决定使用它,可能需要进行一些调整,但这是我的想法。

      因为这意味着要快,所以我放弃了一些过于防御性的措施,比如检查发送给构造函数的size 是否是一个数字。我认为它将用于更多内部使用,因此您会照顾好它。

      【讨论】:

      • 谢谢。我想我会使用这种方法。如果我想使用 peek() 或 pop() 访问不在末尾的元素,我还可以创建一个 get 函数 get(index){return this.stack[i];} 用作“myList.get( 2)" 以获取索引 2 处的元素。我认为无法使用 "myList[2]" 访问它。
      猜你喜欢
      • 1970-01-01
      • 2011-04-17
      • 2011-10-16
      • 1970-01-01
      • 2021-12-25
      • 1970-01-01
      • 2021-07-09
      • 2013-09-15
      相关资源
      最近更新 更多