3.3 变量
ECMAScript 变量是 松散类型的,意思是变量可以用于保存任何类型的数据
每个变量只不过是一个用于保存任意值的命名占位符。
有3个关键字可以声明变量 :var const 和 let 。
其中 var 在 ECMAScript 的任意版本中都可以使用,而 const 和 let 只能在 ECMAScript 6 以及更新版本中使用。
3.3.1 var 关键字
要定义变量,可以使用 var 操作符(注意 var 是一个关键字),后面跟 变量名(即标识符),如:
var message;
这行代码定义了一个名为 message 的变量,可以用它保存任何类型的值。
不初始化的情况下,变量会保存一个特殊值 undefined ,当然也可以在定义变量的时候初始化变量,如:
var message = "hi";
这里 message 被定义为一个保存字符串值 hi 的变量。
像这样初始化变量不会将它标识为 字符串 ,只是一个简单的赋值而已。
随后,不仅可以改变保存的值,还可以改变保存值的类型:
var message = "hi";
message = 100; // 合法,但是不推荐这种做法!
在这个例子中,变量 message 首先被定义为保存一个字符串值 hi 的变量,然后又被重写为保存了数值 100 。
虽然不推荐改变 变量保存值 的类型,但这在 ECMAScript 中是完全有效的。
1 var 声明的作用域
关键的问题在于,使用 var 操作符定义的变量会成为包含它的函数的局部变量。比如:
使用 var 在函数的内部定义一个变量,意味着该变量会在函数退出时被销毁。
function test(){
var message = 'hi'; // 在函数内部定义的 var 变量,此时它是 局部变量
}
test();
console.log(message); // 程序会在该处报错,因为 message 变量是在函数内部
//定义的变量,属于 局部变量,它在随着 test() 执行完毕推出而被销毁,故在此处引用的时候会报错。
不过,在函数内部定义变量的时候,省略 var 操作符,可以创建一个全局变量,但是不推荐这样做,因为在局部域中定义全局变量会很难维护。
function test(){
message = 'hi'; // 定义了一个全局变量
}
test();
console.log(message); // 会正常答应 ‘ hi ’
//定义的变量,属于 局部变量,它在随着 test() 执行完毕推出而被销毁,故在此处引用的时候会报错。
去掉操作符 var 之后,message 变量就变成了一个 全局变量。只要函数调用一次,就会 定义这个变量,并且可以在函数外部访问该变量。
注意:在 严格模式 下,如果像这样给为声明的变量赋值,则会抛出 ReferenceError 。
如果需要定义多个变量,可以在一条语句中用英文状态下的逗号( , )分隔每个变量(及可选的初始化),例如:
var message = "hi",
found = false,
age = 29;
这里定义了3个变量。因为ECMAScript 是松散型的,所以使用不同数据类型初始化的变量可以放在一条语句中来声明。
插入 换行 和 空格 并不是必须的。这是为了方便阅卷和理解代码。
在 严格模式 下,不能定义名为:eval 和 arguments 的变量,否则会导致 语法错误。
2 var 声明提升
使用 var 时,下面代码不会报错。
这是因为使用这个 关键字 声明的 变量会自动提升到函数作用域 顶部。
function foo(){
console.log(age);
var age = 26;
}
foo(); // 打印结果为 undefined
之所以这段代码不会报错,是因为 ECMAScript 运行时把 age 变量看成 如下等价代码了:
function foo(){
var age; // 定义变量不初始化的时候,系统会默认该变量为 undefined
console.log(age);
var age = 26;
}
foo(); // 打印结果为 undefined
这里就是所谓的 ” 提升 “ ( hoist),也就是把所有变量声明都放在函数作用域的顶部。
此为,反复多次使用 var 声明同一个变量也是没有问题的:
function foo(){
var age = 16;
var age = 26;
var age = 36;
console.log(age);
}
foo(); // 打印结果为 36,因为JS代码是顺序执行的,所以以 最后出现的 赋值 为准。