2022年7月2日 JavaScriptの最新仕様ES2022を深ぼる
1. クラスフィールド宣言ができるようになった
そもそもクラスフィールドとは
フィールドはクラスの中でデータの値を保管するために使用するものです。
メリット
- 今までのClass構文ではconstrutor()でフィールドを持たせる必要がありましたが、ES2022からはクラスに直接フィールドを書くことで、インスタンスにフィールドを持たせられるようになりました。
従来のクラスフィールド宣言の場合
class Human { constructor() { this.name = 'yano'; } } const human = new Human(); console.log(human.name); // yano
ES2022のクラスフィールド宣言の場合
class Human { name = 'yano'; } const human = new Human(); console.log(human.name); // yano
実際にブラウザのコンソールで実行すると、期待通りの出力結果が得られました。
従来の書き方とES2022の書き方は共存できるのか気になったので検証してみました
class Human { constructor() { this.name = 'yano'; } name = 'yukiHaga' } const human = new Human(); console.log(human.name); // 'yano'
- この場合は共存することはできずconstructorの中の定義が優先されます。
スタティックなクラスフィールド宣言
class Human { static category = "human" } console.log(Human.category); // human
こちらも従来の書き方とES2022の書き方は共存できるのか気になったので検証してみました
class Human { constructor() { this.name = 'yano'; } static name = 'yukiHaga' } console.log(Human.name); // 'yukihaga' const human = new Human(); console.log(human.name); // 'yano'
- staticなクラスフィールド宣言はconstructorは共存できます。
2. プライベートなフィールドとメソッドが使えるようになった
メリッド
フィールドとメソッドをプライベートにすることで、クラス外からの値の上書きを防ぐことができます。(普通にフィールドとメソッドを定義すると、パブリックとして定義されます。)
#を使ってプライベートなフィールドを宣言する
ES2022でのprivateの宣言は#
を使用します。
class MyClass { // プライベートなフィールド #name; constructor(name) { this.#name = name } hello() { console.log(`こんにちは${this.#name}さん!`) } } const foo = new MyClass("yano"); foo.hello(); // 「こんにちはyanoさん!」と出力される
- 従来は
_
をつける事でprivateな書き換えをしないメソッドだと慣習的に決まっていただけで、ただのルールであり仕様ではありませんでした。 - 今回の
#
を使うことによって、書き換えをしようとするとエラーになるようになり、きちんとした仕様になりました。
エラーを出すコード例
class MyClass { // プライベートなフィールド #name; constructor(name) { this.#name = name } #hello() { console.log(`こんにちは${this.#name}さん!`) } } const foo = new MyClass("田中"); // 以下の行でエラーが発生する foo.#hello = () => console.log('アイウエオ') foo.#hello()
エラー内容
syntaxError: Private field '#hello' must be declared in an enclosing class (プライベートフィールド '#hello' は、包含するクラスで宣言する必要があります。)
#
の付いているhelloメソッドに対して、console.log('アイウエオ')
に書き換えを行なっているのでエラーとなっています。
まとめ
- 従来のJSは慣習でprivateを_をつけることで定義していただけで仕様ではなかったため、全てがpublicでした。
- ES2022からprivateを
#
で定義して、書き換えを行なった際にエラーが出力されるようになった事で、言語の仕様としてprivateを持たせられるようになりました。
クラスフィールドとprivateメソッドは組み合わせられる
class MyClass { // public field foo = "public field: 大部屋"; // private field #bar = "private field: 個室"; // public static field static cafeteria = "public static field: 食堂"; // private static field static #japaneseStyleRestaurant = "private static field: 料亭"; // public method orange() { return console.log("public method: みかん"); } // private method #grape() { return console.log("private method: ぶどう"); } // public static method static staticOrange() { return console.log("public static method: みかん"); } // private static method static #staticGrape() { return console.log("private static method: ぶどう"); } }
- 冒頭で学んだクラスフィールドとpublic privateそれぞれの定義です。
- publicのものは書き換え可能ですが、privateのものは書き換えが不可です。
TypeScriptのprivateとES2022の#
の違い
トランスパイル後の状態が違います。
- TypeScriptのprivateはVSCode上でのコンパイルエラーとしてエラーを出力してくれるので実装上ではprivateが機能しているが、トランスパイル後にJSのコードに変換されたときには、publicなものになっている。
- ES2022の
#
ではトランスパイル後も#
となっており、privateなものとして読み込まれる。
これは、どちらでも問題がないため、チームの方針に従うべきと考えます。