この記事で分かること
- 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を使用していないと予想外の値を参照してしまい、想定とは異なる挙動につながりかねません。
同じような用途でも細かい仕様が異なる機能はほかにもあるので、逐次調べつつ、日々精進したいと思います。
ありがとうございました。