作用域

语法作用域:在编写代码时给代码定义的附属作用域在运行时保持不变。(使用 with 可以改变, eval 可以插入代码进行欺骗)

函数作用域:创建函数时会创建一个可用于变量绑定的作用域

块作用域:JavaScript if(){ .. } for(){ .. } 不会创建块作用域。仅 try/catch ES3+ 具有块作用域。在 ES6 中可以使用 let 将变量定义绑定到 { .. } 块中。(但是不会进行声明提升)

立即执行函数表达式:函数声明绑定在所处作用域中,而函数表达式将函数名隐藏在自身函数表达式中({ .. }部分)。

函数声明 function(){ .. },函数表达式 (function(){ .. })() 立即执行函数表达式,setTimeout(function(){..},1000) 匿名函数表达式

闭包

将函数类型的值进行传递,它都会持有对原始定义作用域的引用。

  1. function wait(message) {
  2. setTimeout(function timer() {
  3. console.log(message);
  4. }, 1000);
  5. }
  6. wait("Hello closure!");

将一个内部函数(名为 timer )传递给 setTimeout(..)。timer 具有涵盖 wait(..)作用域的闭包,因此还保有对变量 message 的引用。
wait(..) 执行 1000 毫秒后,它的内部作用域不会消失,timer 函数依然保有 wait(..) 作用域的闭包。

闭包与循环

  1. for (var i = 0; i != 5; i++) {
  2. setTimeout(function timer() {
  3. console.log(i);
  4. }, 1000);
  5. }
  6. //Output: 5 5 5 5 5
  1. for (var i = 0; i != 5; i++) {
  2. (function () {
  3. setTimeout(function timer() {
  4. console.log(i);
  5. }, 1000);
  6. })();
  7. }
  8. //Output: 5 5 5 5 5
  1. for (var i = 0; i != 5; i++) {
  2. (function (j) {
  3. setTimeout(function timer() {
  4. console.log(j);
  5. }, 1000);
  6. })(i);
  7. }
  8. //Output: 0 1 2 3 4
  1. for (var i = 0; i != 5; i++) {
  2. let j = i;
  3. setTimeout(function timer() {
  4. console.log(j);
  5. }, 1000);
  6. }
  7. //Output: 0 1 2 3 4
  1. //let 循环:let 可以将声明绑定在 for(){ .. } 内部,并且在每次迭代都进行重新绑定。
  2. for (let i = 0; i != 5; i++) {
  3. setTimeout(function timer() {
  4. console.log(i);
  5. }, 1000);
  6. }
  7. //Output: 0 1 2 3 4