Javascript覆盖父母get方法


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

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

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

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

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

意味着,您无法更改该属性。

(下面的解决方案与问题间接相关,但同时它太长而无法在评论中发布。

正如您所经历的,扩展阵列可能会出现问题。这可能是 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是否是一个数字。我认为它将用于更多的内部使用,因此您会照顾它。

最新更新