← Back

【JavaScript】プログラミング初心者が抑えておくべきthisの挙動と使い方

2023年2月20日eyecatch

JavaScriptのthisは、JavaScriptプログラミングにおいて非常に重要な概念の1つです。

thisは、コンテキストに応じて変化する特殊なキーワードであり、関数内部で呼び出されると、その関数を呼び出すオブジェクトを参照することができます。

この記事では、thisの挙動、使用方法、およびthisの一般的な問題、callapplybind メソッドについて詳しく説明します。

thisの挙動

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

thisの値は、関数がどのように呼び出されたかによって決定されます。

具体的には、以下の4つのパターンがあります。

グローバルコンテキスト

thisがグローバルコンテキストで呼び出された場合、thisはグローバルオブジェクトを参照します。

ブラウザでは、windowオブジェクトがグローバルオブジェクトです。

Node.jsでは、globalオブジェクトがグローバルオブジェクトです。

console.log(this === window); // ブラウザ環境でtrueを返す
console.log(this === global); // Node.js環境でtrueを返す


関数呼び出し

thisが関数内で呼び出され、関数がオブジェクトのプロパティである場合、thisはそのオブジェクトを参照します。

これをメソッド呼び出しと呼びます。

const person = {
  name: 'john',
  sayHello() {
    console.log(`Hello, my name is ${this.name}`);
  }
};

person.sayHello(); // "Hello, my name is john"と出力される


callおよびapplyメソッドによる呼び出し

thiscallまたはapplyメソッドで呼び出された場合、thisはメソッドの第1引数に渡されたオブジェクトを参照します。

これを明示的なバインディングと呼びます。

function sayHello() {
  console.log(`Hello, my name is ${this.name}`);
}

const person1 = { name: 'John' };
const person2 = { name: 'Alice' };

sayHello.call(person1); // "Hello, my name is John"と出力される
sayHello.call(person2); // "Hello, my name is Alice"と出力される


newキーワードによる呼び出し

thisがnewキーワードで呼び出された場合、thisは新しいオブジェクトを参照します。

これをコンストラクタ呼び出しと呼びます。

class Person(name) {
  this.name = name;
}

const john = new Person('John');
console.log(john.name); // "John"と出力される


thisの使用方法

thisは、オブジェクト指向プログラミングのコンテキストで非常に役立ちます。

thisを使用することで、関数をオブジェクトにバインドし、そのオブジェクトのプロパティにアクセスすることができます。

メソッド呼び出し

メソッド呼び出しでは、thisを使用して、オブジェクトのプロパティにアクセスすることができます。

const person = {
  name: 'John',
  sayHello() {
    console.log(`Hello, my name is ${this.name}`);
  }
};

person.sayHello(); // "Hello, my name is John"と出力される


コンストラクタ呼び出し

コンストラクタ呼び出しでは、thisを使用して、新しいオブジェクトを作成し、そのオブジェクトのプロパティを初期化することができます。

class Person(name) {
  this.name = name;
}

const john = new Person('John');
console.log(john.name); // "John"と出力される


明示的なバインディング

明示的なバインディングでは、thisを使用して、関数を特定のオブジェクトにバインドし、そのオブジェクトのプロパティにアクセスすることができます。

function sayHello() {
  console.log(`Hello, my name is ${this.name}`);
}


const person1 = { name: 'John' };
const person2 = { name: 'Alice' };


sayHello.call(person1); // "Hello, my name is John"と出力される
sayHello.call(person2); // "Hello, my name is Alice"と出力される


thisの問題

thisは非常に便利なキーワードですが、混乱が生じやすい部分でもあります。

以下は、一般的なthisの問題とその解決策です。

thisの値が変わる

thisの値は、関数がどのように呼び出されたかによって変わります。

たとえば、メソッドとして定義された関数を変数に代入して呼び出した場合、thisの値はグローバルオブジェクトになります。

const person = {
  name: 'John',
  sayHello() {
    console.log(`Hello, my name is ${this.name}`);
  }
};

const sayHello = person.sayHello;
sayHello(); // "Hello, my name is undefined"と出力される

この問題を解決するには、bind()call()、またはapply()を使用して、thisの値を明示的に指定することができます。

const person = {
  name: 'John',
  sayHello() {
    console.log(`Hello, my name is ${this.name}`);
  }
};


const sayHello = person.sayHello.bind(person);
sayHello(); // "Hello, my name is John"と出力される


thisのスコープが変わる

thisは、オブジェクトから呼び出された関数にバインドされます。

しかし、関数がネストされた場合、thisの値は親関数のthisとは異なる値になることがあります。

const person = {
  name: 'John',
  sayHello() {
    console.log(`Hello, my name is ${this.name}`);


    function innerFunction() {
      console.log(`Hello, my name is ${this.name}`);
    }


    innerFunction();
  }
};


person.sayHello(); // "Hello, my name is John"と出力される
                   // "Hello, my name is undefined"と出力される

この問題を解決するには、thisを変数に保存することができます。

これにより、内部関数でthisを使用する際に、保存した変数を参照することができます。

const person = {
  name: 'John',
  sayHello() {
    const self = this;
    console.log(`Hello, my name is ${this.name}`);


    function innerFunction() {
      console.log(`Hello, my name is ${self.name}`);
    }


    innerFunction();
  }
};


person.sayHello(); // "Hello, my name is John"と出力される
                   // "Hello, my name is John"と出力される

または、ES6以降のJavaScriptでは、アロー関数を使用することで、外部関数のthisを維持することができます。

const person = {
  name: 'John',
  sayHello() {
    console.log(`Hello, my name is ${this.name}`);


    const innerFunction = () => {
      console.log(`Hello, my name is ${this.name}`);
    }


    innerFunction();
  }
};


person.sayHello(); // "Hello, my name is John"と出力される
                   // "Hello, my name is John"と出力される


【補足】call・apply・bindメソッド

JavaScriptには、関数オブジェクトに対して callapplybind といったメソッドが用意されています。

これらのメソッドは、関数を呼び出す方法を制御するために使用されます。

call メソッド

call メソッドは、ある関数を別のオブジェクトのメソッドとして呼び出す場合に使用されます。

call メソッドは、関数の最初の引数に使用する this キーワードに代入する値を指定します。

function sayHello() {
  console.log(`Hello, ${this.name}!`);
}

const person = { name: 'Alice' };
sayHello.call(person); // => "Hello, Alice!"

call メソッドの第2引数以降は、呼び出す関数の引数として使用されます。

function sum(a, b) {
  console.log(a + b);
}

sum.call(null, 1, 2); // => 3

上の例では、 sum 関数がグローバルスコープで定義されているため、nullthis キーワードに指定しています。

apply メソッド

apply メソッドは、 call メソッドと似ていますが、引数を配列で渡す点が異なります。

apply メソッドは、関数の最初の引数に使用する this キーワードに代入する値を指定します。

function sum(a, b) {
  console.log(a + b);
}

sum.apply(null, [1, 2]); // => 3


bind メソッド

bind メソッドは、関数を新しい関数として返すことができます。

返された関数は、元の関数と同じ引数と this キーワードを受け取ります。

this キーワードには、 bind メソッドに渡されたオブジェクトがバインドされます。

function sayHello() {
  console.log(`Hello, ${this.name}!`);
}


const person = { name: 'Alice' };
const hello = sayHello.bind(person);
hello(); // => "Hello, Alice!"

また、 bind メソッドには、引数を渡すこともできます。

function sum(a, b) {
  console.log(a + b);
}

const addOne = sum.bind(null, 1);
addOne(2); // => 3

上の例では、 sum 関数の最初の引数に 1 を指定し、 addOne 関数を返します。

addOne 関数は、引数に 2 を受け取る前に、sum関数でbindした 1 を最初の引数として受け取ります。

callapplybind の使い分け

最後にcall、apply、bindメソッドについて簡単に使い分けをまとめました。

  • call メソッドは、関数を呼び出す際に、関数の引数をカンマ区切りで指定し、this キーワードを指定する。
  • apply メソッドは、関数を呼び出す際に、引数を配列で渡し、 this キーワードを指定する。
  • bind メソッドは、関数を新しい関数として返し、引数に値を渡すこともできる。
  • bind メソッドを使用すると、オブジェクトに関数をバインドでき、関数を異なるオブジェクトで使用することができる。


まとめ

この記事ではthisの挙動、使用方法およびthisの一般的な問題、callapplybind メソッドについてまとめました。

this は、JavaScriptにおいて重要な概念の1つであり、関数が呼び出されたときにその関数が属しているオブジェクトを参照するために使用されます。

また、this の値は、関数が呼び出される際に動的に決定されます。

this は、関数がどのように呼び出されたかによって異なる値を持つことがあるので、その点は抑えておきましょう。

また当ブログでは、JavaScriptを学び始めたばかりの方や、スキルを磨きたい方に向けて、こちらのUdemy講座をおすすめしています。

Udemyでは、JavaScriptの基本から応用まで学ぶことができる講座が豊富に揃っています。

その中でもこちらの講座は非常に分かりやすく、おすすめしています。

thisの挙動についてもとても分かりやすく解説されています!

管理人

管理人

よかったらぜひチェックしてみてください。

最後まで読んでいただきありがとうございました。

この記事の目次
フロントエンドRPGについて

当ブログは、Web開発に役立つ情報を日々の学びをもとに発信しています。
サイト制作やブログのカスタマイズについて承ります。
お気軽にご連絡・ご相談ください。

©2024 フロントエンドRPG Created by KOBI 23プライバシーポリシー