57
56

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【TypeScript / JavaScript】this = "これ" ← どれ? 【備忘録】

Last updated at Posted at 2023-10-16

この記事で分かること

  • TypeScript(JavaScript)における関数の宣言方法
  • 各宣言方法におけるthisの扱い

初めに

初めまして。新人エンジニアをしているものです。
先日TypeScriptにおける関数宣言について学習する一環で、thisの取り扱いについて学んだので備忘録として書き上げます。

(前提)TypeScriptの関数の宣言方法

まずは複数ある関数の宣言方法を簡単にまとめます。

①function構文による宣言

function sum (a : number, b : number) : number {
    return a + b ;
}
  • JavaScriptでよくみられる記法
  • TypeScriptでは引数と戻り値に型注釈を付けられる
    • 変数の型注釈を書かない → any型判定
    • 戻り値の型注釈を書かない → 型推論
  • 巻き上げ(宣言した行の前の行で呼び出すこと)が可能

②function式による宣言

const sum = function funcName (a : number, b : number) : number {
    return a + b ;
}
  • 関数宣言は文であるのに対し、関数式は式
    → 変数に直接代入可能
  • 関数名は省略可
  • function式で宣言された関数名は関数内でのみ利用可能
  • 巻き上げ不可

③アロー関数による宣言

const sum = (a : number, b : number) : number => {
    return a + b ;
}

// 省略形の例
const plusOne = n => n + 1;

  • ほかの二つと比べて比較的新しく実装された機能
  • 関数式同様、アロー関数は式
  • 短く書くことができる
  • 引数が一つ、処理が一行(return)だけのときは省略形で書くことができる
  • ※引数の丸かっこも省略可だが、その場合は引数・戻り値の型注釈が書けなくなるので、可読性の観点からも書いたほうがベター。
// 引数の丸かっこを省略した場合、型注釈を使うことはできない
const plusOne = n :number :number => n + 1;  // ← このような記法はエラーになる

thisのふるまいの違い

アロー関数以外におけるthis

-> 実行時にthisのふるまいが決まる
関数におけるthisの基本的な参照先はベースオブジェクト(メソッドを呼ぶ際に.の前に置かれているオブジェクトのこと)を指します。
下の例では、this.nameを出力する関数funcを二通りの方法で呼び出しています。

function func () {
    console.log(this.name)
}

const obj = {
    name : "Baki",
    func : func,
}

// 1.単純に関数として呼び出す
func();  // "undefined"

// 2.obj のメソッドとして呼び出す
obj.func();   // "Baki"

1の方法で呼び出す場合には、ベースオブジェクトが存在していない場合、undefinedが出力されます。
対して、2の方法で呼び出す場合にはobjがベースオブジェクトとなるため、objに含まれるnameプロパティの値が出力されます。

※お使いの環境がstrict modeを利用している(コードに"use strict"と明記されている)場合、"undefined"ではない結果が出力されているかもしれません。これはthisがundefinedの場合はグローバルオブジェクトをベースオブジェクトとするというJavaScriptの仕様によるものです。

このように、呼び出し方でふるまいが変わるのがアロー関数以外におけるthisです。

アロー関数におけるthis

->宣言時に決まる静的な値
アロー関数はにおけるthisはレキシカルなスコープを持っています。端的に言えば静的な値のことで、宣言時の値を格納し、ベースオブジェクトには左右されません。
下の例では上と同様、this.nameを出力する関数funcを二通りの方法で呼び出しています。

const func = () => {
    console.log(this.name)
};

const obj = {
    name:"Yujiro",
    func:func
};

// 1.単純に関数として呼び出す
func();    // "{}"

// 2.objのメソッドとして呼び出す
obj.func();    //{}

実際に適当な環境で実行していただければわかるかと思いますが、いずれの呼び出し方法でも空のオブジェクト{}が出力されていることがわかるかと思います。
上述の通り、アロー関数は宣言時のthisを参照するため、1行目で使っているthis(未定義なので空のオブジェクト)が出力されています。

まとめ

今回は関数の宣言方法とそれらの差、アロー関数とそれ以外の宣言方法におけるthisの違いについてまとめました。
一見、thisが動的に変化するfunction構文・式による宣言方法は便利に思えますが、strict modeを使用していないと予想外の値を参照してしまい、想定とは異なる挙動につながりかねません。
同じような用途でも細かい仕様が異なる機能はほかにもあるので、逐次調べつつ、日々精進したいと思います。
ありがとうございました。

参考サイト

57
56
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
57
56

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?