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}
(下面的解决方案与问题有间接联系,但同时由于太长而无法在评论中发布。)
如您所见,扩展 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
是否是一个数字。我认为它将更多地供内部使用,因此您会照顾好它。
// 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}
(下面的解决方案与问题有间接联系,但同时由于太长而无法在评论中发布。)
如您所见,扩展 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
是否是一个数字。我认为它将更多地供内部使用,因此您会照顾好它。