#誰に向けて
- 全てのJS初心者に向けて
- 技術的なことばをできるだけ避けて学びたい人
#経緯
JavaScript初学者です。
パッションが湧いてきて、ここ数日間猛烈に学んでいます。
「this」の扱いが比較的とっつきづらかったので、
注意すべき点を整理しました。
注意すべき点をまとめて
「アロー呼び出しABC」
などとゴロよく呼べば
頭のメモリを節約できそうです。
(フロントエンドは諸行無常なのでいつまで持つかわかりませんが)
では、それぞれの項目を細かく見ていきます。
#呼び出し
##1.関数呼び出し
宣言した関数を関数名()
で直接呼び出します。
関数の宣言方法は以下の記事でまとめました。
https://qiita.com/konkipiano/items/ba9df345c17e739ecba2
お笑い好きによるJavaScriptの関数宣言まとめ
this
はグローバルオブジェクト、つまりWindow
を指します。
//関数宣言
function tsukkomi(){
console.log(this);
}
//関数呼び出し
tsukkomi(); //->Window {…}
###※間違えやすい点
オブジェクトの中でも、
関数呼び出しであればthisは問答無用で「Window」を指します。
関数の宣言場所がオブジェクトの中でも外でも関係ありません。
//外部関数宣言
function tsukkomi(){
console.log(this);
}
//オブジェクト宣言
var geinin = {
tsukkomi: function(){
//外部関数呼び出し
tsukkomi();
}
}
//関数呼び出し
tsukkomi(); //->Window {…}
//メソッド呼び出し(中で関数呼び出し)
geinin.tsukkomi(); //Window {…} thisは"geinin"ではなく"Window"を指す
//オブジェクト宣言
var geinin = {
tsukkomi: function(){
//内部関数宣言
function tsukkomi(){
console.log(this);
}
//内部関数呼び出し
tsukkomi();
}
}
//関数呼び出し
tsukkomi(); //->Window {…}
//メソッド呼び出し(中で関数呼び出し)
geinin.tsukkomi(); //Window {…} thisは"geinin"ではなく"Window"を指す
##2.メソッド呼び出し
オブジェクトのフィールドに宣言されている関数を、
オブジェクト名.関数名()
で呼び出します。
thisはメソッドの親オブジェクトを指します。
var geinin = {
tsukkomi: function(){
console.log(this);
}
}
geinin.tsukkomi(); //->{tsukkomi: ƒ} メソッドの親オブジェクト"geinin"を指す
##3.コンストラクタ呼び出し
コンストラクタ関数をnew
で呼び出してインスタンス生成します。
このとき、コンストラクタ関数の中のthisは生成されるインスタンスを指します。
//コンストラクタ関数宣言
function Geinin(boke,tsukkomi){
this.boke = boke;
this.tsukkomi = tsukkomi;
}
//コンストラクタ関数をnewで呼び出し
var kojima = new Geinin("oi","kojimadayo");
console.log(kojima.boke); //->"oi"
console.log(kojima.tsukkomi); //->"kojimadayo"
###※間違えやすい点
コンストラクタ関数をnewなしで呼び出す場合、「関数呼び出し」になります。
つまり、thisは「Window」を指します。
//コンストラクタ関数宣言
function Geinin(boke,tsukkomi){
this.boke = boke;
this.tsukkomi = tsukkomi;
}
//コンストラクタ呼び出し…?いえ、newが無いので「関数呼び出し」です
var kojima = Geinin("oi","kojimadayo");
//newを忘れたkojimaはすごく怒られる
console.log(kojima.boke); //->怒られる
console.log(kojima.tsukkomi); //->怒られる
//そしてWindowにポジションを取られる
console.log(window.boke); //->"oi" windowが"oi"とボケてしまう
console.log(window.tsukkomi); //->"kojimadayo" windowが"kojimadayo"とツッコんでしまう
#ABC(apply/bind/call)
apply/bind/callの頭文字を取りました。
これらの共通点は、**「thisを書き換える」**ということです。
目的別にわけると、
thisを書き換えて関数を実行する「apply」と「call」
thisを書き換えて関数を返す「bind」
となります。
##AとC (apply/call)はthisを上書きして関数を実行する
applyとcallはどちらも、
thisを上書きして関数を実行します。
var joymanIketani = {
tsukkomi: "nanda koitsu~",
doTsukkomi: function() {
console.log(this.tsukkomi);
}
};
var fujimoto = {
tsukkomi: "nanda koitsu~~~~~~~~~~~~!!!!!!"
}
joymanIketani.doTsukkomi(); //->"nanda koitsu~" 池谷が持ってる"tsukkomi"が適用される
joymanIketani.doTsukkomi.apply(fujimoto); // ->"nanda koitsu~~~~~~~~~~~~!!!!!!" 藤本が持ってる"tsukkomi"が適用される
上はapplyを使ったコードです。
これをcallで書き換えるには、applyをcallに書き換えるだけです。
var joymanIketani = {
tsukkomi: "nanda koitsu~",
doTsukkomi: function() {
console.log(this.tsukkomi);
}
};
var fujimoto = {
tsukkomi: "nanda koitsu~~~~~~~~~~~~!!!!!!"
}
joymanIketani.doTsukkomi(); //->"nanda koitsu~" 池谷が持ってる"tsukkomi"が適用される
joymanIketani.doTsukkomi.call(fujimoto); // ->"nanda koitsu~~~~~~~~~~~~!!!!!!" 藤本が持ってる"tsukkomi"が適用される
ちなみにこのサンプルコードで使っている
ジョイマン池谷さんとFUJIWARA藤本さんの絡みについてはこちら
https://www.youtube.com/watch?v=vkWjYgXpZJE
###※applyとcallはじゃあ何が違うのか
ブレるので、このページでは説明を省きます。
また今度まとめます。
お笑い好きによる「apply」と「call」の違い
https://qiita.com/konkipiano/items/{TODO:記事を書いたらここにリンク貼る}
##B (bind)はthisを上書きして関数を返す
すでにあるオブジェクトのthisを書きかえて関数を返します。
var joymanIketani = {
tsukkomi: "nanda koitsu~",
doTsukkomi: function() {
console.log(this.tsukkomi);
}
};
var fujimoto = {
tsukkomi: "nanda koitsu~~~~~~~~~~~~!!!!!!"
}
var fujimotoIketaniDoTsukkomi = joymanIketani.doTsukkomi.bind(fujimoto) // ->関数を代入する
fujimotoIketaniDoTsukkomi(); //-> "nanda koitsu~~~~~~~~~~~~!!!!!!" この変数がthisをfujimotoに書き換えたdoTsukkomi関数を持ってる
#アロー関数
アロー関数は、以下のように宣言する関数です。
let pikotaro = (pen,fruits) => {
return fruits + pen;
} //処理が1つの場合、{}を省略できる。
>
console.log(pikotaro('pen','apple')); //->applepen
参考:
お笑い好きによるJavaScriptの関数宣言まとめ
https://qiita.com/konkipiano/items/ba9df345c17e739ecba2
アロー関数で関数宣言すると、
宣言した時点でthisを固定することができます。
ちょっと何言ってるかわからないので、
通常の関数宣言とアロー関数による関数宣言を比べてみます。
// hanmar kanmarをグローバルなボケとして宣言
boke = "hanmar kanmar";
// 台本ボケをする関数
function doBoke() {
console.log(this.boke);
}
// zakoshishoがボケる関数
doZakoshiBoke = () => {
console.log(this.boke); // この時点でthisがwindowに固定される!
}
// この時点ではどちらのthis.bokeも"hanmar kanmar"を指す
doBoke(); //->"hanmar kanmar"
doZakoshiBoke(); //->"hanmar kanmar"
// 台本に"ai tuima te~n"と書いてあるお笑い番組
var desuyo_tv = {
boke: "ai tuima te~n",
geinin: doBoke,
zakoshi: doZakoshiBoke
};
// 台本に"chikusho"と書いてあるお笑い番組
var koume_tv = {
boke: "chikusho",
geinin: doBoke,
zakoshi: doZakoshiBoke
}
// desuyo_tvの進行
desuyo_tv.geinin(); //->"ai tuima te~n" 台本通りボケる
desuyo_tv.zakoshi(); //->"hanmar kanmar" 台本にセットされたボケを無視する
// koume_tvの進行
koume_tv.geinin(); //->"chikusho~" 台本通りボケる
koume_tv.zakoshi(); //->"hanmar kanmar" 台本にセットされたボケを無視する
通常の関数宣言で作成されたdoBoke
関数は、
desuyo_tv
でもkoume_tv
でも
ちゃんと台本通り
"ai tuima te~n"
や
"chikusho"
とボケています。
こんな番組ないですが。
つまり、thisが呼ばれる番組によって変わることがわかります。
一方で、
アロー関数で宣言した
doZakoshiBoke
関数は、
どちらの番組のboke
も無視して
"hanmar kanmar"
とボケています。
つまり、呼ばれる番組に関わらずthisがWindowに固定されていることがわかります。
これがアロー関数によるthisの特徴です。
#まとめ
JavaScriptのthisはアロー呼び出しABCに注意します(2018/5/17現在)。
技術書を読むと
"thisを束縛する"
などのようなカッコイイ表現がたくさんありました。
ですが、この記事では「頭良く見られたい」という欲を必死におさえて
自分にとってイメージしやすい表現を使いました。
見識のある方からすると「なんだ??」という部分があると思います。
そういう場合はコメント頂けると嬉しいです。
#参考にさせていただいたページ
JavaScriptの「this」は「4種類」??
https://qiita.com/takeharu/items/9935ce476a17d6258e27
【JavaScript】アロー関数式を学ぶついでにthisも復習する話
https://qiita.com/mejileben/items/69e5facdb60781927929
Javascriptのbind関数と部分適用 〜 JSおくのほそ道 #015
https://qiita.com/mejileben/items/69e5facdb60781927929