雄辩的JavaScript,序列接口
我正在努力学习有说服力的JavaScript,我对problem#6.3(第二版)有疑问 问题是: 设计一个接口,在一组 价值观提供此接口的对象表示一个序列, 接口必须以某种方式使使用 这样一个对象可以遍历序列,查看元素 它是由价值观组成的,并且有一些方法来确定何时结束 达到序列的最大值 指定接口后,尝试编写函数 获取序列对象并在其上调用console.log的logFive 前五个元素或更少,如果序列少于五个 元素 然后实现一个对象类型ArraySeq,它包装一个数组并允许 使用您设计的界面在阵列上进行迭代。实施 另一个对象类型RangeSeq,在一系列整数上迭代 (取而代之的是它的构造函数的from和to参数) 我写了这个解决方案:雄辩的JavaScript,序列接口,javascript,Javascript,我正在努力学习有说服力的JavaScript,我对problem#6.3(第二版)有疑问 问题是: 设计一个接口,在一组 价值观提供此接口的对象表示一个序列, 接口必须以某种方式使使用 这样一个对象可以遍历序列,查看元素 它是由价值观组成的,并且有一些方法来确定何时结束 达到序列的最大值 指定接口后,尝试编写函数 获取序列对象并在其上调用console.log的logFive 前五个元素或更少,如果序列少于五个 元素 然后实现一个对象类型ArraySeq,它包装一个数组并允许 使用您设计的界面在
function ArraySeq(collection) {
this.values = collection;
}
ArraySeq.prototype.iterate = function(start, end, action) {
var n = Math.min(this.values.length, end);
for (var i = start; i < n; i++) {
action(this.values[i]);
}
};
function RangeSeq(from, to) {
var array = [];
for (var i = from; i <= to; i++)
array.push(i);
ArraySeq.call(this, array);
}
RangeSeq.prototype = Object.create(ArraySeq.prototype);
function logFive(sequenceObject) {
sequenceObject.iterate(0, 5, console.log);
}
//This code to test how the solution works was provided by the author
logFive(new ArraySeq([1, 2]));
// → 1
// → 2
logFive(new RangeSeq(100, 1000));
// → 100
// → 101
// → 102
// → 103
// → 104
函数ArraySeq(集合){
这个值=集合;
}
ArraySeq.prototype.iterate=函数(开始、结束、操作){
var n=Math.min(this.values.length,end);
对于(变量i=开始;i=this.to)
返回false;
这个.pos++;
返回true;
};
RangeSeq.prototype.current=函数(){
返回此.pos;
};
logFive(新的ArraySeq([1,2]);
// → 1.
// → 2.
logFive(新范围seq(1001000));
// → 100
// → 101
// → 102
// → 103
// → 104
//此替代方法将空序列表示为null,
//并给出了非空序列的两种方法:
//
//*head()返回序列开头的元素。
//
//*rest()返回序列的其余部分,如果没有,则返回null
//元素离开了。
//
//因为JavaScript构造函数不能返回null,所以我们添加了make
//函数调用此类型序列的构造函数,其中
//一个序列,如果结果序列是
//空的。
功能日志Five2(顺序){
对于(变量i=0;i<5&&sequence!=null;i++){
console.log(sequence.head());
sequence=sequence.rest();
}
}
函数ArraySeq2(数组,偏移){
this.array=数组;
这个偏移量=偏移量;
}
ArraySeq2.prototype.rest=函数(){
返回ArraySeq2.make(this.array,this.offset+1);
};
ArraySeq2.prototype.head=函数(){
返回此.array[this.offset];
};
ArraySeq2.make=函数(数组,偏移){
如果(offset==null)offset=0;
if(偏移量>=array.length)
返回null;
其他的
返回新的ArraySeq2(数组,偏移);
};
功能范围Seq2(从,到){
this.from=from;
这个;
}
RangeSeq2.prototype.rest=函数(){
返回范围seq2.make(this.from+1,this.to);
};
RangeSeq2.prototype.head=函数(){
把这个还给我;
};
RangeSeq2.make=函数(从,到){
如果(从>到)
返回null;
其他的
返回新的RangeSeq2(从,到);
};
logFive2(ArraySeq2.make([1,2]);
// → 1.
// → 2.
logFive2(范围seq2.make(1001000));
// → 100
// → 101
// → 102
// → 103
// → 104
我的问题是:
谢谢大家! 您的解决方案是不正确的,因为迭代器协议的全部要点是惰性地迭代,因此
RangeSeq(1100000)
不会用所有元素填满内存,如果我们只需要五个元素
作者的代码还可以,但不必要的冗长。迭代器协议通常是这样实现的:
- Iterable是具有
方法的对象迭代器()
返回迭代器对象Iterable.iterator()
- 迭代器提供方法
,该方法返回一对.next
。或者,(完成,值)
可以在对耗尽的迭代器调用时引发异常.next
函数范围seq(从,到){
this.iterator=函数(){
var i=来自;
返回{
下一步:函数(){return[i>=to,i++]}
}
}
}
函数ArraySeq(ary){
this.iterator=函数(){
var i=0;
返回{
下一步:函数(){return[i>=ari.length,ari[i++]}
}
}
}
功能日志(序号,n){
var it=seq.iterator();
而(n--){
让[done,value]=it.next();
如果(完成)中断;
console.log(值)
}
}
logN(新范围seq(100100000000),5);
console.log('------------');
logN(新ArraySeq([11,22,33,44,55,66,77,88,99]),5)代码>模式“return{next:function(){…}}”对我来说是新的。书中有一些类似的东西,比如“get:function(){…}”和“set:function(){…}”,但有点简单。这可能就是为什么他的解决方案冗长的原因——他只能依赖于他介绍的东西
// I am going to use a system where a sequence object has two methods:
//
// * next(), which returns a boolean indicating whether there are more
// elements in the sequence, and moves it forward to the next
// element when there are.
//
// * current(), which returns the current element, and should only be
// called after next() has returned true at least once.
function logFive(sequence) {
for (var i = 0; i < 5; i++) {
if (!sequence.next())
break;
console.log(sequence.current());
}
}
function ArraySeq(array) {
this.pos = -1;
this.array = array;
}
ArraySeq.prototype.next = function() {
if (this.pos >= this.array.length-1)
return false;
this.pos++;
return true;
};
ArraySeq.prototype.current = function() {
return this.array[this.pos];
};
function RangeSeq(from, to) {
this.pos = from - 1;
this.to = to;
}
RangeSeq.prototype.next = function() {
if (this.pos >= this.to)
return false;
this.pos++;
return true;
};
RangeSeq.prototype.current = function() {
return this.pos;
};
logFive(new ArraySeq([1, 2]));
// → 1
// → 2
logFive(new RangeSeq(100, 1000));
// → 100
// → 101
// → 102
// → 103
// → 104
// This alternative approach represents the empty sequence as null,
// and gives non-empty sequences two methods:
//
// * head() returns the element at the start of the sequence.
//
// * rest() returns the rest of the sequence, or null if there are no
// elemements left.
//
// Because a JavaScript constructor can not return null, we add a make
// function to constructors of this type of sequence, which constructs
// a sequence, or returns null if the resulting sequence would be
// empty.
function logFive2(sequence) {
for (var i = 0; i < 5 && sequence != null; i++) {
console.log(sequence.head());
sequence = sequence.rest();
}
}
function ArraySeq2(array, offset) {
this.array = array;
this.offset = offset;
}
ArraySeq2.prototype.rest = function() {
return ArraySeq2.make(this.array, this.offset + 1);
};
ArraySeq2.prototype.head = function() {
return this.array[this.offset];
};
ArraySeq2.make = function(array, offset) {
if (offset == null) offset = 0;
if (offset >= array.length)
return null;
else
return new ArraySeq2(array, offset);
};
function RangeSeq2(from, to) {
this.from = from;
this.to = to;
}
RangeSeq2.prototype.rest = function() {
return RangeSeq2.make(this.from + 1, this.to);
};
RangeSeq2.prototype.head = function() {
return this.from;
};
RangeSeq2.make = function(from, to) {
if (from > to)
return null;
else
return new RangeSeq2(from, to);
};
logFive2(ArraySeq2.make([1, 2]));
// → 1
// → 2
logFive2(RangeSeq2.make(100, 1000));
// → 100
// → 101
// → 102
// → 103
// → 104