はじめに
この記事は、漫画などにたとえて理解(わか)ったつもりになる、ほぼ自分用のアウトプットです。
なんとかこじつけているので、技術側、漫画側も表現の正しさそっちのけです。
また、元ネタを知らない場合は完全に何言ってんだコイツ状態でしょうけどそっ閉じしてください。
「ワールドトリガー」とは
週刊少年ジャンプで連載されてた遅効性SF漫画です。ボーダーと呼ばれる部活動軍隊が不思議な力「トリオン」で動作する武器を使い、日々部隊同士で模擬戦による訓練を行い、ネイバーと呼ばれる異世界人からの侵略を防衛します。現在はジャンプSQに移籍し連載中。
関数・メソッド概論
戦闘員が関数やメソッド
JavaScriptにおける関数・メソッドとは、大雑把にいうと「実行可能なオブジェクト」です。
ワールドトリガーの世界ではボーダーに所属するもの、しないものもあわせていろんなひとがいます。
これらすべての人を「オブジェクト」として考えましょう。オブジェクトは「情報のあつまり」です。
このうち、戦うことができる、すなわち実行することができるのは、ボーダー所属の戦闘員だけです。
// 戦闘員(三雲)は戦える
function mikumo() {}
mikumo();
// 非戦闘員(鬼怒田開発本部長)は戦えない
let kinuta = {};
kinuta(); // <-- そんな関数はないぜエラー
部隊に所属していない戦闘員が関数で、部隊に所属している戦闘員がメソッド
さて、ここで関数とメソッドという言葉が出てきました。
これらは区別されないで用いられたりもするのですが、厳密には異なる概念だと思っていますがあやふやです。
雑に説明すると、部隊に所属していない戦闘員が関数で、部隊に所属している戦闘員がメソッドです。
// 迅悠一は関数
let jinYuichi = function() {};
jinYuichi();
// 三雲修は部隊(玉狛第二)に所属しているメソッド
let tamakoma2nd = {}
tamakoma2nd.mikumoOsamu = function() {};
tamakoma2nd.mikumoOsamu();
ちょっとだけ関数を深掘り
なお、個人的に関数は「任意の引数を受け取り任意の値を返す、冪等性のある一連の処理」と認識しています。
冪等性とは何か。ざっくりいうと「何度呼び出しても同じ結果になること」です。
何度繰り返してもまゆしーは結果的にアレなので冪等性がありそうですが、まどかは毎度毎度結果が異なるうえ、因果がさらに巻き付くので冪等性がありません。
孤月の素振りには冪等性があり、弾トリガーには冪等性がない
ワールドトリガーに話を戻します。
刀型トリガー孤月で虚空に向かい素振りをする太刀川隊員。
刀型トリガーは生成時にトリオンを消費するものの、破壊されたり破棄しない限りはそのまま使い続けることができます。
従って何十回何百回素振りしても 訓練にはなるかもしれませんが 結果は変わりません。
一方、銃手、射手用のトリガーはどうでしょうか。
弾を撃つ度にトリオンは消費され、さらに弾が当たった箇所は破壊されます。
これでは呼び出すたびに残りのトリオン量(状態)が変わり、結果(破壊された場所)も増えていきます。
これが冪等性のない状態です。
そして本来、関数は同じ引数を与える以上は同じ結果を返す必要があるのです。
ちょっとだけメソッドを深掘り
メソッドは誰かに与えた指示のイメージ
一方、メソッドは「レシーバーへのメッセージパッシングとして呼び出す一連の処理」だと考えています。
ブラックトリガー争奪戦の際、趣味は暗躍でお馴染みの 迅悠一に指令(メッセージ)を送っています。●してでもうばいとる
この場合、命令するプログラムが林藤支部長、ぼんち揚げ食う?でお馴染みの 迅悠一がレシーバー、メッセージがブラックトリガー取ってくる、になります。
jinYuichi.getBlackTrigger();
参照(命令)できる範囲を示すスコープ
また、実力派エリート 迅悠一を参照できる範囲であるスコープが、本部のコンテキストである城戸司令ではなく、玉狛支部の林藤支部長にあるのも見逃せない点ですね。スコープについてはまたいつかどこかで書きたいと思います。
ボーダーに指示系統があるように、JavaScriptにはスコープという変数を参照できる範囲があるのです さすがにこじつけがすぎる 。
実装時の視点に応じて粒度が変わるよ(言い訳)
先ほど迅悠一は関数だって言ったじゃん嘘つき!という声が聞こえます 大人は嘘つきではないのです。まちがいをするだけなのです
が、これは何をオブジェクトやメソッドとして捉えるか、というモデリングの粒度の違いです。今回はオブジェクトを部隊でなくそれより細かい範囲である隊員単位、行動をメソッド単位で考えているので、予知予知あるきでお馴染みの迅悠一も単なるオブジェクトになりました。
なおJavaScriptの場合、たとえばブラウザ側ではグローバルでもwindowオブジェクトに紐づくので厳密にはレシーバが存在するのですがまあ全員ボーダーに所属しているよ的なイメージで。
thisとは
隊員をメソッドと考えた場合、thisとは所属部隊
JavaScriptには実行コンテキストという概念がありますが、これは要するに所属部隊のことだと思ってください。
三雲隊員はスパイダーで玉狛第二を強くする
さて、三雲修隊員は自身の戦闘力低いものの、所属部隊である玉狛第二に"this"というキーワードを通してバフをかけることができます。
let tamakoma2nd = {"tsuyosa" : 10};
tamakoma2nd.mikumo = function() {
console.log(this === tamakoma2nd);
this.tsuyosa += 10; // この"this"はtamakoma2ndを表す。
}
console.log(tamakoma2nd.tsuyosa); // 10
tamakoma2nd.mikumo(); // true
console.log(tamakoma2nd.tsuyosa); // 20
ソロの三雲隊員はスパイダーを使っても意味がない
一方で、三雲修隊員を玉狛第二から切り離してしまう=関数として実行すると対象になる所属部隊が存在しないので意味がなくなります。
// 続き
let aloneMikumo = tamakoma2nd.mikumo;
aloneMikumo(); // false
別の部隊でもスパイダーは有効活用できる
別の部隊に編入させてみましょう。諏訪11番隊にいれてみます。
// 続き
const suwa11th = {tsuyosa : 8, mikumo : aloneMikumo};
console.log(suwa11th); // 8
suwa11th.mikumo(); // false
console.log(suwa11th) // 18
よかったね。
入れ子になったときのthisと無名関数・アロー関数
勝手に動くトリオン兵を生成すると部隊には所属していない
玉狛第二のレプリカ先生が自立して勝手に動くトリオン兵を生成した場合、一時的に存在するトリオン兵は玉狛第二の所属ではないので、レプリカ先生のthisと、どこにも所属していないトリオン兵のthisは別のものを指します。
const tamakoma2nd = {};
tamakoma2nd.replica = function() {
const that = this;
const torionSoldier = function() {
console.log(this === that);
}
torionSoldier();
}
tamakoma2nd.replica(); // false
トリオン兵にわざわざ名前つけなくても・・・
上記の場合、トリオン兵という種族名(?)をつけていますが、使い捨てなので固有名詞=関数名がなくてもいいくらいです。
function() {
console.log(this == that);
}
こういうやつを無名関数といいます。
C級隊員を戦わせるなら指示を出した部隊が責任を取れよ的な設定ありそう(ない)
一方、まだ部隊に所属していない訓練生であるC級隊員の出穂ちゃんに指示を出して戦わせた場合、責任の所在は指示を出した部隊にあるような気がします。こういうときはアロー関数という、thisを束縛しない方法で行動させるといいでしょう。
const tamakoma2nd = {};
tamakoma2nd.replica = function() {
const that = this;
const izuho = () => { // アロー関数にする
console.log(this === that);
}
izuho();
}
tamakoma2nd.replica(); // false
玉狛第二の指揮下でC級隊員が活躍してくれました。
thisの束縛を行うbind
迅さんは所属しないけど玉狛第二のために行動する
さて、有能A級ぼっち隊員・迅悠一ですが、遊撃手として単独行動をさせつつも玉狛第二のためにヒュースを勧誘させる状況を考えましょう。
これには トリガー メソッドbind
を使います。
const tamakoma2nd = {name : '玉狛第二'};
window.name = 'よくわからないん';
const jinYuichi = function() {
console.log(`ヒュースが入るべき部隊は${this.name}だ`);
}
jinYuichi(); // ヒュースが入るべき部隊はよくわからないんだ
const tamakoma2ndJinYuichi = jinYuichi.bind(tamakoma2nd); // 一時的に玉狛第二に協力させる
tamakoma2ndJinYuichi(); // ヒュースが入るべき部隊は玉狛第二だ
迅さんがヒュースを説得してくれてよかったですね。
終わりに
逆にわかりにくくなった気がする!