作用域链
当我们访问一个变量的时候,JavaScript引擎首先会在当前作用域寻找这个变量。如果当前作用域没有这个变量,就回去上一层作用域寻找。如果上一层作用域找不到,就去上上层寻找。直到全局作用域`都找不到时,返回undefined。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| var windowVar = "windowVar";
function outer() { var outerVar = "outerVar"; function inner() { var innerVar = "innerVar"; console.log(outerVar); console.log(innerVar); console.log(windowVar); } inner(); }
outer();
|
闭包
定义:即使外部函数已经不存在,也可以获取作用域链上变量的函数。
A closure is a function that keeps access to the variables from the scope where it was created, even when that scope has finished running.
对于下面这段代码,我们称f函数和变量a形成了闭包。
1 2 3 4 5 6 7 8 9 10
| function outer() { const a = 1; function f() { console.log(a); } return f; }
let f = outer(); f();
|
闭包可能会导致内存泄漏
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
|
function createLeakyTimer() { const largeData = new Array(1000000).fill('x');
setInterval(() => { console.log('timer running, data length:', largeData.length); }, 1000);
}
function createLeakyEventHandler() { const bigObject = { data: new Array(500000).fill('leak') };
document.getElementById('myButton').addEventListener('click', function () { console.log('clicked', bigObject.data.length); });
}
function createLeakyCache() { const cache = {};
return function (key, value) { cache[key] = value; return cache; }; }
function createLeakySubscriber() { const heavyPayload = new Array(100000).fill({ id: 1, name: 'leak' });
const EventEmitter = require('events'); const emitter = new EventEmitter();
emitter.on('data', function () { console.log(heavyPayload.length); });
return emitter; }
|
应用
闭包的应用是:可以封装一段代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| let a = 10; let b = 20;
function add(){ return a + b; }
function sub() { return a - b; }
let result1 = add(); let result2 = sub();
console.log(result1); console.log(result2);
|
改写为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| let calculatorModule = (function() {
let a = 10; let b = 20;
function add(){ return a + b; } function sub() { return a - b; }
return { add, sub } })();
let result1 = calculatorModule.add(); let result2 = calculatorModule.sub();
console.log(result1); console.log(result2);
console.log(a);
|