🗑 JavaScript 关于使用 var 声明变量
在 JavaScript 还没有使用 let
声明变量之前,一般使用 var
声明变量。但是 var
声明变量有许多知名
# var
中没有「块级作用域」
用 var
声明的变量,不是 函数作用域 就是 全局作用域,它们在代码块外也是可见的,所以不存在 块级作用域的说法。
🌰 例子 / 对于 if
代码块:
if(true) {
var test = true
}
console.log(test) // true
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)
2
3
4
5
6
在
for
代码块中,使用var
声明的变量同样相当于是 全局变量 。
如果一个代码块位于函数内部,那么 var
声明的变量的作用域将为函数作用域。
🌰 例子 / 函数作用域:
function sayHi() {
if(true) {
var phrase = 'hello'
}
console.log(phrase)
}
sayHi()
console.log(phrase) // 函数内部的变量对外不可见
2
3
4
5
6
7
8
9
10
var
穿透了if
,for
和其它代码块。这是因为在早期的 JavaScript 中,块没有词法环境,而var
就是这个时期的代表之一。
# var
允许重新变量的重新声明
在
let
声明变量时,在同一作用域下将同一个变量声明两次,则会出现错误。
使用 var
,可以重复声明一个变量,不管多少次都行。如果对一个已经声明的变量使用 var
,这条新的声明语句会被忽略 var
,即覆盖上一次声明的内容:
var user = "Pete";
var user = "John"; // 这个 "var" 无效(因为变量已经声明过了)
// ……不会触发错误
alert(user); // John
2
3
4
5
6
# var
可以在声明前被使用 / 变量提升
当函数开始的时候,就会处理 var
声明(脚本启动对应全局变量)。 var
声明的变量会在函数开头被定义,与它在代码中定义的位置无关(这里不考虑定义在嵌套函数中的情况)。
🌰 例子:
function sayHi() {
phrase = "Hello";
console.log(phrase);
var phrase;
}
sayHi();
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();
2
3
4
5
6
7
8
这个例子中,
if (false)
分支永远都不会执行,但没关系,它里面的var
在函数刚开始时就被处理了,所以在执行(*)
那行代码时,变量是存在的。
变量提升(hoisting /rasing) ,所有的 var
都被「提升」到了函数的顶部。声明会被提升,但是赋值不会。
🌰 例子 :
function sayHi(){
console.log(phrase)
var phrase = 'hello'
}
sayHi() // undefined
2
3
4
5
var phrase = "Hello"
这行代码包含两个行为:
- 使用
var
声明变量。- 使用
=
给变量赋值。但是提升只有声明会被提升,而赋值不会,赋值操作始终是在赋值出现的地方才起作用,所以相当于:
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
})();
2
3
4
这里,创建了一个函数表达式并立即调用。因此,代码立即执行并拥有了自己的私有变量。