【JavaScript】プログラミング初心者が抑えておくべきthisの挙動と使い方
2023年2月20日
JavaScriptのthis
は、JavaScriptプログラミングにおいて非常に重要な概念の1つです。this
は、コンテキストに応じて変化する特殊なキーワードであり、関数内部で呼び出されると、その関数を呼び出すオブジェクトを参照することができます。
この記事では、this
の挙動、使用方法、およびthis
の一般的な問題、call
、 apply
、 bind
メソッドについて詳しく説明します。
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メソッドによる呼び出し
this
がcall
または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には、関数オブジェクトに対して call
、 apply
、 bind
といったメソッドが用意されています。
これらのメソッドは、関数を呼び出す方法を制御するために使用されます。
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
関数がグローバルスコープで定義されているため、null
を this
キーワードに指定しています。
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
を最初の引数として受け取ります。
call、 apply、 bind の使い分け
最後にcall、apply、bindメソッドについて簡単に使い分けをまとめました。
call
メソッドは、関数を呼び出す際に、関数の引数をカンマ区切りで指定し、this
キーワードを指定する。apply
メソッドは、関数を呼び出す際に、引数を配列で渡し、this
キーワードを指定する。bind
メソッドは、関数を新しい関数として返し、引数に値を渡すこともできる。bind
メソッドを使用すると、オブジェクトに関数をバインドでき、関数を異なるオブジェクトで使用することができる。
まとめ
この記事ではthisの挙動、使用方法およびthis
の一般的な問題、call
、 apply
、 bind
メソッドについてまとめました。this
は、JavaScriptにおいて重要な概念の1つであり、関数が呼び出されたときにその関数が属しているオブジェクトを参照するために使用されます。
また、this
の値は、関数が呼び出される際に動的に決定されます。this
は、関数がどのように呼び出されたかによって異なる値を持つことがあるので、その点は抑えておきましょう。
また当ブログでは、JavaScriptを学び始めたばかりの方や、スキルを磨きたい方に向けて、こちらのUdemy講座をおすすめしています。
Udemyでは、JavaScriptの基本から応用まで学ぶことができる講座が豊富に揃っています。
その中でもこちらの講座は非常に分かりやすく、おすすめしています。
thisの挙動についてもとても分かりやすく解説されています!

管理人
よかったらぜひチェックしてみてください。
最後まで読んでいただきありがとうございました。