jQueryのeachを読む

コードリーディングの第一歩として自分が読みやすいJavaScriptを読むことに。

jQueryのソースコードを読むための参考サイト20選 - DQNEO起業日記

を参考にして、よく使うeachメソッドを読んでみる。

ソースコードビューアあったから、古いバージョンとメソッドの内容を比較するのにいいかもしれない。

jQuery source viewer

よく使う方法

このようなhtmlがある時に、liを1つずつ取り出す。

<ul>
    <li>(・∀・)</li>
    <li>(*´Д`)</li>
    <li>(・∀・)</li>
    <li>(*´Д`)</li>
    <li>(・∀・)</li>
</ul>
$('li').each(function(i, elm) {
    // elm == this
    console.log(i + $(elm).text()); // 0(・∀・) のように表示される
});

eachメソッド

// args is for internal usage only
each: function( obj, callback, args ) {
    var value,
        i = 0,
        length = obj.length,
        isArray = isArraylike( obj );

    if ( args ) {
        if ( isArray ) {
            for ( ; i < length; i++ ) {
                value = callback.apply( obj[ i ], args );

                if ( value === false ) {
                    break;
                }
            }
        } else {
            for ( i in obj ) {
                value = callback.apply( obj[ i ], args );

                if ( value === false ) {
                    break;
                }
            }
        }

    // A special, fast, case for the most common use of each
    } else {
        if ( isArray ) {
            for ( ; i < length; i++ ) {
                value = callback.call( obj[ i ], i, obj[ i ] );

                if ( value === false ) {
                    break;
                }
            }
        } else {
            for ( i in obj ) {
                value = callback.call( obj[ i ], i, obj[ i ] );

                if ( value === false ) {
                    break;
                }
            }
        }
    }

    return obj;
}
eachメソッドについての疑問
  1. eachの第3引数argsは何か?使うの?
    第3引数argsがある場合はapply、ない場合はcallを使っている。applycallって何だっけ?
  2. $.each($('li'))$('li).each 両方使えるよね?

1. eachの第3引数argsは何か?使うの?

applyとcall

全く読んでいなかったサイ本の出番!第5版しかもってないからそれを引っ張り出して読む。サイ本、いい本ですよね。

JavaScript 第6版

JavaScript 第6版

P.138 8.6.4 apply()メソッドとcall()メソッド の部分より引用

2つのメソッドを利用すると、あるオブジェクトのメソッドであるかのように関数を呼び出すことができます。call()メソッドとapply()メソッドの最初の引数は、これから呼び出す関数の対象となるオブジェクトで、関数の本体のthisキーワードの値になります。call()メソッドの2番目以降の引数は、これから呼び出す関数に引数として渡されます。

apply()メソッドとcall()メソッドの違いについては、

apply()メソッドもcall()メソッドと同じような働きをします。ただ、関数に渡す引数を配列形式で指定する点が異なります。

なるほど。第3引数のargsは配列形式で渡してあげると。

第3引数argsを試す

試しに第3引数を渡してeachを実行してみる。

// callback関数の引数に第3引数で渡した配列の値が入る。
$.each(['a', 'b', 'c'], function(a, b) {
    console.log(this); // String {0: "a", length: 1}
    console.log(a); // 1
    console.log(b); // 2
}, [1, 2]);

$('li').each(function(a, b) {
    // elm == this
    console.log($(this).text() + ':' + a + ' :' + b); // (・∀・):3 :5 
}, [3, 5]);    

// 第3引数は配列形式じゃないといけないので、以下はエラーになる
$('li').each(function() {
    console.log(this);
}, 'test');

ここまで見て思ったのは、eachに第3引数を渡して使ったことないこと。

使い方としては以下のような感じ?うーん・・・

// こういう使い方は出来るのか?
$.each([1, 2, 3], function(x, y) {
    console.log(this + ':' + x + ':' + y); // 1:5:10
    console.log((this + x) * y); // 60
}, [5, 10]);

// わざわざ引数で渡すならこうするかな?
$.each([1, 2, 3], function() {
    var x = 5, y = 10;
    console.log(this + ':' + x + ':' + y); // 1:5:10
    console.log((this + x) * y); // 60
});

まて。eachメソッドにコメント書いてあった。

// args is for internal usage only

argsは内部利用のためにのみ使う??よくわからなかった。。

第3引数なしの場合はcallback.call()が実行される

argsがない場合のコメント

// A special, fast, case for the most common use of each

eachの一般的な使い方ってことかな??

配列じゃなくてオブジェクトもOK

// オブジェクトもいける
// callback関数の引数には`key`と`value`が入ってくる
$.each({'test': 123, 'test2': 'あいうえお'}, function(key, value) {
    console.log(key, value); // test 123, test2 あいうえお
    console.log(this); // Number {}, String {0: "あ", 1: "い", 2: "う", 3: "え", 4: "お", length: 5}
});


// `i`にはindex, `v`には値が入ってくる
// この場合は this == v
var obj = $.each([1, 2, 3, 4, 5], function(i, v) {
    console.log(i + ':' + this); // 0:1, 1:2, 2:3, 3:4, 4:5
    console.log(i + ':' + v); // 0:1, 1:2, 2:3, 3:4, 4:5
});
// each関数はobjをreturnするのでこうなる
console.log(obj); // [1, 2, 3, 4, 5]

2. $.each($('li'))$('li').each 両方使えるよね?

$('li').each(function(i, elm) {}); の場合は以下が呼ばれる。

// Execute a callback for every element in the matched set.
// (You can seed the arguments with an array of args, but this is
// only used internally.)
each: function( callback, args ) { // callbackにfunction(i, elm) {} が入る
    return jQuery.each( this, callback, args ); // eachメソッドを呼ぶ。thisは$('li')
},

jQuery.eachを呼んでいるので、 $.each($('li'), function(i, elm) {}); となる!