読み込み中...

スコープ内でのthisの扱い方10選を実践的に解説!

JavaScriptにおけるthisキーワードの使い方 JS
この記事は約15分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

本記事のサンプルコードを活用して機能追加、目的を達成できるように作ってありますので、是非ご活用ください。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を満たす現役のプログラマチームによって監修されています。

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

●JavaScriptのthisとは?

JavaScriptを学ぶ上で避けては通れないのが、thisキーワードの理解です。

thisは一見シンプルな概念に見えますが、スコープによって値が変化するため、初心者にとってはわかりにくい部分があります。

○thisの基本概念

JavaScriptにおけるthisは、現在実行中のコードが属するオブジェクトを指します。

つまり、thisは呼び出し元のオブジェクトを参照するために使用されます。

しかし、thisの値は呼び出し方によって異なるため、コンテキストを理解することが重要です。

○グローバルスコープとローカルスコープ

JavaScriptにはグローバルスコープとローカルスコープがあります。

グローバルスコープはプログラム全体で利用可能な領域であり、ローカルスコープは関数内など限定された領域を指します。

thisはスコープによって参照するオブジェクトが変わってくるので、スコープの概念を理解しておく必要があります。

○サンプルコード1:スコープとthis

グローバルスコープとローカルスコープでのthisの違いを見てみましょう。

// グローバルスコープ
console.log(this); // Window(ブラウザの場合)

function myFunction() {
  // 関数内のローカルスコープ
  console.log(this); // Window(ブラウザの場合)
}

myFunction();

実行結果

Window {...}
Window {...}

このサンプルコードでは、グローバルスコープと関数内のローカルスコープでthisを出力しています。

どちらの場合もWindowオブジェクト(ブラウザの場合)を参照していることがわかります。

ただし、これはデフォルトの動作です。

strictモードを使用したり、オブジェクトのメソッドとして関数を呼び出したりすると、thisの参照先が変わります。

●メソッド内でのthisの使用

JavaScriptでオブジェクト指向プログラミングを行う際、メソッド内でのthisの扱いは非常に重要です。

メソッドは、オブジェクトに属する関数のことを指します。

thisを使うことで、メソッド内からオブジェクトのプロパティやメソッドにアクセスすることができます。

○オブジェクトのメソッドとthis

オブジェクトのメソッドを呼び出す際、thisはそのオブジェクト自身を参照します。

これにより、メソッド内でオブジェクトのプロパティを操作したり、他のメソッドを呼び出したりすることが可能になります。

○サンプルコード2:メソッド内のthis

メソッド内でthisを使用した例を見てみましょう。

const person = {
  name: '太郎',
  greet: function() {
    console.log('こんにちは、' + this.name + 'です。');
  }
};

person.greet();

実行結果

こんにちは、太郎です。

このサンプルコードでは、personオブジェクトにnameプロパティとgreetメソッドを定義しています。

greetメソッド内でthis.nameを使用することで、オブジェクトのnameプロパティにアクセスしています。

○コンストラクタ関数とthis

コンストラクタ関数は、新しいオブジェクトを作成するための特殊な関数です。

コンストラクタ関数内でthisを使用すると、新しく作成されるオブジェクトを参照することができます。

これにより、オブジェクトのプロパティを初期化したり、メソッドを追加したりすることが可能になります。

○サンプルコード3:コンストラクタ関数のthis

コンストラクタ関数内でthisを使用した例を見てみましょう。

function Person(name, age) {
  this.name = name;
  this.age = age;
  this.greet = function() {
    console.log('こんにちは、' + this.name + 'です。' + this.age + '歳です。');
  };
}

const taro = new Person('太郎', 20);
taro.greet();

実行結果

こんにちは、太郎です。20歳です。

このサンプルコードでは、Personコンストラクタ関数を定義しています。

関数内でthisを使用して、新しく作成されるオブジェクトのプロパティ(name、age)を設定し、greetメソッドを追加しています。

newキーワードを使ってPersonオブジェクトを作成し、greetメソッドを呼び出すと、オブジェクトのプロパティを使用した挨拶文が出力されます。

●アロー関数とthis

ES2015(ES6)で導入されたアロー関数は、JavaScriptでの関数定義を簡潔に記述できる便利な構文です。

アロー関数にはいくつかの特徴があり、特にthisの扱いに関しては通常の関数とは異なる動作をします。

○アロー関数の特徴と利点

アロー関数は、functionキーワードを省略し、”=>”を使用して関数を定義します。

シンプルな構文で関数を記述できるため、コードの可読性が向上します。

また、アロー関数は自動的にthisをバインドするため、コールバック関数などで使用する際に便利です。

○サンプルコード4:通常の関数とthis

まずは、通常の関数におけるthisの動作を確認してみましょう。

const obj = {
  name: '太郎',
  greet: function() {
    setTimeout(function() {
      console.log('こんにちは、' + this.name);
    }, 1000);
  }
};

obj.greet();

実行結果

こんにちは、undefined

このサンプルコードでは、objオブジェクトのgreetメソッド内でsetTimeout関数を使用しています。

しかし、setTimeoutのコールバック関数内でthis.nameを参照すると、undefinedが出力されます。

これは、コールバック関数内のthisがグローバルオブジェクトを参照しているためです。

○サンプルコード5:アロー関数とthis

では、アロー関数を使用した場合はどうでしょうか。

const obj = {
  name: '太郎',
  greet: function() {
    setTimeout(() => {
      console.log('こんにちは、' + this.name);
    }, 1000);
  }
};

obj.greet();

実行結果

こんにちは、太郎

このサンプルコードでは、setTimeoutのコールバック関数をアロー関数に変更しました。

すると、期待通りにオブジェクトのnameプロパティが出力されます。

アロー関数は、定義された場所のthisを継承するため、greetメソッド内のthisを参照することができるのです。

○アロー関数の注意点

アロー関数は便利な機能ですが、注意点もあります。

アロー関数は自身のthisを持たないため、コンストラクタ関数として使用することができません。

また、アロー関数内ではargumentsオブジェクトも利用できません。

状況に応じて、通常の関数とアロー関数を使い分ける必要があります。

アロー関数を使いこなすことで、JavaScriptのコードをより簡潔に記述できます。

特にコールバック関数で使用する際には、アロー関数が力を発揮します。

ただし、アロー関数特有の動作を理解し、適切に使用することが大切です。

●ラムダ式とthis

JavaScriptにはラムダ式という概念があります。

ラムダ式は、関数型プログラミングの世界では重要な役割を果たしています。

JavaScriptでは、ラムダ式を使ってコードをよりシンプルに記述することができます。

○ラムダ式の基本構文

ラムダ式の基本構文は、アロー関数と似ています。

引数と”=>”の後に式を記述します。

ラムダ式は、関数を定義する際に使用されることが多いですね。

○サンプルコード6:ラムダ式の例

ラムダ式を使った簡単な例を見てみましょう。

const add = (a, b) => a + b;

console.log(add(2, 3));

実行結果

5

このサンプルコードでは、addという変数にラムダ式を代入しています。

ラムダ式は2つの引数a、bを受け取り、それらを足し合わせた値を返します。

add(2, 3)を呼び出すと、2と3が足し合わされて5が出力されます。

○ラムダ式とthisの関係

ラムダ式を使う際に、thisの扱いに注意が必要です。

ラムダ式内でthisを使用すると、予期しない動作をすることがありす。

○サンプルコード7:ラムダ式内のthis

ラムダ式内でthisを使用した例を見てみましょう。

const obj = {
  name: '太郎',
  greet: function() {
    const sayHello = () => {
      console.log('こんにちは、' + this.name);
    };
    sayHello();
  }
};

obj.greet();

実行結果

こんにちは、太郎

このサンプルコードでは、objオブジェクトのgreetメソッド内でラムダ式を定義しています。

ラムダ式内でthis.nameを参照すると、期待通りにオブジェクトのnameプロパティが出力されます。

ラムダ式は、その外側のスコープのthisを継承するためです。

●よくあるエラーと対処法

JavaScriptでthisを使っていると、時々奇妙なエラーに遭遇することがあります。

特に、オブジェクトのメソッドやコールバック関数内でthisを使用する際に、予期しない動作に頭を悩ませたことがある人も多いのではないでしょうか。

○”TypeError: Cannot read property”エラー

よくあるエラーの1つが、”TypeError: Cannot read property”というエラーメッセージです。

このエラーは、オブジェクトのプロパティにアクセスしようとしたときに、そのオブジェクトがundefinedやnullであることを表しています。

const obj = {
  name: '太郎',
  greet: function() {
    console.log('こんにちは、' + this.name);
  }
};

const greetFunc = obj.greet;
greetFunc();

実行結果

TypeError: Cannot read property 'name' of undefined

このサンプルコードでは、objオブジェクトのgreetメソッドを別の変数greetFuncに代入しています。

しかし、greetFunc()を呼び出すと、”TypeError: Cannot read property ‘name’ of undefined”というエラーが発生します。

これは、greetFunc()の呼び出し時にthisがundefinedになっているためです。

○”this is undefined”エラー

もう1つのよくあるエラーが、”this is undefined”というエラーメッセージです。

このエラーは、期待したオブジェクトではなく、undefinedがthisに割り当てられていることを表しています。

const obj = {
  name: '太郎',
  greet: function() {
    function sayHello() {
      console.log('こんにちは、' + this.name);
    }
    sayHello();
  }
};

obj.greet();

実行結果

こんにちは、undefined

このサンプルコードでは、objオブジェクトのgreetメソッド内で、sayHello関数を定義しています。

sayHello()を呼び出すと、”こんにちは、undefined”と出力されます。

これは、sayHello()内のthisがグローバルオブジェクトを参照しているためです。

○アロー関数とthisのバインディング問題

アロー関数を使用する際にも、thisのバインディングに関する問題が発生することがあります。

アロー関数は、定義された場所のthisを継承するため、意図しない動作をすることがあるのです。

const obj = {
  name: '太郎',
  greet: () => {
    console.log('こんにちは、' + this.name);
  }
};

obj.greet();

実行結果

こんにちは、undefined

このサンプルコードでは、objオブジェクトのgreetメソッドをアロー関数で定義しています。

obj.greet()を呼び出すと、”こんにちは、undefined”と出力されます。

これは、アロー関数内のthisがグローバルオブジェクトを参照しているためです。

●thisを使った実用的なテクニック

JavaScriptでthisを使いこなすと、より洗練されたコードを書くことができます。

ここでは、thisを活用した実用的なテクニックをいくつか紹介しましょう。

このテクニックを身につけることで、JavaScriptでのコーディングスキルを向上させることができます。

○サンプルコード8:メソッドチェーン

メソッドチェーンは、オブジェクトのメソッドを連続して呼び出すテクニックです。

thisを使うことで、メソッドチェーンを実現することができます。

const calculator = {
  result: 0,
  add: function(num) {
    this.result += num;
    return this;
  },
  subtract: function(num) {
    this.result -= num;
    return this;
  },
  multiply: function(num) {
    this.result *= num;
    return this;
  },
  getResult: function() {
    return this.result;
  }
};

const finalResult = calculator.add(5).subtract(2).multiply(3).getResult();
console.log(finalResult);

実行結果

9

このサンプルコードでは、calculatorオブジェクトに複数のメソッドを定義しています。

各メソッドは、計算を行った後にthisを返しています。

これにより、メソッドを連続して呼び出すことができます。

最後にgetResult()メソッドを呼び出すことで、計算結果を取得しています。

○サンプルコード9:コールバック関数とthis

コールバック関数内でthisを使用する場合、thisのバインディングに注意が必要です。

bind()メソッドを使うことで、コールバック関数内でthisを適切に参照することができます。

const person = {
  name: '太郎',
  greet: function() {
    setTimeout(function() {
      console.log('こんにちは、' + this.name);
    }.bind(this), 1000);
  }
};

person.greet();

実行結果

こんにちは、太郎

このサンプルコードでは、personオブジェクトのgreetメソッド内でsetTimeout関数を使用しています。

コールバック関数内でthis.nameを参照するために、bind(this)を使ってコールバック関数のthisをpersonオブジェクトにバインドしています。

○サンプルコード10:thisを使った設計パターン

thisを活用することで、JavaScriptでさまざまな設計パターンを実装することができます。

例えば、シングルトンパターンを実装する際にthisを使うことができます。

const singleton = {
  instance: null,
  getInstance: function() {
    if (!this.instance) {
      this.instance = {
        name: 'シングルトンオブジェクト',
        // その他のプロパティやメソッド
      };
    }
    return this.instance;
  }
};

const instance1 = singleton.getInstance();
const instance2 = singleton.getInstance();
console.log(instance1 === instance2);

実行結果

true

このサンプルコードでは、singletonオブジェクトにgetInstanceメソッドを定義しています。

getInstanceメソッドは、this.instanceプロパティをチェックし、インスタンスがない場合は新しいインスタンスを作成します。

これにより、常に同じインスタンスが返されるようになります。

○thisを使いこなすためのヒント

thisを使いこなすためには、次のようなヒントを意識するとよいでしょう。

  • thisが参照するオブジェクトを常に意識する
  • メソッドやコールバック関数内でthisを使用する場合は、thisのバインディングに注意する
  • 必要に応じて、bind()やcall()、apply()を使ってthisを明示的にバインドする
  • アロー関数とthisの動作の違いを理解する
  • 設計パターンを実装する際には、thisを活用することを検討する

thisを使った実用的なテクニックを身につけることで、JavaScriptでのコーディングの幅が広がります。

メソッドチェーンやコールバック関数、設計パターンなどで、thisを効果的に活用することができます。

ただし、thisの動作を正しく理解し、適切に使用することが重要です。

まとめ

JavaScriptのthisは、コンテキストによって参照先が変化する特殊なキーワードです。

JavaScriptでthisを使いこなすことで、より洗練されたコードを書くことができます。

継続的に学習し、実践を積むことで、thisを使ったベストプラクティスを身につけましょう。

今回学んだ知識を活かして、JavaScriptでのコーディングスキルを向上させていってください。