目录

🗑 JavaScript 关于使用 var 声明变量

在 JavaScript 还没有使用 let 声明变量之前,一般使用 var 声明变量。但是 var 声明变量有许多知名

# var 中没有「块级作用域」

var 声明的变量,不是 函数作用域 就是 全局作用域,它们在代码块外也是可见的,所以不存在 块级作用域的说法。

🌰 例子 / 对于 if 代码块:

if(true) {
  var test = true
}

console.log(test) // true 
1
2
3
4
5

由于 var 会忽略代码块,所以声明了 全局变量 test 。如果使用 let 则仅 if 代码块内部中可见。

🌰 例子 / 对于 for 代码块:

for(var i = 0; i < 10; i++) {
  var one = 1
}

console.log(i)
console.log(one)
1
2
3
4
5
6

for 代码块中,使用 var 声明的变量同样相当于是 全局变量

如果一个代码块位于函数内部,那么 var 声明的变量的作用域将为函数作用域。

🌰 例子 / 函数作用域:

function sayHi() {
  if(true) {
    var phrase = 'hello'
  }
  
  console.log(phrase)
}

sayHi()
console.log(phrase) // 函数内部的变量对外不可见
1
2
3
4
5
6
7
8
9
10

var 穿透了 iffor 和其它代码块。这是因为在早期的 JavaScript 中,块没有词法环境,而 var 就是这个时期的代表之一。

# var 允许重新变量的重新声明

let 声明变量时,在同一作用域下将同一个变量声明两次,则会出现错误。

使用 var ,可以重复声明一个变量,不管多少次都行。如果对一个已经声明的变量使用 var ,这条新的声明语句会被忽略 var ,即覆盖上一次声明的内容:

var user = "Pete";

var user = "John"; // 这个 "var" 无效(因为变量已经声明过了)
// ……不会触发错误

alert(user); // John
1
2
3
4
5
6

# var 可以在声明前被使用 / 变量提升

当函数开始的时候,就会处理 var 声明(脚本启动对应全局变量)。 var 声明的变量会在函数开头被定义,与它在代码中定义的位置无关(这里不考虑定义在嵌套函数中的情况)。

🌰 例子:

function sayHi() {
  phrase = "Hello";
  console.log(phrase);
  var phrase;
}
sayHi();
1
2
3
4
5
6

由于 var 会被在函数的开头定义,所以相当于:

function sayHi() {
  var phrase;
  phrase = "Hello";
  console.log(phrase);
}
1
2
3
4
5

🌰 例子 / 在 if 中:

function sayHi() {
  phrase = "Hello"; // (*)
  if (false) {
    var phrase;
  }
  alert(phrase);
}
sayHi();
1
2
3
4
5
6
7
8

这个例子中, if (false) 分支永远都不会执行,但没关系,它里面的 var 在函数刚开始时就被处理了,所以在执行 (*) 那行代码时,变量是存在的。

变量提升(hoisting /rasing) ,所有的 var 都被「提升」到了函数的顶部。声明会被提升,但是赋值不会。

🌰 例子 :

function sayHi(){
  console.log(phrase)
  var phrase = 'hello'
}
sayHi() // undefined
1
2
3
4
5

var phrase = "Hello" 这行代码包含两个行为:

  1. 使用 var 声明变量。
  2. 使用 = 给变量赋值。

但是提升只有声明会被提升,而赋值不会,赋值操作始终是在赋值出现的地方才起作用,所以相当于:

function sayHi() {
  var phrase; // 在函数刚开始时进行变量声明
  alert(phrase); // undefined
  phrase = "Hello"; // ……赋值 — 当程序执行到这一行时。
}
1
2
3
4
5

var 声明可以在函数开头处理,所以可以在任何地方引用。但是,不赋值之前都是为 undefined ,所以使用变量之前最好要先被赋值。

# 「IIFE」

因为 var 声明的变量没有 块级作用域,为了实现类似 块级作用域的效果,程序员们就发明 「立即调用函数表达式(immediately-invoked function expressions,IIFE)」利用了函数作用域的特性。

现在的脚本中基本不会使用 IFFE 了。

🌰 例子:

(function() {
  var message = "Hello";
  alert(message); // Hello
})();
1
2
3
4

这里,创建了一个函数表达式并立即调用。因此,代码立即执行并拥有了自己的私有变量。

📢 上次更新: 2022/09/02, 10:18:16