6時だョ!!全員集合!!

Rails・JavaScrictを中心にアウトプットします。

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
  • 従来ならばnew演算子を使用してインスタンス化しないとアクセスできなかったのに対して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なものとして読み込まれる。

これは、どちらでも問題がないため、チームの方針に従うべきと考えます。

参考

https://zenn.dev/tonkotsuboy_com/articles/es2022-whats-new