白猫のメモ帳

C#とかJavaとかJavaScriptとかHTMLとか機械学習とか。

callとかapplyはいつ使う?

あけましておめでとうございます。

お正月、いかがお過ごしでしたでしょうか。
おもちは食べましたか。初詣はいきましたか。


さて、たまにはJavaScriptのお話をします。
callとapplyを使うことはありますか。違いは知っていますか。

結論から先に書くと、違いは「引数の渡し方」だけです。
これは別にそんなに重要ではないので、2つのfunctionの使い道をちょっと考えてみます。

何ができるのか


そもそもこれが謎なまま使おうと思っても、使い道は当然ありません。
ためしにMDNのcallの概要を見てみると、

this の値と、個々にあたえた引数をわたして、関数を呼び出します。

とあります。
後半の「個々にあたえた引数をわたして、関数を呼び出します。」は普通の関数呼び出しと変わらないわけですから、
thisの値を渡すことに意味があることがわかります。

つまり、「任意のオブジェクトをthisに束縛できる」というのがcallやapplyの存在意義と言えそうです。

どう使うのか


何ができるのかはわかりましたが、どう使うのかがまだ謎のままです。
というわけで、よく使うパターンを2つほど紹介します。

①イベントバインドされたfunctionを任意のオブジェクトで呼び出す

jQueryなどのライブラリを使うと、イベントに関数をバインドすることが多々あります。
(もちろんネイティブのaddEventListenerとかでも)

$(".target").on("click", myAlert);
function myAlert() {
    alert($(this).text());
}

当然この場合のthisはクリックされた要素自体を指すわけです。
が、myAlertは独立した関数なので、そのまま呼び出すことができます。

$(".newTarget").on("click", function() {
    myAlert();
    myLog();
});
function myAlert() {
    alert($(this).text());
}
function myLog() {
    console.log($(this).text());
}

この場合、呼び出し時にthisがバインドされていないため、グローバルオブジェクトになってしまいます。
これは困ってしまいますね。そこで、callを使うとこんな風に書き換えることができます。

$(".newTarget").on("click", function() {
    myAlert.call(this);
    myLog.call(this);
});
function myAlert() {
    alert($(this).text());
}
function myLog() {
    console.log($(this).text());
}

上の階層のthisを下の階層に渡すことによって、
thisの指す先を示してあげるということですね。

②他オブジェクトのprotetype関数を利用する

こちらはもう少し黒魔術的な使い方です。
よくあるのがargumentsにArrayのprotetype関数を利用するパターンです。

// エラーになる
var slicedArgs = arguments.slice(1);

argumentsオブジェクトは配列っぽいのでArrayのprotetype関数を使いたくなりますが、
残念ながら「配列っぽいけど配列じゃない何か」なので使えません。
そこで、callを利用します。

// 使える!
var slicedArgs = Array.prototype.slice.call(arguments, 1);


というわけで、可変長引数を利用するとこんなことができるわけですね。

function myConcat(separator) {
    var slicedArgs = Array.prototype.slice.call(arguments, 1);
    return slicedArgs.join(separator);
}

// "first,secont,third"が返る
myConcat(",", "first", "second", "third");


個人的にはこの2パターンしかcallやapplyは使いません。
ちょっとややこしいですが、覚えておくと困ったときの解決方法が増えて素敵ですね。

それでは、本年もよろしくお願いします。