Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

お笑い好きによるJavaScriptの「this」まとめ

More than 1 year has passed since last update.

誰に向けて

  • 全てのJS初心者に向けて
  • 技術的なことばをできるだけ避けて学びたい人

経緯

JavaScript初学者です。
パッションが湧いてきて、ここ数日間猛烈に学んでいます。

「this」の扱いが比較的とっつきづらかったので、
注意すべき点を整理しました。

全体像(2018/05/28現在)

全体像は以下です。
image.png

注意すべき点をまとめて

「アロー呼び出しABC」

などとゴロよく呼べば
頭のメモリを節約できそうです。
(フロントエンドは諸行無常なのでいつまで持つかわかりませんが)

では、それぞれの項目を細かく見ていきます。

呼び出し

1.関数呼び出し

宣言した関数を関数名()で直接呼び出します。
関数の宣言方法は以下の記事でまとめました。

https://qiita.com/konkipiano/items/ba9df345c17e739ecba2
お笑い好きによるJavaScriptの関数宣言まとめ

thisグローバルオブジェクト、つまりWindowを指します。

tsukkomi_func.js
//関数宣言
function tsukkomi(){
  console.log(this);
}

//関数呼び出し
tsukkomi();  //->Window {…}

※間違えやすい点

オブジェクトの中でも、
関数呼び出しであればthisは問答無用で「Window」を指します。
関数の宣言場所がオブジェクトの中でも外でも関係ありません。

tsukkomi_func_obj_out.js
//外部関数宣言
function tsukkomi(){
  console.log(this);
}

//オブジェクト宣言
var geinin = {
  tsukkomi: function(){
    //外部関数呼び出し
    tsukkomi();
  }
}

//関数呼び出し
tsukkomi();  //->Window {…}
//メソッド呼び出し(中で関数呼び出し)
geinin.tsukkomi();  //Window {…}  thisは"geinin"ではなく"Window"を指す
tsukkomi_func_obj_in.js
//オブジェクト宣言
var geinin = {
  tsukkomi: function(){
    //内部関数宣言
    function tsukkomi(){
      console.log(this);
    }
    //内部関数呼び出し
    tsukkomi();
  }
}

//関数呼び出し
tsukkomi();  //->Window {…}
//メソッド呼び出し(中で関数呼び出し)
geinin.tsukkomi();  //Window {…}  thisは"geinin"ではなく"Window"を指す

2.メソッド呼び出し

オブジェクトのフィールドに宣言されている関数を、
オブジェクト名.関数名()で呼び出します。
thisはメソッドの親オブジェクトを指します。

tsukkomi_method.js
var geinin = {
  tsukkomi: function(){
    console.log(this);
  }
}
geinin.tsukkomi();  //->{tsukkomi: ƒ}  メソッドの親オブジェクト"geinin"を指す

3.コンストラクタ呼び出し

コンストラクタ関数をnewで呼び出してインスタンス生成します。
このとき、コンストラクタ関数の中のthisは生成されるインスタンスを指します。

tsukkomi_const.js
//コンストラクタ関数宣言
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」を指します。

tsukkomi_const_func.js
//コンストラクタ関数宣言
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を上書きして関数を実行します。

joyman_apply.js
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に書き換えるだけです。

joyman_call.js
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を書きかえて関数を返します。

joyman_bind.js
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関数を持ってる

アロー関数

アロー関数は、以下のように宣言する関数です。

arrow.js
let pikotaro = (pen,fruits) => {
  return fruits + pen;
} //処理が1つの場合、{}を省略できる。

console.log(pikotaro('pen','apple'));  //->applepen

参考:
お笑い好きによるJavaScriptの関数宣言まとめ
https://qiita.com/konkipiano/items/ba9df345c17e739ecba2

アロー関数で関数宣言すると、
宣言した時点でthisを固定することができます。

ちょっと何言ってるかわからないので、
通常の関数宣言とアロー関数による関数宣言を比べてみます。

HollywoodZakoShisho_arrow.js
// 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

konkipiano
Webエンジニア兼ピアノ弾き。 ピアノは15年間独学。楽しいから続く。 ピアノ同様、コーディングもシンプルな学びを目指す。
https://www.youtube.com/channel/UCkevdgimtQpVhTlqfe1aaXg
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away