![8d1de6ea1b9dca4b04b79a1831d58f64.png](https://img-blog.csdnimg.cn/img_convert/8d1de6ea1b9dca4b04b79a1831d58f64.png)
前言
ECMAScript
变量是松散类型的,也就意味着变量可以用于保存任何数据的类型,而每个变量只不过是一个用于保存任意值的命名占位符。
有三个关键字可以声明变量:var
、let
(ES6
新增)、const
(ES6
新增)
var
var
关键字可以声明变量,我们可以定义一个变量不赋值,也可以定义变量的同时为这个变量赋值,还可以改变保存的值和改变值的类型,但是不推荐去改变值的类型,虽然这在 ECMAScript
中是完全有效的:
var message // undefined
var message1 = 1 // 1
message1 = 'abc' // 合法,但不推荐
var 声明作用域
1. 在函数内部定义一个变量时,这个变量会在函数退出时被销毁:
function test() {
var message = 1; // 局部变量
}
test();
console.log(message) // Uncaught ReferenceError: message is not defined
2. 在函数内部省略 var
操作符,可以创建一个全局变量:
function test() {
message = 1; // 全局变量
}
test()
console.log(message); // 1
在这个例子中,去掉了上面?例子中的 var
关键字,那么只要 test()
函数被调用了一次,就会自动定义 message
变量,并且可以在函数外部访问到这个变量。
⚠️ 虽然我们可以省略 var
操作符来定义全局变量,但是不推荐这么做,因为会造成困惑,很难维护。
3. 可使用 var
操作符一次定义多个变量:
var message = 1, age = null,
a = ‘123’, b = fasle;
上面例子中定义了 4
个变量,因为 ECMAScript
是松散类型的,所以使用不同数据类型初始化的变量可以用一条语句来声明。
var 声明提升
使用 var
关键字声明的变量会自动提升到函数作用顶部:
function test() {
console.log(message);
var message = 1
}
test() // undefined
上面 ? 例子中,我们打印 message
时没有报错,并且还打印出了 undefined
,这是因为 ECMAScript
在运行的时候把它看成等价于如下代码:
function test() {
var message;
console.log(message);
message = 1;
}
这就是变量提升,就是把所有变量声明都拉到函数作用域的顶部,并且因为此特性,我们反复声明同一个变量也是没有问题的:
function test() {
var message = 1;
var message = 2;
var message = 3;
console.log(message);
}
test(); // 3
let
let
是 ES6
语法,它与 var
的作用差不多,都是声明变量的,但还是有区别的:
作用域
1、let
声明的范围是块作用域,而 var
声明的范围是函数作用域
// 使用 var 在块级作用域中声明变量:
if (true) {
var name = 'Shinkai';
console.log(name) // Shinkai
}
console.log(name) // Shinkai
// 使用 let 在块级作用域中声明变量:
if (true) {
let age = 2;
console.log(age) // 2
}
console.log(age) // Uncaught ReferenceError: age is not defined
上面例子中,age
变量不能在 if
块外部被使用,因为它的作用域仅限于 if
这个块内部,而我们的块级作用域是函数作用域的自己,所以适用于 var
的作用域限制同样也适用于 let
。
2、let
不允许同一个作用域中出现多次声明同一个变量:
在使用 var
声明变量时,由于声明会被提升,JavaScript
引擎会自动将多余的声明在作用域顶部合并为一个声明。而 let
的作用域是块,所以不可能检查前面是否已经使用 let
声明过同名的变量。因此,重复声明会报错。
var name;
var name;
let age;
let age; // Uncaught SyntaxError: Identifier 'age' has already been declared
当然,我们可以在不同块作用域中,嵌套使用相同的标识符,因为同一个块中没有重复声明:
var name = 'abc';
console.log(name) // name
if (true){
var name = 'Shinkai';
console.log(name) // Shinkai
if (true) {
var name = 'xss'
console.log(name) // xss
}
}
let age = 1;
console.log(age) // 1
if (true) {
let age = 10;
console.log(age) // 10
if (true) {
let age = 18;
console.log(age) // 18
}
}
暂时性死区
let
与 var
的另一个重要区别就是 —— let
声明的变量不会在作用域中被提升。
// name 会被提升
console.log(name); // undefined
var name = 'Shinkai';
// age 不会被提升
console.log(age); // Uncaught ReferenceError: age is not defined
let age = 18;
在
let
声明之前的执行瞬间被称为“暂时性死区”,在此阶段引用任何后面才声明的变量都会抛出ReferenceError
。
全局声明
使用 let
声明的全局变量不会成为 window
对象的属性,而 var
声明的变量则会。
var name = "Shinkai";
let age = 18;
console.log(window.name) // "Shinkai"
console.log(window.age) // undefined
const
1、const
声明变量必须同时为其初始化
const age; // 报错:Uncaught SyntaxError: Missing initializer in const declaration
const age = 18;
2、const
声明的变量不允许修改
const age = 18;
age = 20; // 报错:Uncaught TypeError: Assignment to constant variable.
3、const
声明的限制只适用于它指向的变量的引用
// 对象
const pesron = {}
person.name = 'Shinkai'
// 数组
const nums = []
nums.push(1)
// 重新赋值就会报错
nums = [] // Uncaught TypeError: Assignment to constant variable.
上面例子其实就表明,如果是一个引用类型的变量,那么去对它进行一些列操作不会有问题,因为它始终指向同一个内存地址。但是若去改变它的引用地址,也就是重新赋值,就会报错。
总结
var
、let
、const
的区别
var
声明的变量会变量提升,而let
和const
不会。var
因为有变量提升,所以可以重复声明同一个变量,而let
和const
不允许这样操作。var
的作用域是函数作用域,而let
和const
都是块级作用域。let
和const
都有暂时性死区,也就是在作用域中,使用let
或const
声明之前执行的瞬间。const
声明变量必须同时初始化,否则会报错。const
声明的变量不可以改变,但是对象只要不改变的内存地址,可以对属性进行操作。
参考文献
JavaScript 高级程序设计(第4版)
结语
前端基础是非常重要的基石,我们需要去学习理解并掌握它,当然,如果有不正确的地方欢迎指出哦~
如果你喜欢我的文章,就请动动你可爱的指头,扫码关注一下下,我们一起学习一起进步,走向人生巅峰~!
![8ec5d744ff2faef85b0cad5a0ff683d4.gif](https://img-blog.csdnimg.cn/img_convert/8ec5d744ff2faef85b0cad5a0ff683d4.gif)