メインコンテンツまでスキップ

従来の関数とアロー関数の違い

JavaScriptの関数は、関数宣言関数式アロー関数の3通りの方法で作れます。

アロー関数は後発

JavaScriptの歴史を紐解くと、元々は関数宣言と関数式しかありませんでした。この2つの機能上の違いはほぼありません。この2つはまとめて「従来の関数」と呼びます。アロー関数は、従来の関数の問題点を解決するために、あとで導入されたものです。

構文の簡潔さ

従来の関数は構文の長さが問題でした。JavaScriptではよくコールバック関数を書きます。コールバック関数とは、関数の引数として渡される関数を言います。従来の関数は、関数を書くたびにfunctionキーワードを書く必要があります。処理が1行だけでも、複数行要するコーディングスタイルもあります。書くのも読むのもわずらわしいコードになりがちです。一方で、アロー関数は短くシンプルな記述になります。

js
// 従来の関数(関数式)
[1, 2, 3].map(function (n) {
return n + 1;
});
// アロー関数
[1, 2, 3].map((n) => n + 1);
js
// 従来の関数(関数式)
[1, 2, 3].map(function (n) {
return n + 1;
});
// アロー関数
[1, 2, 3].map((n) => n + 1);

引き算で再設計されたアロー関数

アロー関数が後発だと聞くと、従来の関数に機能が追加されたものと思われるかもしれません。実は逆です。引き算のアプローチでアロー関数は再設計されました。従来の関数が持つ機能から、関数としては余計な機能を削ったり、複雑な仕様を単純化したりしたものです。そのため、シンプルに「関数らしさ」がより際立つものになっています。どのような機能が間引かれたか見ていきましょう。

コンストラクタ

関数の機能の本質は、入力から計算結果を返すことです。JavaScriptの従来の関数にはこの本質以外に、オブジェクトを生成するコンストラクタの役割も担います。関数をコンストラクタとして扱うにはnew演算子を用います。

js
function Cat(name) {
this.name = name;
}
// Catオブジェクトを生成する
const cat = new Cat("ミケ");
console.log(cat);
Cat { name: 'ミケ' }
js
function Cat(name) {
this.name = name;
}
// Catオブジェクトを生成する
const cat = new Cat("ミケ");
console.log(cat);
Cat { name: 'ミケ' }

関数にコンストラクタ機能がついているのは、一見すると便利そうです。しかし、関数にnew演算子をつけるべきかどうかを、使い手が判断する必要がでてしまいます。それを判断するには、関数の処理内容を読んでみるまで分かりません。コンストラクタとして実行すべき関数を、普通の関数として呼び出ししてまうとバグの原因になりえます。

アロー関数はコンストラクタになれません。もしもJavaScriptでnew演算子を使うと実行エラーになります。誤用の心配がありません。

js
const Cat = (name) => {};
const cat = new Cat("ミケ");
TypeError: Cat is not a constructor
js
const Cat = (name) => {};
const cat = new Cat("ミケ");
TypeError: Cat is not a constructor

TypeScriptでは、従来の関数でもコンストラクタとして使えないようになっています。もし、関数を誤ってnewしたとしても、コンパイルエラーで警告されるので安心です。

ts
function Cat(name: string) {
/* ... */
}
const cat = new Cat("ミケ");
'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.7009'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.
ts
function Cat(name: string) {
/* ... */
}
const cat = new Cat("ミケ");
'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.7009'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.

まとめると、JavaScriptではコンストラクタになれるかどうかは意識する必要がありますが、TypeScriptではコンパイルエラーで気づけるので、JavaScriptほど注意を払う必要はないということになります。

thisの指すもの

従来の関数では、変数thisの指すものが実行時の文脈で決まるという仕様があります。言い換えると、同じ関数であっても、関数の呼び出し方や呼び出される環境によってthisが別のものを参照するようになります。次のthisをコンソールに表示する従来の関数を例に見てみましょう。

js
function showThis() {
console.log(this);
}
js
function showThis() {
console.log(this);
}

このshowThis関数を普通に実行した場合、thisが指すのはグローバルオブジェクトです。グローバルオブジェクトとはブラウザではWindowオブジェクトです。WindowオブジェクトはページのサイズやURL、表示するHTML(DOM)などを操作するAPIを提供するオブジェクトです。

js
showThis();
Window
js
showThis();
Window

JavaScriptにはstrictモードがあります。これは危険な処理ができないよう制約する実行モードです。strictモードを有効にするには"use strict"をコードの冒頭に書きます。strictモードでshowThisを実行すると、thisの値はundefinedになります。

js
"use strict";
showThis();
undefined
js
"use strict";
showThis();
undefined

ちなみにTypeScriptでは、コンパイラオプションalwaysStrictを有効にすると、コンパイル後のJavaScriptがstrictモードになります。

また、JavaScriptにはスクリプトモードとモジュールモードがあります。モジュールモードのJavaScriptでは、exportimportの構文が使えます。このモードでは自動的にstrictモードになります。そのため、モジュールモードでshowThisを実行すると、thisの値はundefinedになります。

js
export {};
showThis();
undefined
js
export {};
showThis();
undefined

関数はオブジェクトのメソッドとして呼び出すこともできます。showThis関数をメソッド呼び出しした場合、thisが指す値はメソッドが紐づくオブジェクトになります。

js
const foo = { name: "Foo" };
// 関数をオブジェクトのメンバーにする
foo.showThis = showThis;
// メソッドとして呼び出す
foo.showThis();
{name: "Foo", showThis: function}
js
const foo = { name: "Foo" };
// 関数をオブジェクトのメンバーにする
foo.showThis = showThis;
// メソッドとして呼び出す
foo.showThis();
{name: "Foo", showThis: function}

従来の関数はコンストラクタとして呼び出せることを説明しましたが、コンストラクタとして呼び出した場合、thisは生成中のオブジェクトを指します。

js
function showThis() {
this.name = "Foo";
console.log(this);
}
new showThis();
{name: "Foo"}
js
function showThis() {
this.name = "Foo";
console.log(this);
}
new showThis();
{name: "Foo"}

上で例示してきたとおり、従来の関数は実行の文脈でthisの内容が動的に決まります。そのため、従来の関数は呼び出し方に注意を払う必要があります。使い方を誤るとバグに繋がる危険性があります。

従来の関数のthisが指すもの
文脈thisの値
通常の呼び出し
showThis()
グローバルオブジェクト(Window)
通常の呼び出し + strictモード
showThis()
undefined
メソッド呼び出し
obj.showThis()
メソッドが属するオブジェクト(obj)
コンストラクタ呼び出し
new showThis()
生成中のオブジェクト

アロー関数のthisはレキシカルスコープで静的です。つまり、定義したときにthisが指すものが決定し、関数の呼び出し方(文脈)に左右されません。thisの値は明瞭です。

たとえば、次のtimerオブジェクトは1秒後にメッセージを表示するstartメソッドを持ちます。startメソッドで1秒後にtimermessageフィールドの値を出力する処理を予約しています。

start関数のthistimerを指します(❶)。1秒経つと、this.messageを出力しようとします。従来の関数は、thisがグローバルオブジェクトのWindowを指すため、undefinedが出力されます(❷)。一方のアロー関数は、thisがレキシカルスコープのthisを指します(❸)。このthistimerです。よって、messageフィールドの値"時間です!"が正常に出力されます。

js
const oneSecond = 1000;
const timer = {
message: "時間です!",
start: function () {
console.log(this); // ❶
 
// 従来の関数
setTimeout(function () {
console.log(this.message); // ❷
}, oneSecond);
 
// アロー関数
setTimeout(() => {
console.log(this.message); // ❸
}, oneSecond);
},
};
timer.start();
js
const oneSecond = 1000;
const timer = {
message: "時間です!",
start: function () {
console.log(this); // ❶
 
// 従来の関数
setTimeout(function () {
console.log(this.message); // ❷
}, oneSecond);
 
// アロー関数
setTimeout(() => {
console.log(this.message); // ❸
}, oneSecond);
},
};
timer.start();

callapplybindの振る舞い

JavaScriptの関数はオブジェクトで、callapplybindの3つのメソッドが生えています。このメソッドは関数を呼び出すものですが、従来の関数では、第一引数にthisが何を指すかを指定できます。

js
function showThis() {
console.log(this);
}
const obj = { name: "foo" };
showThis.bind(obj)(); // objをthisにバインドして、関数呼び出し
{ name: 'foo' }
js
function showThis() {
console.log(this);
}
const obj = { name: "foo" };
showThis.bind(obj)(); // objをthisにバインドして、関数呼び出し
{ name: 'foo' }

アロー関数にも、callapplybindが生えていますが、第一引数に値を渡してもthisは上書きされません。

js
const showThis = () => {
console.log(this);
};
const obj = { name: "foo" };
showThis.bind(obj)();
{}
js
const showThis = () => {
console.log(this);
};
const obj = { name: "foo" };
showThis.bind(obj)();
{}

arguments変数の有無

従来の関数では、argumentsという特殊な変数が自動的に定義されます。この値は引数の配列です。

js
function foo() {
console.log(arguments);
}
foo(1, 2, 3);
[1, 2, 3]
js
function foo() {
console.log(arguments);
}
foo(1, 2, 3);
[1, 2, 3]

argumentsは可変長引数を実現するには便利ですが、関数を実装する多くの場合、利用することのない余計な変数という見方もできます。アロー関数にはargumentsがありません。アロー関数で可変長引数を実現したい場合は、残余引数...を用います。

js
const foo = (...args) => {
console.log(args);
};
foo(1, 2, 3);
[1, 2, 3]
js
const foo = (...args) => {
console.log(args);
};
foo(1, 2, 3);
[1, 2, 3]

ジェネレーター

JavaScriptにはジェネレーターという複数の値を生成できる特殊な関数があります。ジェネレーターは、functionキーワードにアスタリスクをつけ、yield文で生成する値を記述します。

js
function* generateNumbers() {
yield 1;
yield 2;
yield 3;
}
js
function* generateNumbers() {
yield 1;
yield 2;
yield 3;
}

ジェネレーターの値はfor-ofなどの反復処理で取り出せます。

js
for (const value of generateNumbers()) {
console.log(value); // 1、2、3の順で出力される
}
js
for (const value of generateNumbers()) {
console.log(value); // 1、2、3の順で出力される
}

ジェネレーターを定義できるのは従来の関数だけです。アロー関数はそもそもジェネレーター構文をサポートしていないため、ジェネレーターを定義することはできません。

安全性が強化されたアロー関数

アロー関数は、従来の関数にあった危険な仕様が改善されています。

引数名の重複

JavaScriptの従来の関数は、引数名の重複が許されます。引数が重複した場合、最後の引数に渡された値が採用されます。

js
function foo(a, a, a) {
console.log(a);
}
foo(1, 2, 3);
3
js
function foo(a, a, a) {
console.log(a);
}
foo(1, 2, 3);
3

この仕様はバグを引き起こしやすいものですが、従来の関数でもstrictモードにすることで、引数名の重複を構文エラーにできます。

js
"use strict";
function foo(a, a) {}
// ^構文エラー
SyntaxError: Duplicate parameter name not allowed in this context
js
"use strict";
function foo(a, a) {}
// ^構文エラー
SyntaxError: Duplicate parameter name not allowed in this context

アロー関数が導入される際には、こうした危険な仕様が最初から省かれました。アロー関数で引数名が重複した場合、strictモードのオンオフにかかわらず常に構文エラーになります。

js
const foo = (a, a) => {};
// ^構文エラー
SyntaxError: Duplicate parameter name not allowed in this context
js
const foo = (a, a) => {};
// ^構文エラー
SyntaxError: Duplicate parameter name not allowed in this context

TypeScriptでは、従来の関数でも引数名の重複はコンパイルエラーになります。

ts
function foo(a: number, a: number) {}
Duplicate identifier 'a'.
Duplicate identifier 'a'.
2300
2300
Duplicate identifier 'a'.
Duplicate identifier 'a'.
ts
function foo(a: number, a: number) {}
Duplicate identifier 'a'.
Duplicate identifier 'a'.
2300
2300
Duplicate identifier 'a'.
Duplicate identifier 'a'.

そのため、TypeScriptにおいては、従来の関数とアロー関数の間に、そもそも安全面での差はありません。

関数名の重複

JavaScriptでは変数宣言するときにconstletvarのいずれかで行います。varはJavaScriptの初期から存在する宣言方法ですが、constletは2015年に追加されたものです。大きな違いは、constは宣言時にのみ値が代入できる宣言方法で、letは宣言後でも値を変更できる宣言方法です。

constletは、varの問題点を解決するために導入されました。varの問題点のひとつが何度も同じ変数名で変数宣言できる点でした。たとえば、valueという変数がすでに宣言されていたとしても、もう一度var valueで変数宣言しなおすと、特にエラーになることはなく実行できてしまいます。

js
var value = 1;
var value = 2;
console.log(value);
2
js
var value = 1;
var value = 2;
console.log(value);
2

この仕様は、意図しない変数の上書きに気づきにくく、不具合の要因になることがしばしばあります。constletは変数名が重複している場合は、エラーになります。つまり、varよりも安全なコーディングが行えます。

js
let value = 1;
Cannot redeclare block-scoped variable 'value'.2451Cannot redeclare block-scoped variable 'value'.
let value = 2; // 構文エラー
Cannot redeclare block-scoped variable 'value'.2451Cannot redeclare block-scoped variable 'value'.
js
let value = 1;
Cannot redeclare block-scoped variable 'value'.2451Cannot redeclare block-scoped variable 'value'.
let value = 2; // 構文エラー
Cannot redeclare block-scoped variable 'value'.2451Cannot redeclare block-scoped variable 'value'.

関数宣言で作った関数はvarに相当します。そのため、重複した関数名で関数が作れてしまいます。

js
function foo() {
console.log("1つ目の関数");
}
function foo() {
console.log("2つ目の関数");
}
foo();
"2つ目の関数"
js
function foo() {
console.log("1つ目の関数");
}
function foo() {
console.log("2つ目の関数");
}
foo();
"2つ目の関数"

アロー関数は、変数宣言と同じ構文で作るため、varを避けてletまたはconstを使うコーディングをしている限り、関数名の重複が起こりえません。

js
const foo = () => {};
Cannot redeclare block-scoped variable 'foo'.2451Cannot redeclare block-scoped variable 'foo'.
const foo = () => {};
Cannot redeclare block-scoped variable 'foo'.2451Cannot redeclare block-scoped variable 'foo'.
js
const foo = () => {};
Cannot redeclare block-scoped variable 'foo'.2451Cannot redeclare block-scoped variable 'foo'.
const foo = () => {};
Cannot redeclare block-scoped variable 'foo'.2451Cannot redeclare block-scoped variable 'foo'.

もちろん、アロー関数でもvarを用いて関数を作った場合は、関数名が重複できてしまいます。しかし、最近のJavaScriptのベストプラクティスでは、varを使わないことが推奨されています。そのため、関数宣言と比べて、アロー関数のほうがずっと関数名重複のミスを低減できる状況が多いです。

TypeScriptでは、関数宣言でも重複した関数名がコンパイルエラーになります。

ts
function foo() {}
Duplicate function implementation.2393Duplicate function implementation.
function foo() {}
Duplicate function implementation.2393Duplicate function implementation.
ts
function foo() {}
Duplicate function implementation.2393Duplicate function implementation.
function foo() {}
Duplicate function implementation.2393Duplicate function implementation.

したがって、関数名の重複問題に関しては、TypeScriptでは安全性の差がありません。

巻き上げと関数定義と呼び出しの順序

関数宣言とアロー関数では巻き上げ(hoisting)が起こるか否かの違いがあります。巻き上げとは、変数が宣言される前のコードで、その変数を参照できる仕様です。

巻き上げとは、変数スコープの途中で宣言された変数が、変数スコープの冒頭に変数宣言を自動的に持ってくる仕様です。巻き上げられた変数はundefinedで初期化された状態になります。次の例では、valueの変数宣言よりも先に、変数valueを参照していますが、これはエラーにならずundefinedが出力されます。

js
console.log(value);
undefined
var value = 1;
js
console.log(value);
undefined
var value = 1;

これは変数valueに巻き上げが起こり、console.log(value)よりも手前でvalueの変数宣言がなされるためです。上のコードは、実質的に次のコードと同じ意味になります。

js
var value;
console.log(value);
value = 1;
js
var value;
console.log(value);
value = 1;

関数宣言でも類似の巻き上げが起こります。varの巻き上げと異なる点は、関数はundefinedで初期化されるのではなく、関数の実装も合わせて巻き上げられる点です。そのため、関数宣言よりも手前で関数呼び出しが行えます。

js
foo();
実行しました
function foo() {
console.log("実行しました");
}
js
foo();
実行しました
function foo() {
console.log("実行しました");
}

コードに書かれた順序が、関数呼び出し、関数宣言の順になるだけで、関数の巻き上げには問題点はありません。

学びをシェアする

JavaScriptのアロー関数の特徴

・構文が短い
・thisがレキシカルスコープ
・コンストラクタになれない
・ジェネレータになれない
・引数の重複が起こらない
・関数の宣言重複が起きにくい
・巻き上げが起きにくい

『サバイバルTypeScript』より

この内容をXにポストする

従来の関数とアロー関数の使い分け

上では、従来の関数(関数宣言と関数式)とアロー関数の機能上の違いを見てきました。違いを踏まえた上で、この2つはどちらを使ったほうがよいのでしょうか。もしどちらも使う場合、どのような基準で使い分けたらよいのでしょうか。

従来の関数を使うべきか、アロー関数を使うべきかは、意見が分かれるところです。アロー関数は従来の関数の問題点を解決した新しい機能であるため、できるだけアロー関数を使うべきという考えの人もいます。一方で、関数宣言とアロー関数は適度に使い分けるべきという意見の人もいます。アロー関数よりも関数宣言を積極的に使うべきと考える人もいるでしょう。どこでアロー関数を使い、どこで従来の関数を使うか。こうした基準は議論が尽きないところです。どのような判断基準が正しいと断言できるものではありません。

それでも、従来の関数とアロー関数の使い分け方は、個人やチームといったひとつのソースコードを共有する範囲では、一貫した決まりで使い分けることが重要です。ここからは、自分なりの使い分けを考えられるようになるために、判断材料の手がかりを示したいと思います。ここで提示することが普遍的に正しいとは限りません。読んだ上で自分なりの使い分け方を考えてみてください。

特に理由がない場合、アロー関数を使うほうが無難です。なぜかと言うと、アロー関数は関数としての最低限の機能をもったシンプルな関数だからです。上で見たように、従来の関数にはコンストラクタやthisの動的な解釈などさまざまな機能があり、それらの機能を使わない場合は余計な機能になります。機能が多い分、コーディング時に考慮しないといけないことが増えます。アロー関数はミニマムな機能に抑えられているので、細かいことを気にせず書ける利点があります。

アロー関数が特に相性がいいところはコールバック関数です。たとえば、配列オブジェクトのArrayには、各要素に対して処理をかけるメソッドがいくつかあります。これらのメソッドは引数に関数を渡す必要があります。次の例は、数値の配列に対してfilterメソッドを用い、偶数だけを抽出するコードです。このコードでは関数式をコールバック関数に渡しています。

js
const nums = [1, 2, 3, 4];
const even = nums.filter(function (n) {
return n % 2 === 0;
});
console.log(even);
[2, 4]
js
const nums = [1, 2, 3, 4];
const even = nums.filter(function (n) {
return n % 2 === 0;
});
console.log(even);
[2, 4]

これをアロー関数に置き換えると、次のようにシンプルな記述になります。

js
const nums = [1, 2, 3, 4];
const even = nums.filter((n) => n % 2 === 0);
console.log(even);
[2, 4]
js
const nums = [1, 2, 3, 4];
const even = nums.filter((n) => n % 2 === 0);
console.log(even);
[2, 4]

こうしたコールバック関数ではアロー関数を積極的に使うことで、コードの記述量が減ったり、コードが意図する処理が目立つといったメリットが出てきます。

従来の関数も出番がないわけではありません。HTMLのボタンがクリックされたときに何らかの処理をしたい場合、addEventListenerメソッドを使います。任意の処理をコールバック関数としてこのメソッドに渡すことで、好きな処理が行なえます。

js
button.addEventListener("click", コールバック関数);
js
button.addEventListener("click", コールバック関数);

処理の中でクリックされたボタンを参照する場合、渡す関数が従来の関数なら変数thisでボタンを参照できます。下の例では、クリックした「保存」ボタンの表示を「保存中…」に変えるコードです。this.innerTextでボタン表示を変更しています。このようなthisの使い方をしたい場合はアロー関数では書くことができません。

html
<button id="save">保存</button>
<script>
const button = document.getElementById("save");
button.addEventListener("click", function () {
this.innerText = "保存中…";
});
</script>
html
<button id="save">保存</button>
<script>
const button = document.getElementById("save");
button.addEventListener("click", function () {
this.innerText = "保存中…";
});
</script>

上の場合でも、buttonを参照すればアロー関数も使えます。なので、従来の関数でなければならない決定打ではありません。

html
<button id="save">保存</button>
<script>
const button = document.getElementById("save");
button.addEventListener("click", () => {
button.innerText = "保存中…";
// ^^^buttonを参照
});
</script>
html
<button id="save">保存</button>
<script>
const button = document.getElementById("save");
button.addEventListener("click", () => {
button.innerText = "保存中…";
// ^^^buttonを参照
});
</script>

オブジェクトのメソッドとして関数を作る場合は、従来の関数を選ぶ理由になります。thisでオブジェクトを参照できるからです。たとえば、次の例fullName1メソッドのように、メソッドでオブジェクトのプロパティを用いる場合、thisで参照するのが便利です。

js
const taroYamada = {
firstName: "Taro",
lastName: "Yamada",
// 従来の関数
fullName1: function () {
return this.firstName + " " + this.lastName;
},
// アロー関数
fullName2: () => {
return this.firstName + " " + this.lastName;
},
};
console.log(taroYamada.fullName1());
"Taro Yamada"
console.log(taroYamada.fullName2());
undefined undefined
js
const taroYamada = {
firstName: "Taro",
lastName: "Yamada",
// 従来の関数
fullName1: function () {
return this.firstName + " " + this.lastName;
},
// アロー関数
fullName2: () => {
return this.firstName + " " + this.lastName;
},
};
console.log(taroYamada.fullName1());
"Taro Yamada"
console.log(taroYamada.fullName2());
undefined undefined

アロー関数を用いたfullName2thisがオブジェクトを指さないため、期待どおりの動作になりません。もし、アロー関数を使う場合は、thisではなくtaroYamada.firstNameのようにオブジェクトの変数名を参照する必要があります。

js
const taroYamada = {
firstName: "Taro",
lastName: "Yamada",
fullName: () => {
return taroYamada.firstName + " " + taroYamada.lastName;
},
};
console.log(taroYamada.fullName());
"Taro Yamada"
js
const taroYamada = {
firstName: "Taro",
lastName: "Yamada",
fullName: () => {
return taroYamada.firstName + " " + taroYamada.lastName;
},
};
console.log(taroYamada.fullName());
"Taro Yamada"

従来の関数には巻き上げがあるおかげで、理解しやすいコードになる場合もあります。たとえば、プログラムを処理過程ごとに関数でグルーピングし、プログラムの冒頭で関数呼び出しを羅列することで、そのプログラムの処理の概要が読み始めのところでわかりやすくなることがあります。

js
// プログラムの概要
step1();
step2();
step3();
 
// 各処理の詳細
function step1() {
/* 処理の詳細 */
}
function step2() {
/* 処理の詳細 */
}
function step3() {
/* 処理の詳細 */
}
js
// プログラムの概要
step1();
step2();
step3();
 
// 各処理の詳細
function step1() {
/* 処理の詳細 */
}
function step2() {
/* 処理の詳細 */
}
function step3() {
/* 処理の詳細 */
}

アロー関数は、constletvarで作る必要があるため、関数の巻き上げが起こりません。そのため、上のサンプルコードのように先に処理の概要を示すようなパターンはそのまま書くことができません。

js
step1();
ReferenceError: Cannot access 'step1' before initialization
step2();
step3();
const step1 = () => {};
const step2 = () => {};
const step3 = () => {};
js
step1();
ReferenceError: Cannot access 'step1' before initialization
step2();
step3();
const step1 = () => {};
const step2 = () => {};
const step3 = () => {};

もし上の書き方と近い表現をアロー関数で行う場合、処理の概要を書いた関数を定義し、その関数をプログラムの最後で呼び出す書き方になります。

js
const main = () => {
step1();
step2();
step3();
};
const step1 = () => {};
const step2 = () => {};
const step3 = () => {};
main();
js
const main = () => {
step1();
step2();
step3();
};
const step1 = () => {};
const step2 = () => {};
const step3 = () => {};
main();

関数が関数であることを目立たせたい場合に、関数宣言を使うという選択もあります。アロー関数は、変数宣言と同じ書き方で書くので、それが値なのか関数なのかがひと目では分かりにくいと感じる人も中にはいます。変数宣言の間に、アロー関数と関数宣言がある次の例を見比べてください。どちらがぱっと見て関数であると分かりやすいでしょうか。

js
// 変数宣言の間にあるアロー関数
const str = "foo";
const obj = { value: str };
const func = (n) => n + 1;
const nums = [1, 2, 3];
js
// 変数宣言の間にあるアロー関数
const str = "foo";
const obj = { value: str };
const func = (n) => n + 1;
const nums = [1, 2, 3];
js
// 変数宣言の間にある関数宣言
const str = "foo";
const obj = { value: str };
function func(n) {
return n + 1;
}
const nums = [1, 2, 3];
js
// 変数宣言の間にある関数宣言
const str = "foo";
const obj = { value: str };
function func(n) {
return n + 1;
}
const nums = [1, 2, 3];