これを指さして
JavaScript では、これは現在の関数が実行されるコンテキスト オブジェクトを表します。この値は、関数の実行時に動的に決定され、関数の呼び出し方法によって異なります。これが表す可能性のあるさまざまな状況を次に示します。
1. デフォルトのバインディング
関数が独立して呼び出される場合、this の値はグローバル オブジェクト (ブラウザーのウィンドウ オブジェクト、Node.js のグローバル オブジェクト) を指します。
function foo() {
console.log(this);
}
foo(); // window(浏览器中)或 global(Node.js 中)
2. 暗黙的なバインディング
関数がオブジェクトのメソッドとして呼び出される場合、this の値はオブジェクトを指します。
var obj = {
name: "张三",
sayName: function() {
console.log(this.name);
}
};
obj.sayName(); // 张三
3. バインディングを表示する
call、apply、またはbindメソッドを通じて関数の実行コンテキストを変更し、これを指定されたオブジェクトに明示的にバインドします。
function sayName() {
console.log(this.name);
}
var obj1 = {
name: "张三" };
var obj2 = {
name: "李四" };
sayName.call(obj1); // 张三
sayName.apply(obj2); // 李四
var sayName2 = sayName.bind(obj1);
sayName2(); // 张三
4. 新しいバインディング
new 演算子を使用してコンストラクターが呼び出される場合、this の値は新しく作成されたインスタンス オブジェクトを指します。
function Person(name) {
this.name = name;
}
var p = new Person("张三");
console.log(p.name); // 张三
アロー関数が使用される場合、this の値は定義時に決定され、動的に変更されないことに注意してください。したがって、これをアロー関数で使用する場合、その値は通常、それが定義されたコンテキストになります。
閉鎖
JavaScript では、クロージャは、関数が外側のスコープ内の変数にアクセスして操作できることを意味し、これらの変数は関数の実行が終了した後も値と状態を保持できます。クロージャは JavaScript において非常に一般的で重要な概念です。
クロージャは、関数内に別の関数を定義し、それを戻り値として返すことで実装され、クロージャを形成します。返された関数は、それが定義されたスコープ内の変数にアクセスできます。これらの変数はクロージャによって参照されるため、関数の終了後に破棄されません。
以下は、クロージャを使用してカウンタを実装する例です。
function createCounter() {
var count = 0;
return function() {
count++;
console.log(count);
};
}
var counter1 = createCounter();
counter1(); // 输出 1
counter1(); // 输出 2
counter1(); // 输出 3
var counter2 = createCounter();
counter2(); // 输出 1
counter2(); // 输出 2
上記のコードでは、createCounter 関数は、外部スコープ内の変数 count を参照する内部定義された匿名関数を返します。createCounter 関数を呼び出すたびに新しいクロージャーが作成されるため、counter1 と counter2 は 2 つの独立したカウンターになります。
クロージャには、関数のカリー化、遅延計算、モジュール化などを実装するためにクロージャを使用するなど、いくつかの特別な用途もあります。クロージャは関数内の変数をメモリ内に保持するため、クロージャを過度に使用するとメモリ リークが発生する可能性があるため、クロージャの適切な使用に注意する必要があることに注意してください。
実行コンテキスト
JavaScript では、実行コンテキスト (Execution Context) は JavaScript コードが実行されるときの環境を指し、変数、関数、スコープ、this など、コードの実行に必要なすべての情報が含まれます。関数呼び出しごとに、新しい実行コンテキストが作成されます。
実行コンテキストには次の 3 種類があります。
-
グローバル実行コンテキスト: JavaScript コードの実行開始時に作成される実行コンテキスト。コード内の最も外側の実行コンテキストであり、プログラム全体のデフォルトの実行コンテキストです。グローバル実行コンテキストは 1 つだけあり、プログラムのライフサイクル全体にわたって存在します。
-
関数実行コンテキスト: 関数が呼び出されるたびに作成される実行コンテキストには、関数内で定義された変数、関数、スコープ チェーンなどの情報が含まれます。
-
eval 実行コンテキスト (Eval Execution Context) : eval 関数の使用時に作成される実行コンテキスト。変数、関数、スコープ チェーン、および実行されるコード フラグメントに必要なその他の情報が含まれます。
実行コンテキストは、作成時に次の 2 つの段階を経ます。
- 作成フェーズ: 実行コンテキストが作成されると、JavaScript エンジンは変数オブジェクト (Variable Object)、スコープ チェーン (Scope Chain)、このポインターおよびその他の情報を作成します。
- 実行フェーズ: 実行コンテキストが作成された後、JavaScript エンジンはその中のコードを実行し、変数オブジェクトやスコープ チェーンなどの情報を更新します。
作成フェーズでは、実行コンテキストは次の順序でいくつかの操作を完了します。
- 変数オブジェクト(Variable Object)の作成: 変数オブジェクトとは、変数や関数宣言などの情報を格納するオブジェクトで、実行コンテキストの作成時に作成されます。
- スコープ チェーン (スコープ チェーン) の作成: スコープ チェーンは、現在の実行コンテキストとすべての外部実行コンテキスト変数オブジェクトを格納するリンク リスト構造です。JavaScript エンジンが現在のコンテキストで変数を探すときは、まず現在の変数オブジェクトを調べますが、見つからない場合はスコープ チェーンを調べます。
- このポインタを決定する: このポインタは、関数が実行されるときの現在のオブジェクトへのポインタであり、関数が呼び出されたときに決定されます。
実行フェーズでは、実行コンテキストは次の順序でいくつかの操作を完了します。
- コードの実行: JavaScript エンジンは、コード内のステートメントを、記述された順序で実行します。
- 変数オブジェクトの更新: 変数オブジェクト内の変数は、実行中に最新の値に更新されます。
- 実行関数宣言: コード内に関数宣言が存在する場合、それらは作成フェーズ中に変数オブジェクトに追加され、これらの関数は実行フェーズ中に直接呼び出すことができます。
実行コンテキストとスコープは JavaScript において非常に重要な概念であり、それらがどのように機能するかを理解することは、高品質の JavaScript コードを作成するために非常に重要です。
プロトタイプ/プロトタイプチェーン
JavaScript では、すべてのオブジェクトにそのプロトタイプ (コンストラクターを通じて作成されたオブジェクトのプロトタイプ オブジェクト) への内部リンクがあります。prototype
コンストラクターのプロトタイプ オブジェクトには、プロパティを通じてアクセスできます。
オブジェクトを作成すると、JavaScript エンジンはまずオブジェクト自体に特定のプロパティまたはメソッドがあるかどうかを確認します。ない場合は、そのオブジェクトのプロトタイプ オブジェクト内を検索します。それでも見つからない場合は、引き続き検索します。プロトタイプ オブジェクト。プロパティまたはメソッドが見つかるまで、またはプロトタイプ チェーンの最後に到達するまで、プロトタイプ オブジェクトを検索します。
プロトタイプ オブジェクトは、プロパティとメソッドの継承を実装できます。オブジェクトのプロパティまたはメソッドにアクセスするとき、オブジェクト自体にそのプロパティまたはメソッドがない場合、JavaScript エンジンはプロパティまたはメソッドが見つかるまでプロトタイプ チェーンを検索します。
プロトタイプ チェーンの一般的な概念をいくつか示します。
**1. プロトタイプ:** 各オブジェクトには、プロパティとメソッドの継承を実装するために使用されるプロトタイプ オブジェクトがあります。
**2. プロトタイプチェーン: **各オブジェクトのプロトタイプオブジェクトもオブジェクトであるため、プロトタイプオブジェクトも独自のプロトタイプオブジェクトを持ち、プロトタイプチェーンと呼ばれるチェーン構造を形成します。
-
コンストラクター: オブジェクトの作成に使用される関数。コンストラクターを通じて作成されたオブジェクトには、
prototype
コンストラクターのプロパティを通じて設定されるプロトタイプ オブジェクトがあります。 -
__proto__
プロパティ: 各オブジェクトには、__proto__
オブジェクトのプロトタイプ オブジェクトを指すプロパティがあり、それを通じてプロトタイプ チェーン上のプロパティとメソッドにアクセスできます。__proto__
ただし、実際の開発ではプロパティを使用することは推奨されず、Object.getPrototypeOf
オブジェクトのプロトタイプオブジェクトを取得するメソッドを使用することをお勧めします。
以下は、プロトタイプを使用してプロパティとメソッドの継承を実装する方法を示す簡単な例です。
// 定义一个构造函数
function Person(name, age) {
this.name = name;
this.age = age;
}
// 在 Person 构造函数的原型对象上定义一个方法
Person.prototype.sayHello = function() {
console.log(`Hello, my name is ${
this.name} and I am ${
this.age} years old.`);
};
// 创建一个 Person 对象
const person1 = new Person('Alice', 25);
// 调用 Person 对象的 sayHello 方法
person1.sayHello(); // 输出:Hello, my name is Alice and I am 25 years old.
// 创建一个 Student 对象,继承自 Person 对象
function Student(name, age, grade) {
Person.call(this, name, age); // 调用父类构造函数,初始化父类的属性
this.grade = grade;
}
// 通过原型继承,使 Student 对象也拥有 sayHello 方法
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;
// 创建一个 Student 对象
const student1 = new Student('Bob', 18, 10);
// 调用 Student 对象的 sayHello 方法
スコープとスコープチェーン
JavaScript では、スコープは変数 (関数を含む) のアクセス可能なスコープ、つまり変数にアクセスできるコード領域を指します。JavaScript には、グローバル スコープと関数スコープの 2 種類のスコープがあります。
グローバル スコープは、プログラム全体でアクセスできるコードの最も外側のレベルで定義された変数を指します。関数スコープは、関数内で定義された変数を指し、関数内でのみアクセスできます。
JavaScript のスコープ チェーンは、一連のネストされた関数スコープで構成され、レイヤーごとにネストされたスコープ チェーンを形成します。コードが特定のスコープ内の変数にアクセスする場合、JavaScript エンジンはまず現在のスコープ内の変数を検索します。変数が見つかった場合は、その変数を直接使用します。見つからない場合は、変数内で検索を続けます。変数が見つかるまで外部スコープを検索するか、グローバル スコープまで検索します。
スコープチェーンの生成プロセスは関数定義時に決まり、関数定義時のスコープ環境によって決まります。関数が実行されると、その関数が定義されたときのスコープ環境を含むスコープ チェーンを持つ新しい実行環境が作成されます。他の関数が関数内で定義されている場合、新しい関数のスコープ チェーンには外側の関数のスコープ環境も含まれるため、ネストされたスコープ チェーンが形成されます。
スコープとスコープ チェーンの概念は JavaScript の比較的基本的で重要な概念であり、JavaScript の変数、関数、クロージャなどを理解するのに非常に役立ちます。次に、スコープ チェーンの使用法を示す簡単な例を示します。
// 全局作用域
const globalVar = 'globalVar';
function outer() {
// 外层函数作用域
const outerVar = 'outerVar';
function inner() {
// 内层函数作用域
const innerVar = 'innerVar';
console.log(innerVar); // 输出 'innerVar'
console.log(outerVar); // 输出 'outerVar'
console.log(globalVar); // 输出 'globalVar'
}
inner();
}
outer();
上の例では、グローバル スコープにはグローバル変数 が含まれglobalVar
、外側の関数スコープには変数 が含まれouterVar
、内側の関数スコープには変数が含まれていますinnerVar
。関数が実行されるとinner
、最初に独自のスコープ内の変数を検索し、次に外側のスコープとグローバル スコープinnerVar
内の変数を検索し、最後にこれらの変数の値を出力します。スコープ チェーン メカニズムにより、内部関数は外部関数の変数にアクセスできますが、外部関数は内部関数の変数にアクセスできません。これはクロージャの概念です。つまり、関数が定義されたスコープが破棄された場合でも、関数はその定義されたスコープ内の変数にアクセスできます。outerVar
globalVar
クロージャの使用例を次に示します。
function outer() {
const outerVar = 'outerVar';
function inner() {
console.log(outerVar);
}
return inner;
}
const innerFn = outer();
innerFn(); // 输出 'outerVar'
上記の例では、outer
関数は内部関数を返しinner
、変数はinner
関数内でアクセスされますouterVar
。関数が呼び出されるとouter
、新しい実行環境が作成され、outer
現在のスコープ チェーン内の関数がスコープ環境としてスコープ チェーンにプッシュされます。関数が実行されるとouter
スコープ環境は破壊されますが、inner
関数がouterVar
変数を参照しているため、この変数の値は解放されず、inner
関数内でこの変数にアクセスできます。