Kodokon kodokon.com

this、プロトタイプ、クラス

this が動的にどう解決されるか、プロトタイプチェーンがどう機能するか、そしてクラスがオブジェクトモデルに実際に何を加えるのかを理解しましょう。

10 分 · 3 問

このレッスンを Kodokon で開く

this の値は宣言時ではなく 呼び出し箇所 で決まります。優先度の高い順に4つのルールがあります。new を使った呼び出し、明示的な束縛(callapplybind)、メソッドとしての呼び出し(obj.fn())、そして単なる呼び出し(fn())で、これは strict モードでは undefined になります。実務で最もよくあるバグはここから直接生じます。メソッドをそのオブジェクトから取り出すと、暗黙の束縛が壊れるのです。

JAVASCRIPT
const user = {
  name: "Ada",
  greet() {
    return "Hello, " + this.name;
  },
};
console.log(user.greet()); // "Hello, Ada"
const detached = user.greet;
// detached(); // TypeError: this is undefined
const bound = user.greet.bind(user);
console.log(bound()); // "Hello, Ada"
メソッドが取り出された瞬間に、暗黙の束縛は消え去ります。

アロー関数は自分自身の this を持ちません。クロージャと同じように、それを囲むスコープから レキシカルに this を捕捉します。そのため、コールバックには理想的ですが、オブジェクトリテラルのメソッドとしては逆効果です。その場合 this は外側のスコープを指してしまいます。内部では、すべてのオブジェクトは自身の プロトタイプチェーン を通じて委譲します。存在しないプロパティは、null に到達するまでリンクをたどって1つずつ探索されます。

JAVASCRIPT
function Animal(name) {
  this.name = name;
}
Animal.prototype.describe = function () {
  return this.name + " is an animal";
};
const dog = new Animal("Rex");
console.log(dog.describe()); // "Rex is an animal"
console.log(Object.getPrototypeOf(dog) ===
  Animal.prototype); // true
console.log(dog.hasOwnProperty("describe")); // false
describe はプロトタイプ上に存在し、すべてのインスタンスで共有されます。

class 構文はこのモデルを変えるものではなく、読みやすくするものです。クラス本体で宣言されたメソッドは Constructor.prototype に置かれるため 共有 されます。インスタンスフィールド(フィールドとして代入されたアロー関数を含む)は インスタンスごとに 作り直されます。this の束縛は保証されますが、その分メモリコストは倍増します。最後に、#private フィールドは、_underscore の慣習とは違い、エンジンによって強制されるプライバシーを提供します。

JAVASCRIPT
class BankAccount {
  #balance = 0;
  deposit(amount) {
    if (amount <= 0) throw new Error("Invalid amount");
    this.#balance += amount;
    return this;
  }
  get balance() {
    return this.#balance;
  }
}
const account = new BankAccount();
account.deposit(50).deposit(25);
console.log(account.balance); // 75
エンジンが強制するプライベートフィールドと、チェーン可能な API。

理解度チェック

このレッスンの要点をしっかり覚えているか確認しましょう。

  1. strict モードで、オブジェクトも明示的な束縛もない単なる呼び出し fn() の間、this は何ですか?
    • globalThis
    • undefined
    • fn が宣言されたオブジェクト
    • null
  2. クラス本体で宣言されたメソッド(フィールドを除く)はどこに格納されますか?
    • 各インスタンス上に、構築時にコピーされる
    • Constructor.prototype 上に、すべてのインスタンスで共有される
    • アクセスできない内部スコープの中に
  3. this に関して、アロー関数の特別な点は何ですか?
    • メソッドのように、呼び出しているオブジェクトに this を束縛する
    • 自身の this を持たず、それを囲むスコープの this を捕捉する
    • 常に this を globalThis に束縛する
    • this へのあらゆるアクセスを禁止する