Eloquent JavaScriptを使用しています。問題#6.3(第2版)に関する質問があります。ここでEloquent JavaScript、Sequence Interface
は問題です:
値のコレクションの反復処理を抽象化するインターフェースを設計します。このインターフェイスを提供するオブジェクトは というシーケンスを表し、インターフェイスは何らかの形で などのオブジェクトを使用してシーケンス上で繰り返し処理する必要があります。 という値を見て、それを検索する方法がありますシーケンスの末尾に が到達したときに終了します。
あなたのインターフェイスを指定している、シーケンス・オブジェクトを受け取り、シーケンスが5つ未満の の要素を持っている場合、その 最初の5つの要素、または少ない上にconsole.logを呼び出す関数 logFiveを書いてみます。
次に、配列をラップするオブジェクト型ArraySeqを実装し、設計したインターフェイスを使用して配列に対して の繰り返し処理を行うことができます。 (そのコンストラクタの引数から引き継いで)整数の範囲を反復する別のオブジェクト型のRangeSeqを実装してください。
私は、このソリューションを書いた:
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
作者によるソリューションはここに、異なっているが、それらの両方は、以下のとおりです。
// 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
私の質問:
マイソリューションは、著者のソリューションとまったく同じ結果をもたらします。私はさまざまなテストケースで3つすべてをテストしました。私は、私の解決策を書くときにこの章の内容を利用しました(この章ではJavaScript、継承などのOOPテクニックについて説明しています)。 このことを考えると、私の解決策は間違っているかどうか?
なぜ彼のソリューションは書かれている方法で書かれていますか?私のアプローチに間違いがありますか?十分に抽象的ではない?私の方法が議論を受け入れるのは悪いことですか?彼の方法は議論を必要としない。 彼のソリューションに比べて私のソリューションに欠点はありますか?(私の解決策は、おそらく問題の私の理解のレベルを反映しているので、私は告白しなければならない、私はやっと、問題を理解する。)
ありがとうございました!分かりました。 –
パターン「return {next:function(){...}}」は、私にとって初めてのパターンです。 "get:function(){...}"と "set:function(){...}"というやや似たようなものがありました。それはたぶん彼のソリューションが冗長である理由でしょう - 彼は読者に紹介したものだけに頼らざるを得ません。 –