ホームページ >ウェブフロントエンド >jsチュートリアル >JavaScript の &#this&# キーワードをマスターする: もう振り返る必要はありません

JavaScript の &#this&# キーワードをマスターする: もう振り返る必要はありません

Susan Sarandon
Susan Sarandonオリジナル
2025-01-06 06:59:40994ブラウズ

Mastering the

JavaScript の this キーワードは、初心者と熟練の開発者の両方を同様に困惑させることが多い基本的な概念です。その動的な性質を十分に理解していないと、予期しない動作が発生する可能性があります。この包括的なガイドは、さまざまな背景、ニュアンス、ベスト プラクティスを探求し、これをわかりやすくすることを目的としています。また、理解を確実にするための具体的な例や難しい問題も完備しています。

これについての紹介

JavaScript では、this は、現在のコードが実行されているオブジェクトを参照するキーワードです。 this が静的にバインドされる他のプログラミング言語とは異なり、JavaScript の this は関数の呼び出し方法に基づいて動的に決定されます。

1. グローバルコンテキスト

関数内にない場合、これはグローバル オブジェクトを参照します。

  • ブラウザの場合: グローバル オブジェクトは window です。
  • Node.js の場合: グローバル オブジェクトはグローバルです。


console.log(this === window); // true (in browser)
console.log(this === global); // true (in Node.js)

注: strict モード ('use strict';) では、グローバル コンテキスト内の this はグローバル オブジェクトのままです。

2. 関数コンテキスト

I. 通常の関数

通常の関数では、これは関数の呼び出し方法によって決まります。

  • デフォルトのバインディング: コンテキストなしで関数が呼び出された場合、これはグローバル オブジェクト (厳密モードでは未定義) を参照します。

例:

function showThis() {
  console.log(this);
}

showThis(); // Window object (in browser) or global (in Node.js)
  • 暗黙的バインディング: 関数がオブジェクトのメソッドとして呼び出される場合、これはそのオブジェクトを参照します。


const person = {
  name: 'Alice',
  greet: function() {
    console.log(`Hello, I'm ${this.name}`);
  }
};

person.greet(); // "Hello, I'm Alice"

これを明示的に設定するには、callapply、または bind を使用できます。

function greet() {
  console.log(`Hello, I'm ${this.name}`);
}

const person = { name: 'Bob' };
greet.call(person); // "Hello, I'm Bob"

II.アロー関数

アロー関数には語彙的な this があり、作成時に周囲のスコープから this を継承します。


const person = {
  name: 'Charlie',
  greet: () => {
    console.log(`Hello, I'm ${this.name}`);
  }
};

person.greet(); // "Hello, I'm undefined" (or global name if defined)

説明: アロー関数には独自の this がないため、this は person オブジェクトではなく、グローバル オブジェクトを参照します。

アロー関数の正しい使用法:

const person = {
  name: 'Dana',
  greet: function() {
    const inner = () => {
      console.log(`Hello, I'm ${this.name}`);
    };
    inner();
  }
};

person.greet(); // "Hello, I'm Dana"

課題の側面: メソッドが変数に割り当てられて呼び出される場合、意図したコンテキストが失われる可能性があります。

const calculator = {
  value: 0,
  add: function(num) {
    this.value += num;
    return this.value;
  }
};

console.log(calculator.add(5)); // 5
console.log(calculator.add(10)); // 15

const addFunction = calculator.add;
console.log(addFunction(5)); // NaN (in non-strict mode, this.value is undefined + 5)

3. コンストラクター関数とこれ

関数が new キーワードを使用してコンストラクターとして使用される場合、これは新しく作成されたインスタンスを参照します。

console.log(this === window); // true (in browser)
console.log(this === global); // true (in Node.js)

重要な注意事項:
• new が使用されない場合、これはグローバル オブジェクトを参照するか、厳密モードで未定義になる可能性があります。
• コンストラクターは通常、通常の関数と区別するために最初の文字を大文字にします。

4. イベントハンドラーの this

イベント ハンドラーでは、これはイベントを受信した要素を指します。


function showThis() {
  console.log(this);
}

showThis(); // Window object (in browser) or global (in Node.js)

5. call、apply、bind による明示的バインディング

JavaScript には、この値を明示的に設定するメソッドが用意されています。

  • call: これを最初の引数に設定して関数を呼び出し、続いて関数引数を呼び出します。
const person = {
  name: 'Alice',
  greet: function() {
    console.log(`Hello, I'm ${this.name}`);
  }
};

person.greet(); // "Hello, I'm Alice"
  • apply: call と似ていますが、引数を配列として受け取ります。
function greet() {
  console.log(`Hello, I'm ${this.name}`);
}

const person = { name: 'Bob' };
greet.call(person); // "Hello, I'm Bob"
  • bind: これを最初の引数にバインドした新しい関数を返します。
const person = {
  name: 'Charlie',
  greet: () => {
    console.log(`Hello, I'm ${this.name}`);
  }
};

person.greet(); // "Hello, I'm undefined" (or global name if defined)

使用例:

  • 他のオブジェクトからメソッドを借用します。
  • コールバック内でこれが一貫していることを確認します。

6. これをクラスで

ES6 では、コンストラクター関数とメソッドのより明確な構文を提供するクラスが導入されました。クラスメソッド内では、これはインスタンスを指します。
例:

const person = {
  name: 'Dana',
  greet: function() {
    const inner = () => {
      console.log(`Hello, I'm ${this.name}`);
    };
    inner();
  }
};

person.greet(); // "Hello, I'm Dana"

クラスのアロー関数:
アロー関数は、クラス コンテキストからこれを継承するメソッドに使用でき、コールバックに役立ちます。

const calculator = {
  value: 0,
  add: function(num) {
    this.value += num;
    return this.value;
  }
};

console.log(calculator.add(5)); // 5
console.log(calculator.add(10)); // 15

const addFunction = calculator.add;
console.log(addFunction(5)); // NaN (in non-strict mode, this.value is undefined + 5)

よくある落とし穴とベストプラクティス

I. このコンテキストを失う

メソッドをコールバックとして渡すと、元のコンテキストが失われる可能性があります。
問題

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

const alice = new Person('Alice');
console.log(alice.name); // "Alice"

解決策
バインドを使用してコンテキストを保持します。

<button>



<p><strong>Arrow Function Caveat:</strong><br>
Using arrow functions in event handlers can lead to this referring to the surrounding scope instead of the event target.<br>
<strong>Example:</strong><br>
</p>

<pre class="brush:php;toolbar:false">button.addEventListener('click', () => {
  console.log(this); // Global object or enclosing scope
});

II.アロー関数の不適切な使用

アロー関数には独自の this がないため、メソッドとして使用すると予期しない動作が発生する可能性があります。

問題

function greet(greeting) {
  console.log(`${greeting}, I'm ${this.name}`);
}

const person = { name: 'Eve' };
greet.call(person, 'Hello'); // "Hello, I'm Eve"

解決策
オブジェクトメソッドには通常の関数を使用してください。

greet.apply(person, ['Hi']); // "Hi, I'm Eve"

Ⅲ.グローバルなこれを回避する

グローバル オブジェクトに意図せずプロパティを設定すると、バグが発生する可能性があります。

問題

const boundGreet = greet.bind(person);
boundGreet('Hey'); // "Hey, I'm Eve"

解決策
厳密モードまたは適切なバインディングを使用してください。

class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(`${this.name} makes a noise.`);
  }
}

const dog = new Animal('Dog');
dog.speak(); // "Dog makes a noise."

高度な概念

I. 入れ子関数のこれ

入れ子関数では、this は外側の this を参照しない場合があります。解決策には、アロー関数を使用するか、これを変数に保存することが含まれます。
アロー関数を使用した例:

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

  greet = () => {
    console.log(`Hello, I'm ${this.name}`);
  }
}

const john = new Person('John');
john.greet(); // "Hello, I'm John"

変数を使用した例:

const obj = {
  name: 'Object',
  getName: function() {
    return this.name;
  }
};

const getName = obj.getName;
console.log(getName()); // undefined or global name

II.これはプロトタイプ付き

プロトタイプを使用する場合、これはインスタンスを指します。

console.log(this === window); // true (in browser)
console.log(this === global); // true (in Node.js)

結論

JavaScript の this キーワードは、正しく理解すればコーディング能力を大幅に向上できる多用途で強力な機能です。


これをマスターするための10の難しい問題

これについての理解を確実にするために、次の難しい問題に取り組んでください。各問題は、JavaScript の this キーワードのさまざまな側面とエッジ ケースをテストするように設計されています。最終的には解決策です。

問題 1: 謎の出力

function showThis() {
  console.log(this);
}

showThis(); // Window object (in browser) or global (in Node.js)

問題 2: アロー関数のサプライズ

const person = {
  name: 'Alice',
  greet: function() {
    console.log(`Hello, I'm ${this.name}`);
  }
};

person.greet(); // "Hello, I'm Alice"

問題 3: これをコールバックでバインドする

function greet() {
  console.log(`Hello, I'm ${this.name}`);
}

const person = { name: 'Bob' };
greet.call(person); // "Hello, I'm Bob"

問題 4: バインドを正しく使用する

const person = {
  name: 'Charlie',
  greet: () => {
    console.log(`Hello, I'm ${this.name}`);
  }
};

person.greet(); // "Hello, I'm undefined" (or global name if defined)

問題 5: コンストラクター関数の this

const person = {
  name: 'Dana',
  greet: function() {
    const inner = () => {
      console.log(`Hello, I'm ${this.name}`);
    };
    inner();
  }
};

person.greet(); // "Hello, I'm Dana"

問題 6: イベント ハンドラー コンテキスト

const calculator = {
  value: 0,
  add: function(num) {
    this.value += num;
    return this.value;
  }
};

console.log(calculator.add(5)); // 5
console.log(calculator.add(10)); // 15

const addFunction = calculator.add;
console.log(addFunction(5)); // NaN (in non-strict mode, this.value is undefined + 5)

問題 8: Promise のこれ

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

const alice = new Person('Alice');
console.log(alice.name); // "Alice"

問題 9: バインドによるチェーン

<button>



<p><strong>Arrow Function Caveat:</strong><br>
Using arrow functions in event handlers can lead to this referring to the surrounding scope instead of the event target.<br>
<strong>Example:</strong><br>
</p>

<pre class="brush:php;toolbar:false">button.addEventListener('click', () => {
  console.log(this); // Global object or enclosing scope
});

問題 10: クラスと継承に関する問題

function greet(greeting) {
  console.log(`${greeting}, I'm ${this.name}`);
}

const person = { name: 'Eve' };
greet.call(person, 'Hello'); // "Hello, I'm Eve"

厄介な問題の解決策

問題 1 の解決策:

getName が変数に割り当てられ、オブジェクト コンテキストなしで呼び出される場合、これはデフォルトでグローバル オブジェクトになります。非厳密モードでは、this.name はグローバル名「Global」を参照します。厳密モードでは、これは未定義となり、エラーが発生します。

greet.apply(person, ['Hi']); // "Hi, I'm Eve"

問題 2 の解決策:

アロー関数には独自の this がありません。周囲のスコープからそれを継承します。この場合、周囲のスコープはグローバル コンテキストであり、this.name は「Global」です。

const boundGreet = greet.bind(person);
boundGreet('Hey'); // "Hey, I'm Eve"

問題 3 の解決策:

setInterval コールバック内で、これはグローバル オブジェクトを参照します (または、厳密モードでは未定義です)。したがって、this.seconds は window.seconds をインクリメントするか、厳密モードでエラーをスローします。 timer.秒は 0 のままです。

class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(`${this.name} makes a noise.`);
  }
}

const dog = new Animal('Dog');
dog.speak(); // "Dog makes a noise."

問題 4 の解決策:

retrieveX を module にバインドした後、boundGetX() を呼び出すと、これが module に正しく設定されます。

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

  greet = () => {
    console.log(`Hello, I'm ${this.name}`);
  }
}

const john = new Person('John');
john.greet(); // "Hello, I'm John"

問題 5 の解決策:

アロー関数 getModel はコンストラクターからこれを継承し、新しく作成された車のインスタンスを参照します。

const obj = {
  name: 'Object',
  getName: function() {
    return this.name;
  }
};

const getName = obj.getName;
console.log(getName()); // undefined or global name

問題 6 の解決策:

通常の関数を使用するイベント ハンドラーでは、イベントを受信した DOM 要素 (ボタン) を指します。ボタンには name プロパティがないため、this.name は未定義です。

console.log(this === window); // true (in browser)
console.log(this === global); // true (in Node.js)

問題 7 の解決策:

  • 最初の console.log(this.name); inside innerFunc は obj を参照しているため、「Outer」を出力します。
  • 2 番目の console.log(this.name); innerFunc の内部はグローバル オブジェクトを参照するため、厳密モードでは 'Global' または unknown が出力されます。
function showThis() {
  console.log(this);
}

showThis(); // Window object (in browser) or global (in Node.js)

問題 8 の解決策:

Promise コンストラクター内で、これはグローバル オブジェクトを参照します (または、厳密モードでは未定義です)。したがって、this.value は未定義です (または、厳密モードでエラーが発生します)。

const person = {
  name: 'Alice',
  greet: function() {
    console.log(`Hello, I'm ${this.name}`);
  }
};

person.greet(); // "Hello, I'm Alice"

問題 9 の解決策:

multiply 関数は、最初の引数 a を 2 としてバインドされています。double(5) が呼び出されると、事実上、multiply(2, 5) が計算されます。

function greet() {
  console.log(`Hello, I'm ${this.name}`);
}

const person = { name: 'Bob' };
greet.call(person); // "Hello, I'm Bob"

問題 10 の解決策:

Dog クラスの speech メソッドでは、setTimeout コールバックが通常の関数です。したがって、コールバック内の this は、dog インスタンスではなく、グローバル オブジェクトを参照します。 this.name は「未定義」であるか、名前がグローバルに定義されていない場合はエラーが発生します。

const person = {
  name: 'Charlie',
  greet: () => {
    console.log(`Hello, I'm ${this.name}`);
  }
};

person.greet(); // "Hello, I'm undefined" (or global name if defined)

これを修正するには、アロー関数を使用します。

const person = {
  name: 'Dana',
  greet: function() {
    const inner = () => {
      console.log(`Hello, I'm ${this.name}`);
    };
    inner();
  }
};

person.greet(); // "Hello, I'm Dana"

これで、正しくログが記録されるようになりました。

const calculator = {
  value: 0,
  add: function(num) {
    this.value += num;
    return this.value;
  }
};

console.log(calculator.add(5)); // 5
console.log(calculator.add(10)); // 15

const addFunction = calculator.add;
console.log(addFunction(5)); // NaN (in non-strict mode, this.value is undefined + 5)

以上がJavaScript の &#this&# キーワードをマスターする: もう振り返る必要はありませんの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。