目次
B. 関数は関数を返し、子関数は親スコープの変数を呼び出します。
プライベート変数/メソッド: グローバルな汚染を回避し、外部アクセスや変更から変数を保護するために関数内にカプセル化されています。
メモリ使用量: ガベージ コレクションできません。乱用するとメモリリークが発生する可能性があります
パフォーマンスの損失: スコープチェーン検索、パフォーマンスの損失
関数のカリー化 (関数を返す): パラメーターの再利用、遅延実行
メモリ リーク: メモリの無駄遣い -> 速度の低下 -> クラッシュ
使用されなくなった/null 参照は削除されません: クロージャ/DOM は削除され、子ノード参照は削除されません
IIFE: ()() (関数式を即座に呼び出す)/自己実行匿名関数
クロージャは、関数とそのバンドルされた周囲の環境(字句環境)への参照の組み合わせです。
語彙範囲
変数がソース コード内で宣言されている場所に基づいて、その変数が使用できる場所を判断します。
function init() {
var name = "Mozilla"; // name 是一个被 init 创建的局部变量
function displayName() {
// displayName() 是内部函数,一个闭包
alert(name); // 使用了父函数中声明的变量
}
displayName();
}
init();
ネストされた関数は、外側のスコープで宣言された変数にアクセスできます。
クロージャは、関数と、その関数が宣言されている字句環境で構成されます。環境には、クロージャの作成時にスコープ内にあったローカル変数がすべて含まれます。この場合、これはmyFunc
実行 makeFunc
中に作成された 関数インスタンスへの参照ですdisplayName
。 のインスタンスは、その語彙環境 (変数が存在する環境)displayName
への参照を維持します 。name
function makeFunc() {
var name = "Mozilla";
function displayName() {
alert(name);
}
return displayName;
}
var myFunc = makeFunc();
myFunc();
一部のプログラミング言語では、関数内のローカル変数は関数の実行中にのみ存在します。実行が完了すると 、 その変数にはアクセスできなくなるとmakeFunc()
思われるかもしれません 。name
ただし、JavaScript ではコードが期待どおりに実行されるため、これは明らかに当てはまりません。
A.パラメータとしての関数: IIFE 匿名クロージャ
for (var i = 0; i < 5; i++) {
(function(j) {
setTimeout(function timer() {
console.log(j);
}, 1000);
})(i);
}
//或者
for(var i = 0;i < 5;i++)
{
setTimeout((function(i){
return () => console.log(i);
})(i),1000)
}
B. 関数は function を返し、子関数は親スコープの変数を呼び出します。
これは、jsスコープのライフサイクルは、内部スクリプトがすべて破棄され、親スコープに持ち込まれない前に実行されるかどうかに依存するためです。
これは下位スコープで参照されており、解放されていないためです。その結果、上位レベルのスコープ内の変数は、下位レベルのスコープが実行されるか、クロージャ (サブ関数) が参照されなくなるまで解放されません。
function createCounter() {
let counter = 0
const myFunction = function() {
counter = counter + 1
return counter
}
return myFunction
}
const increment = createCounter()
const c1 = increment()
const c2 = increment()
const c3 = increment()
console.log('example increment', c1, c2, c3)//1 2 3
アドバンテージ
プライベート変数/メソッド: グローバルな汚染を回避し、外部アクセスや変更から変数を保護するために関数内にカプセル化されます。
欠点がある
メモリ使用量: ガベージ コレクションできません。乱用するとメモリリークが発生する可能性があります
パフォーマンス損失: スコープチェーン検索、パフォーマンス損失
使用するシーン
関数のカリー化 (関数を返す): パラメーターの再利用、遅延実行
手ぶれ補正スロットリング
プライベート変数
JavaScript はプライベート変数をネイティブにサポートしていません
var Counter = (function () {
var privateCounter = 0;
function changeBy(val) {
privateCounter += val;
}
return {
increment: function () {
changeBy(1);
},
decrement: function () {
changeBy(-1);
},
value: function () {
return privateCounter;
},
};
})();
console.log(Counter.value()); /* logs 0 */
Counter.increment();
Counter.increment();
console.log(Counter.value()); /* logs 2 */
Counter.decrement();
console.log(Counter.value()); /* logs 1 */
パブリッシュ-サブスクライブ
function createPubSub() {
// 存储事件及其对应的订阅者
const subscribers = {};
// 订阅事件
function subscribe(event, callback) {
// 如果事件不存在,则创建一个新的空数组
if (!subscribers[event]) {
subscribers[event] = [];
}
// 将回调函数添加到订阅者数组中
subscribers[event].push(callback);
}
// 发布事件
function publish(event, data) {
// 如果事件不存在,则直接返回
if (!subscribers[event]) {
return;
}
// 遍历订阅者数组,调用每个订阅者的回调函数
subscribers[event].forEach((callback) => {
callback(data);
});
}
// 返回订阅和发布函数
return {
subscribe,
publish,
};
}
// 使用示例
const pubSub = createPubSub();
// 订阅事件
pubSub.subscribe("event1", (data) => {
console.log("订阅者1收到事件1的数据:", data);
});
pubSub.subscribe("event2", (data) => {
console.log("订阅者2收到事件2的数据:", data);
});
// 发布事件
pubSub.publish("event1", "Hello");
// 输出: 订阅者1收到事件1的数据: Hello
pubSub.publish("event2", "World");
// 输出: 订阅者2收到事件2的数据: World
チェーンコール
function calculator() {
let result = 0;
function add(num) {
result += num;
return this;
}
function subtract(num) {
result -= num;
return this;
}
function multiply(num) {
result *= num;
return this;
}
function divide(num) {
result /= num;
return this;
}
function getResult() {
return result;
}
function clear() {
result = 0;
return this;
}
return {
add,
subtract,
multiply,
divide,
getResult,
clear,
};
}
const calc = calculator();
const result = calc.add(5).subtract(2).divide(3).multiply(6).getResult();
console.log(result); // 输出:6
メモリ リーク:メモリの無駄遣い -> 速度の低下 -> クラッシュ
使用されなくなった/null 参照は削除されません: クロージャ/DOM は削除され、子ノード参照は削除されません
IIFE: ()() (関数式を即座に呼び出す)/自己実行匿名関数
- 最初の部分は字句スコープを持つ匿名関数であり、括弧演算子
()
で 閉じられます。これにより、外部の世界が IIFE 内の変数にアクセスするのを防ぐだけでなく、グローバル スコープを汚染することもありません。 - 2 番目の部分
()
では、JavaScript エンジンが関数を即座に実行する即時関数式を作成します。
(function () {
// …
})();
(() => {
// …
})();
(async () => {
// …
})();