JavaScriptの基礎をもう一度おさらいしたい【this/クロージャ編】

に公開

JavaScript復習記事(this・クロージャ編)

以前はUdemyを中心に受講していたのですが、学んだきり仕事でも使うことがなく1,2年経過していました...

復習として、後から見返せるように記事として残してみたいと思います。

何編かに分けたいと思いますが、今回はthisとクロージャ編です。

以前私が受講したUdemy講座はこちらです。

以下MDNを参考にして進めていきます
https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide

this

thisは実行環境によって指すものが変わります。基本的には呼び出し方によって決まるという認識でよいかと思います。

通常の関数・メソッド呼び出し

// オブジェクトのメソッドとして呼び出し
const person = {
  name: "Jon",
  hello() {
    console.log(this); // personオブジェクト
    console.log(`Hello, ${this.name}`);
  },
};
person.hello(); // thisはpersonオブジェクト

// クラスのメソッド
class User {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  hello() {
    console.log(this); // Userインスタンス
    console.log(`Hello, ${this.name}`);
  }
}
const user1 = new User("Bob", 20);
user1.hello(); // thisはuser1インスタンス

アロー関数のthis

アロー関数は自分のthisを持たず、定義された場所のthisを引き継ぎます(レキシカルスコープ)。

const person2 = {
  name: "Alice",
  // アロー関数をメソッドにするとthisがwindowになる
  hello: () => {
    console.log(this); // window(またはundefined in strict mode)
    console.log(`Hello, ${this.name}`); // undefined
  },
  
  // 通常メソッド内でアロー関数を使う場合
  greet() {
    console.log("outer this外側だよ:", this.name); // "Alice"
    
    const inner = () => {
      console.log("内側だよ:", this.name); // "Alice" (外側のthisを引き継ぐ)
    };
    inner();
  }
};

### よくある間違いとその対策

```javascript
const obj = {
  name: "David",
  getName() {
    return this.name;
  }
};

// メソッドを変数に代入するとthisが失われる
const getNameFunc = obj.getName;
console.log(getNameFunc()); // undefined

// bindで修正
const boundGetName = obj.getName.bind(obj);
console.log(boundGetName()); // "David"

クロージャ

あまり意識して書くことはないようですが、ライブラリやReact内部などでも使われているようです。

クロージャって?

関数が外側のスコープにアクセスできるやつっていう認識でいました。

実際は:

クロージャは、組み合わされた(囲まれた)関数と、その周囲の状態(レキシカル環境)への参照の組み合わせです。言い換えれば、クロージャは関数にその外側のスコープにアクセスする機能を提供します。JavaScript では、クロージャは関数が作成されるたびに、関数作成時点で作成されます。

とのことです。基本的にはあってそうです。

基本的なクロージャの例

function counterFn() {
  let count = 0; // 外側の変数
  
  function countFactory() {
    count++; // 外側の変数にアクセス
    return count; 
  }
  
  return countFactory; // 内側の関数を返す
}

const counter = counterFn();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3

// 別のカウンターを作成
const counter2 = counterFn();
console.log(counter2()); // 1 (独立している)

ちなみにlet count = 0;constだと動きません。
constが再代入不可としているためです。

React hooksとクロージャ

React の useState も内部的にクロージャを使っています

// useState の簡略化された実装イメージ
function useState(initial) {
  let state = initial; // クロージャで保持される
  
  const setState = (newState) => {
    state = newState;
    // 再レンダリング処理...
  };
  
  return [state, setState];
}

参考資料

まとめ

  • thisは呼び出し方によって決まる
  • アロー関数は定義された場所のthisを引き継ぐ
  • クロージャは関数が外側のスコープにアクセスできる仕組み

次回は配列メソッドやPromiseについて復習予定です。

Discussion