Javascript 覆盖 parents get 方法

Javascript overriding parents get method

// 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 方法时,它似乎仍在访问 parents (数组)长度。当我调用 l.length 时,我如何做到这一点,我得到 l 的大小?

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

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

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

表示,you can't change that property

(下面的解决方案与问题有间接联系,但同时由于太长而无法在评论中发布。)

如您所见,扩展 Array 可能会出现问题。它可能是 collection 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 是否是一个数字。我认为它将更多地供内部使用,因此您会照顾好它。