// 浏览器的 ES6 环境 functionf() { console.log('outside'); } (function () { if(false) { functionf() { console.log('inside'); } } f(); // TypeError: f is not a function }());
// 实际运行等同于 functionf() { console.log('outside'); } (function () { var f = undefined; if(false) { functionf() { console.log('inside'); } } f(); // TypeError: f is not a function }());
functionfn() { var a = 10; functionfn1() { var b = 20; console.log(a); // 10 functionfn2() { console.log(b); // 20 console.log(a); // 10 } fn2(); } fn1(); } fn(); console.log(b); // ReferenceError: b is not defined
词法作用域
词法作用域(也叫静态作用域),指变量的作用域是在代码编写阶段确定的,而不是在代码运行阶段确定的
JavaScript 是一种基于词法作用域的语言
1 2 3 4 5 6 7 8 9 10 11 12 13
// 无论 printNumber() 在哪里被调用,console.log(number)都会打印 10 let number = 10;
functionprintNumber() { console.log(number); }
functionlog() { let number = 20; printNumber(); }
log(); // 10
自由变量
自由变量是指,在当前作用域没有定义但被使用了的变量,即跨越了自己的作用域的变量
自由变量会向上级作用域,一层一层依次寻找,直至找到为止,如果直到全局作用域都没有找到该变量,则报错 xx is not defined
1 2 3 4 5 6 7 8 9 10 11 12 13 14
let a = 1; functionfn1() { let a1 = 100; functionfn2() { let a2 = 200; functionfn3() { let a3 = 300; console.log(a + a1 + a2 + a3); // 601 } fn3(); } fn2(); } fn1();
闭包
闭包是什么
简单地说,闭包是指能够访问自由变量的函数
通过闭包可以访问创建闭包时所处环境中的所有变量
创建闭包的方法
在一个函数的内部创建另一个函数,且在内部函数中引用了外部的变量,则创建了闭包
闭包不仅包含了函数的声明,还包含了在函数声明时该作用域中的所有变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
let n = 1; functionfn1() { let n = 999; add = function () { // add 为全局变量,其值是一个匿名函数,为一个闭包 n += 1; console.log(n); } functionfn2() { // fn2 是 fn1 的子函数,且作为 fn1 的返回值被返回,为一个闭包 console.log(n); } return fn2; }
let result = fn1(); // 将 fn1 的返回结果赋值给全局变量 result(); // 999 add(); // 1000 result(); // 1000
result 一共执行了两次,第一次的值是 999,第二次的值是 1000,说明了函数 fn1 中的局部变量 n 一直维持在内存中,并没有在 fn1 调用执行完之后被自动清除。