アプリ版:「スタンプのみでお礼する」機能のリリースについて

お世話になっております。現在JavaScriptの勉強をしております。
その一環としてPrototype.js ver 1.6.1 を解読しているのですが
Enumerable 等のメソッドで出てくる return でリテラル関数を指定するような部分が多々見受けられるのですが…この意味がイマイチ感覚がつかめず困っています。
例:Prototype.js 702行目付近
Enumerable = (function(){...
の collectメソッド(743行目付近)

function collect(iterator, context) {
iterator = iterator || Prototype.K;
var results = [];
this.each(function(value, index) {
results.push(iterator.call(context, value, index));
});
return results;
}
などの
this.each(function(value, index) {
results.push(iterator.call(context, value, index));
}
部分で
function(value, index)...
とあるvalue, index はどこでどれから指定されるのかがよくわかりません。

[1,2,3,4].collect(a,b);
と呼び出した場合、collect(a,b){... と呼ばれますが value と indexには何がどうやって指定されるのでしょうか?
このような記法が把握できず、混乱を極めている状態です。

どなたかお手数ですがお教え願えないでしょうか?
よろしくお願いいたします。

A 回答 (5件)

prototype.jsからコードを抜き出して読み易くまとめてみました。


Arrayオブジェクトしか扱えませんけど。

//- Arrayオブジェクトの拡張 -------------------------
Array.prototype._each = function (iterator) {
for (var i = 0, length = this.length; i < length; i++) {
iterator(this[i]); // callback関数第一引数 (this[i])
}
};

Array.prototype.each = function (iterator, context) {
var index = 0;
this._each(function(value) {
iterator.call(context, value, index++); // callback関数第二引数 (index++)
});
}

Array.prototype.collect = function (iterator, context) {
var results = [];
this.each(function(value, index) {
results.push(iterator.call(context, value, index));
});
return results;
}
//- Arrayオブジェクトの拡張ここまで ------------------

var arr = [ 2, 4, 6, 8 ];
//各要素を2倍した値に置き換えその結果を返す
var callback = function (v, i) { return this[i] = v * 2; };
var results = arr.collect(callback, arr /* 関数内this値 */);
alert('collectメソッドの戻り値: ' + results);
alert('arrの値: ' + arr);

//- ここまで -----------------------------------------


//Array.collect()に限るなら
Array.prototype.collect = function (iterator, context) {
var results = [];
for (var i = 0, length = this.length; i < length; i++) {
results.push(iterator.call(context, this[i], i));
}
return results;
}

Function.prototype.call
http://www2u.biglobe.ne.jp/~oz-07ams/prog/ecma26 …

Function.callメソッドさえ抑えれば難しくないはずです。

この回答への補足

ご回答いただき誠にありがとうございます。
callback変数に関数オブジェクトを代入することで
ずいぶん感覚がつかみやすくなりました。
何となくわかってきた気がします。
要はEnumerable の定義でのfunction(value, index)は
「Enumerable をインタフェースに持つクラスはそのメソッド使う時は
こういうフォーマットの評価・処理関数をしてくださいな」
ということなのでしょうか?
>var arr = [ 2, 4, 6, 8 ];
>//各要素を2倍した値に置き換えその結果を返す
>var callback = function (v, i) { return this[i] = v * 2; };
>var results = arr.collect(callback, arr /* 関数内this値 */);

>Array.prototype.collect = function (iterator, context) {
>var results = [];
>this.each(function(value, index) {
>results.push(iterator.call(context, value, index));
>});
↑のthis.each(fuction(v, i){results.puch(callback.call(context, v, i);}
となるイメージでよろしいのでしょうか?

補足日時:2010/03/10 18:48
    • good
    • 0

No.1さらに気づいた事


iterator.call(context, value, index)
の部分は単にiteratorを実行しているのではなく、
iteratorクラスの継承でvalueとindexをiterator内で
使える用にしているという事かなあ。

想像ばかりの回答で、すんません。

有識者の回答を待ちましょう....
    • good
    • 0
この回答へのお礼

たびたびご回答いただきありがとうございます。
Arrayに関しては_eachを実装しているので分かりやすいので逆にたどればEnumerableとの動作連携は分かる気がします。
のんびり待ちます…
その前に自力で把握できればいいのですけどね。(苦笑

お礼日時:2010/03/10 17:51

No.1です。

私の回答ちょっと違ってました。
オブジェクト指向にそんなに詳しいわけじゃないんですが。
「Enumerableでとなっているの所のvalue はどこから来るんだ?」
valueはやはりthisで受け渡されていくような気がします。

Enumerable.collect(iterator)はリストEnumerableを返すのですよね。

ret=[1,2,3,4].collect(function(val,idx){return val+idx;});
だとcollect(){}の中でthisは[1,2,3,4]ですよね
このthisが、this.each(function(value, index) {
results.push(iterator.call(context, value, index));
});
でeach(){}で処理され、each(){}の中のthisも
[1,2,3,4]になります。さらにeachの中で
this._each(function(value) {
iterator.call(context, value, index++);
});
となっているので、this [1,2,3,4] がそのまま_eachで処理されます。
よって_each(){}の中のthisも[1,2,3,4]のことになるので

_each: function(iterator) {
for (var i = 0, length = this.length; i < length; i++)
iterator(this[i]);
}

iterator(this[i]); で、[1,2,3,4] の i 番目がiteratorで処理されます、
iterator関数内に引き渡す際の引数名が単にvalueなのではないかと、
    • good
    • 0

No.1補足


this.eachのeachもprototype.jsのメンバーで、
var Enumerable = {
each: function(iterator, context) {
var index = 0;
try {
this._each(function(value) {
iterator.call(context, value, index++);
});
} catch (e) {
if (e != $break) throw e;
}
return this;
}
となっており、さらに別のところで
Object.extend(Array.prototype, {
_each: function(iterator) {
for (var i = 0, length = this.length; i < length; i++)
iterator(this[i]);
}
ますから、indexはこの仕組みの中で作られて、使われるわけですね。

この回答への補足

お世話になります。
Object.extend(Array.prototype, {
_each: function(iterator) {
for (var i = 0, length = this.length; i < length; i++)
iterator(this[i]);
}
のところは感覚として分かるのです。配列インスタンス(this)の各要素にiteratorを実行するのだと…
//---
each: function(iterator, context) {
var index = 0;
try {
this._each(function(value) {
iterator.call(context, value, index++);
});
} catch (e) {
//---
Enumerableでとなっているの所のvalue はどこから来るんだ?
となってしまうのです。_each(以降の部分がiterator?としてEnumerableを追加されたクラスの_each()へ行くのかな?と
なんだか迷走してしまうんです。
お手数ですがお答えいただけたら幸いです。

補足日時:2010/03/10 15:15
    • good
    • 0

質問の意味がよくわからないのですが...


[1,2,3,4].collect(a,b);と使うのは変です。a,bは何ですか?
列挙型オブジェクト.collect(イテレータ関数);
と使われるはずです。
function collect(iterator, context){}
の内部で引き渡したイテレータ関数が
results.push(iterator.call(context, value, index));
で、iterator()の名前で呼び出されて、結果をresultsに格納して
return results;で返しています。
iterator.call(context, value, index)時の
valueとindexは、
this.each(function(value, index) {

内にありますから、
thisのそれぞれの配列要素と要素キーです。
thisはcollect()のを呼んだやつの列挙型オブジェクトです。
つまり
[1,2,3,4].collect(function(a,b){alert(a[b])});
ならaがvalueで[1,2,3,4]、bがindexでその配列の
要素キー 0,1,2,3 をbでアクセス出来る
という事では....

この回答への補足

お世話になっております。
言葉足らずで申し訳ありません。collect()自身に疑問があるわけではなく、

>iterator.call(context, value, index)時の
>valueとindexは、
>this.each(function(value, index) {
>}
>内にありますから、
>thisのそれぞれの配列要素と要素キーです。
>thisはcollect()のを呼んだやつの列挙型オブジェクトです。
>つまり
>[1,2,3,4].collect(function(a,b){alert(a[b])});
>ならaがvalueで[1,2,3,4]、bがindexでその配列の
>要素キー 0,1,2,3 をbでアクセス出来る
>という事では....

とご回答いただいたわけですが、まさにそこが疑問点なのです。
[1,2,3,4].collect(function(a,b){alert(a[b])});
ならaがvalueで[1,2,3,4]、bがindexでその配列の
要素キー 0,1,2,3 をbでアクセス出来る
のaがなぜvalueの[1,2,3,4]になり、bがindexになるのか?
というところが分からないのです。
「そうなるんだよ」と言われたらそれまでなのですが、
なぜそうなるのかおわかりでしたらお教え願えないでしょうか?

補足日時:2010/03/10 15:06
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!