在JavaScript中通过递归继承构造序列/链表

Constructing a sequence/linked list through inheritance recursively in JavaScript

本文关键字:链表 继承 JavaScript 递归      更新时间:2023-09-26

背景:我正在阅读在线书籍Eloquent JavaScript,第6章中的一个练习提到"Sequence"的行为类似于链表。这里是练习的链接,我已经复制了一些相关的文本:

另一个解决方案是避免改变对象的状态。您可以公开一种方法来获取当前元素(不推进任何计数器),另一种方法用于获取一个新序列,该序列表示当前元素之后的剩余元素(或者如果达到序列的末尾,则提供一个特殊值)。

我试图通过在接口类中递归地调用实现类的(ArraySeq)构造函数来构建序列。然而,当在节点上运行测试时,我得到TypeError: Cannot read property '0' of undefined at Sequence.ArraySeq

我已经复制并粘贴了我的(不完整的)实现:

/**
 * Sequence interface
 */
function Sequence(current, rest) {
  this.current = current;
  this.rest = rest;
}
Object.defineProperty(Sequence.prototype, "end", {
  get: function() {
    return this.rest === undefined;
  }
});
Sequence.prototype.next = function() {
  return this.rest;
};
/**
 * Array implementation of sequence
 */
function ArraySeq(array) {
  if (array === []) {
    Sequence.call(undefined, undefined);
  } else {
    Sequence.call(array[0], new ArraySeq(array.slice(1)));
  }
}
ArraySeq.prototype = Object.create(Sequence.prototype);
/**
 * Logs all elements in a Sequence
 */
function logSequence(sequence) {
  while (sequence.rest !== undefined) {
    console.log(sequence.current);
    sequence = sequence.rest;
  }
}
logSequence(new ArraySeq([1, 2]));

感谢你读到这里,任何帮助或指导是非常感激的!

正如我在注释中所指出的:

  • array.splice[1]将给您未定义。您需要array.slice(1) -不包含第一个元素的整个数组:slice,而不是splicearray.splice(1)将从数组中删除第二个元素并返回该元素——这不是您想要的。

  • 你写Sequence作为一个构造函数,但你没有调用它作为一个构造函数。用new Sequence代替Sequence.call

  • 相反,您调用new ArraySeq,但ArraySeq看起来不像构造函数。只使用ArraySeq,并使它返回的东西(return new Sequence...)

  • 使用if (!array.length)测试数组是否为非空。array === [],甚至array == [],永远不能返回true,因为对象(因此数组)是基于对象标识进行比较的,而不是相等的,并且您刚刚创建了一个新的对象(因此它不可能与已经存在的对象相同)。

  • 当然,ArraySequence没有定义;应该是ArraySeq,对吧?

有了这些修改,你的代码就可以工作了。编辑:然而,练习希望ArraySeq是一个对象,所以还有一点工作…首先,"接口"不是一个对象。它只是一个对象应该如何表现。我的练习是:

function ArraySeq(array) {
  this.array = array;
  this.index = 0;
}
Object.defineProperty(ArraySeq.prototype, "end", {
  get: function() {
    return this.index >= this.array.length;
  }
});
Object.defineProperty(ArraySeq.prototype, "next", {
  get: function() {
    return this.array[this.index++];
  }
});

/**
 * Logs all elements in a Sequence
 */
function logSequence(sequence) {
  while (!sequence.end) {
    console.log(sequence.next);
  }
}
logSequence(new ArraySeq([1, 2]));

这里的"接口"是.end.next。如果你想按照你的报价,那就稍微改变一下。这里的接口是.end, .rest.value:

function ArraySeq(array) {
  this.array = array;
}
Object.defineProperty(ArraySeq.prototype, "end", {
  get: function() {
    return this.array.length == 0;
  }
});
Object.defineProperty(ArraySeq.prototype, "rest", {
  get: function() {
    return new ArraySeq(this.array.slice(1));
  }
});
Object.defineProperty(ArraySeq.prototype, "value", {
  get: function() {
    return this.array[0];
  }
});

/**
 * Logs all elements in a Sequence
 */
function logSequence(sequence) {
  while (!sequence.end) {
    console.log(sequence.value);
    sequence = sequence.rest;
  }
}
logSequence(new ArraySeq([1, 2]));

首先,splice是方法。

array.splice(1)代替array.splice[1]

和使用数组。Length == 0 in array === [].

如果两个对象是不同的对象,则===运算符被视为假,即使所有元素都相同。