1. let と const
させて
- メモリの特性: let で宣言された変数 (数値、文字列、配列など) の後に割り当てられた記憶領域の値は変更でき、格納されているポインタも変更でき、ポインタが指すメモリ領域も変更できます。変更されました (配列、オブジェクトなど)
- スコープ: ブロックスコープ
- 一時的なデッドゾーン: 宣言前に使用するとエラーが発生します
- 変数のプロモーション: 変数のプロモーションはなく、繰り返し宣言することはできません。
- for ループ: JavaScript エンジンは内部的に前のループを記憶し、このラウンドで let によって宣言された変数を初期化します。
定数
- メモリの特性: const 宣言後に確保された変数 (数値、文字列、配列など) の記憶空間の値は定数と等価であり、変更できません 格納されたポインタは変更できません メモリ空間の値ポインタの指す先は変更可能(配列、オブジェクト等)
- スコープ、一時行デッドゾーン、変数プロモーション機能は let と同じです。
// 正确示例 const obj = {} obj.father = '123' // 错误示例 const obj = {} obj = { father: '123'} // 冻结对象 const obj = { name: 'Alice', age: 20 }; Object.freeze(obj); obj.name = 'Bob'; // 抛出TypeError错误
最上位オブジェクト
- ブラウザでは、トップレベルのオブジェクトは です
window
が、Node と Web Worker は異なりますwindow
。- ブラウザと Web ワーカーでは、
self
これらもトップレベルのオブジェクトを指しますが、Node はそうではありませんself
。- Node では、トップレベルのオブジェクトは です
global
が、他の環境ではサポートされていません。
2. 代入と展開の分割
代入の分割
- 分割代入では、オブジェクト、配列、文字列、ブール値、関数などのオブジェクトがサポートされます。
- 代入の分割では、デフォルト値の設定がサポートされています。代入オブジェクトが厳密に未定義に等しい場合、デフォルト値が有効になります。
- オブジェクト構造の割り当ての内部メカニズムは、まず同じ名前の属性を見つけて、それを対応する変数に割り当てることです。実際にコピーされるのは、前者ではなく後者です。この割り当てプロセスの「前者」は「」と呼ばれます。 「モード」、「後者」を「変数」と呼びます。
- 構造体の割り当て中に括弧を使用できないシナリオは 3 つあります。
- 変数宣言文
- 関数ステートメント内のパラメータ
- 代入ステートメントのパターン
// 对象 const node = { loc: { start: { line: 1, column: 5 } } }; let { loc, loc: { start }, loc: { start: { line }} } = node; line // 1 loc // Object {start: Object} start // Object {line: 1, column: 5} // 数组 const [a, b, c, d, e] = 'hello'; a // "h" b // "e" c // "l" d // "l" e // "o" // 字符串 let {length : len} = 'hello'; len // 5 // 布尔类型 let {toString: s} = true; s === Boolean.prototype.toString // true // 函数 function add([x, y]){ return x + y; } add([1, 2]); // 3
機能拡張
- 関数パラメータは、次のようなデフォルト値に設定できます。
function fn(a,b = 1) {} // 默认值作用域指向外层对象 let foo = 'outer'; function bar(func = () => foo) { let foo = 'inner'; console.log(func()); } bar(); // outer
- 割り当てを分割するためのデフォルト値と組み合わせて使用されます
// 这种写法函数第二个参数不能省略 function fetch(url, { body = '', method = 'GET', headers = {} }) { console.log(method); } fetch('http://example.com', {}) // "GET" fetch('http://example.com') // 报错 // 这种写法函数第二个参数可以省略 function fetch(url, { body = '', method = 'GET', headers = {} } = {}) { console.log(method); } fetch('http://example.com') // "GET"
- 残りのパラメータ
const obj = [1,2,3,4] console.log(...obj) // 1,2,3,4
- アロー関数
- 通常の関数の場合、内部
this
ポイントは関数が実行されているオブジェクトですが、これはアロー関数には当てはまりません。独自のオブジェクトはなくthis
、内部オブジェクトはthis
定義時に上位スコープにありますthis
。つまり、this
アロー関数の内部方向は固定ですが、this
通常の関数の方向は可変です。- アロー関数は実際にポインタを固定することができ
this
、バインディングによりthis
可変ではなくなります。この機能はコールバック関数をカプセル化するのに非常に役立ちます。// 只有一条语句且返回值不为对象时,不需要return且可以省略代码块 const sum = (num_a, num_b) => num_a + num_b // 只有一条语句时且返回值为对象时, 需要用圆括号 const getObj = id => ({ id: id, name: Tom }) // 不报错 const getObj = id => { id: id, name:Tom } // 报错 // 箭头函数this指向问题 function foo() { setTimeout(() => { console.log('id:', this.id); }, 100); } var id = 21; foo.call({ id: 42 }); // id: 42
配列拡張子
- スプレッド演算子:
console.log(...[1, 2, 3]) // 1 2 3
- スプレッド演算子は内部でデータ構造の Iterator インターフェイスを呼び出すため、オブジェクトに Iterator インターフェイスがある限り、スプレッド演算子を使用できます。
Object.assign()
オブジェクトのスプレッド演算子は、メソッドを使用するのと同じです。let aClone = { ...a }; // 等同于 let aClone = Object.assign({}, a);
三、代理、約束、反映
プロキシ
- プロキシは、ターゲット オブジェクトの前に「インターセプト」層を設定するものとして理解できます。オブジェクトへの外部アクセスは、まずこのインターセプト層を通過する必要があります。そのため、外部アクセスをフィルタリングして書き換えるメカニズムを提供します。Proxy という言葉の本来の意味は代理店であり、ここでは特定の業務を「代行する」という意味で使用されており、「代理人」と訳すこともできます。
- ES6 は、プロキシ インスタンスを生成するためのプロキシ コンストラクターをネイティブに提供します。
var proxy = new Proxy({}, { get: function(target, propKey) { return 35; } }); proxy.time // 35 proxy.name // 35 proxy.title // 35
- ハンドティアプロキシ:
const target = { name: 'Tom', age: 20 }; const handler = { get: function(target, prop) { console.log(`Getting ${prop} property`); return target[prop]; }, set: function(target, prop, value) { console.log(`Setting ${prop} property to ${value}`); target[prop] = value; } }; const proxy = new Proxy(target, handler); console.log(proxy.name); // 输出:Getting name property Tom proxy.age = 25; // 输出:Setting age property to 25 console.log(proxy.age); // 输出:Getting age property 25
約束
- Promise は、JavaScript で非同期操作を処理できるようにする非同期プログラミング パターンです。Promise オブジェクトは、非同期操作の最終的な完了または失敗を表し、then() メソッドを使用して非同期操作の結果を処理できます。Promise は、コールバック地獄を回避し、非同期コードをクリーンで保守しやすくするのに役立ちます。
- オブジェクトの状態は外界の影響を受けません。
Promise
このオブジェクトは非同期操作を表し、pending
(進行中)、fulfilled
(成功)、rejected
(失敗) の 3 つの状態があります。非同期操作の結果のみが現在の状態を決定でき、他の操作はこの状態を変更できません。これがPromise
名前の由来でもあり、英語で「コミットメント」という意味で、他の手段では変えられないという意味です。- 一度状態が変化すると再度変化することはなく、いつでもこの結果が得られます。
Promise
オブジェクトの状態が変化する可能性は 2 つだけです。 からpending
へfulfilled
と からpending
へですrejected
。この 2 つの状況が発生する限り、状態は固定化され、再び変化することはなく、常にその結果が維持されます。これを解決済みといいます。すでに変更が行われている場合は、Promise
オブジェクトにコールバック関数を追加すると、結果がすぐに得られます。イベントとは全く違い、一度聞き逃してもう一度聞いても結果が出ないのがイベントの特徴です。- 約束を手で破る:
function MyPromise(fn) { const self = this; self.value = null; self.error = null; self.onFulfilled = null; self.onRejected = null; function resolve(value) { setTimeout(() => { self.value = value; self.onFulfilled(self.value); }, 0); } function reject(error) { setTimeout(() => { self.error = error; self.onRejected(self.error); }, 0); } fn(resolve, reject); } MyPromise.prototype.then = function(onFulfilled, onRejected) { const self = this; return new MyPromise((resolve, reject) => { self.onFulfilled = function(value) { try { const result = onFulfilled(value); resolve(result); } catch (error) { reject(error); } }; self.onRejected = function(error) { try { const result = onRejected(error); resolve(result); } catch (error) { reject(error); } }; }); }; const promise = new MyPromise((resolve, reject) => { setTimeout(() => { resolve('Hello, world!'); }, 1000); }); promise.then( value => console.log(value), error => console.error(error) );
反映する
- JavaScriptではオブジェクトの操作メソッドが比較的分散しており、例えばプロパティ値を取得するにはobj[key]、obj.property、Object.getOwnPropertyDescriptor()などのメソッドが使用でき、メソッドの名前や使い方も異なります。覚えて使用するのは不便です。Reflect は、Reflect.get()、Reflect.set()、Reflect.getOwnPropertyDescriptor() などの統一されたメソッド セットを提供し、オブジェクト操作の一貫性を高め、使いやすくします。
- Reflect は、オブジェクト操作の一貫性を高め、使いやすくするための API の統合セットを提供します。また、プロキシ インターセプトをサポートし、いくつかの新しい操作メソッドを提供することで、JavaScript の柔軟性とスケーラビリティを向上させます。
例:
const obj = { name: 'Tom', age: 20 }; console.log(Reflect.get(obj, 'name')); // 输出:Tom Reflect.set(obj, 'age', 25); console.log(obj.age); // 输出:25 console.log(Reflect.has(obj, 'name')); // 输出:true Reflect.deleteProperty(obj, 'age'); console.log(obj.age); // 输出:undefined function Person(name, age) { this.name = name; this.age = age; } const person = Reflect.construct(Person, ['Tom', 20]); console.log(person.name, person.age); // 输出:Tom 20 function sayHello(name) { console.log(`Hello, ${name}!`); } Reflect.apply(sayHello, null, ['Tom']); // 输出:Hello, Tom!
4. クラスとコンストラクター
クラスクラス
- クラス定義: class キーワードを使用してクラスを定義します。クラス名は通常、大文字で始まるキャメルケースの名前を使用します。
- コンストラクター: コンストラクターは、オブジェクトのプロパティを初期化するために、constructor キーワードを使用してクラス内で定義できます。
- プロパティとメソッド: プロパティとメソッドは、オブジェクト リテラルと同様の構文を使用してクラス内で定義できますが、カンマで区切る必要はありません。
- 継承: クラスは extends キーワードを通じて継承でき、サブクラスは親クラスのプロパティとメソッドを継承し、親クラスのメソッドをオーバーライドできます。
- super キーワード: サブクラスで super キーワードを使用して、親クラスのコンストラクターとメソッドを呼び出すことができます。
- 静的メソッド: 静的メソッドは、static キーワードを使用してクラス内で定義できます。静的メソッドは、オブジェクトを作成せずにクラス名を通じて直接呼び出すことができます。
- ゲッターとセッター: クラス内でゲッター メソッドとセッター メソッドを定義して、オブジェクトの属性値を取得および設定できます。
- クラス式: クラスは式を使用して定義することもでき、クラス式は変数に割り当てたり、関数パラメータとして渡すことができます。
ジェネレーター機能
- 非同期プログラミング: Generator 関数は、 yield キーワードを使用して関数の実行を一時停止および再開できます。これを使用すると、非同期操作を処理し、コールバック 地獄や多層ネストされたコールバック関数を回避できます。
- Iterator: Generator 関数は、配列、オブジェクト、マップなどのデータ構造を走査するために使用できる反復子オブジェクトを返します。
- ステート マシン: ジェネレーター関数を使用してステート マシンを実装できます。次のメソッドが呼び出されるたびに、関数は最後に一時停止した位置から実行を継続し、さまざまな状態に応じてさまざまな値を返すことができます。
- フローの制御: ジェネレーター関数を使用してフローを制御できます。たとえば、yield キーワードを使用して関数の実行を一時停止し、実行を続行する前に特定の条件が満たされるのを待つことができます。
- コルーチン: ジェネレーター関数を使用してコルーチンを実装したり、関数の実行中に実行を一時停止および再開したり、いくつかの複雑なタスクを処理したりできます。
- Generator と Promise を使用して GPT テキスト出力の効果をシミュレートする
function* gptOutput(text) { for (let i = 0; i < text.length; i++) { yield text[i]; yield new Promise(resolve => setTimeout(resolve, 50)); } } const output = gptOutput('Hello, world!'); const timer = setInterval(() => { const { value, done } = output.next(); if (done) { clearInterval(timer); } else { console.log(value); } }, 100);