在js中有三种声明变量的方式,分别为var,let,const。那么它们三个有什么区别呢?
var关键字
要定义变量,可以使用var操作符(注意,var是一个关键字)
例如:
var message
console.log(message)
就是定义了一个变量message,因为没有赋值,所以它的值默认为undefined。
我们来运行一下,因为输出为undefined,所以message确实是undefined。
var声明作用域
在函数内部也是可以创建全局变量的 正常情况下
function msg() {
var message = '123'
}
msg()
console.log(message)
输出,因为在全局找不到message
如果在函数内部不写var声明变量
function msg() {
message = '123'
}
msg()
console.log(message)
因为去掉var关键字之后,message就变成了全局变量,所以只要调用一次函数就能访问到
虽然可以省略var操作符定义全局变量,但是不推荐这么做。
如果想同时定义多个变量,,可以用逗号隔开
var message = 'hi',
found = false,
age = 29
变量提升
如果我们写下这段代码
function foo() {
console.log(message)
}
foo()
会报这样的错误
可是,当我们输入这段代码时
function foo() {
console.log(message)
var message = 'hi'
}
foo()
输出
它等同于这段代码
function foo() {
var message
console.log(message)
message = 'hi'
}
foo()
这就是所谓的变量提升,也是把所有的变量声明都拉到顶部
let声明
let和var差不多,但还是有一些非常重要的区别。最明显的区别就是let声明块作用域,而var声明函数作用域
if(true){
var name = 'name';
console.log(name);
}
console.log(name);
输出为
而用let声明
if(true){
let age = 'name';
console.log(age);
}
console.log(age);
输出
因为let声明的是块级作用域,所以只在if里面有效,所以外面找不到age。
let还有一个特点,就是不能重复声明一个变量
var age = 1;
var age = 2;
console.log(age);
输出为
let age = 1;
let age = 2;
console.log(age);
输出为,标识符age已经被声明过了
但如果两个let在不同的块作用域就不一样了。
let age = 1;
if(true){
let age = 2;
console.log('内',age);
}
console.log('外',age);
输出为
用let还可以在实际开发中防止声明冗余
let age = 1;
var age = 2;
报错
var age = 1;
let age = 2;
也同样报错
1.暂时性死区
这个和变量提升有关,比如用var
console.log(age);
var age = 1;
相当于
var age
console.log(age);
age = 1;
输出undefined
可如果是let
console.log(age);
let age = 1;
直接报错
2.全局声明
var声明变量会成为window的属性,比如
var age = 1;
console.log(window.age);
输出为1
如果是let声明
let age = 1;
console.log(window.age);
就是undefined
3.条件声明
var声明变量会提升变量,在作用域顶部合并为一个声明,但是let作用域是块,所以不可能检查前面let是否声明过同一个变量。比如下面的代码就不会报错
<script>
let age = 1;
var name = 'name'
</script>
<script>
var name = 2
</script>
而一旦用let在下面新声明一个age
<script>
let age = 1;
var name = 'name'
</script>
<script>
var name = 2
let age = 2
</script>
就会报错
4.for循环中的let声明
在let出现之前,var会渗透到外面
for(var i = 0; i < 5; i++){}
console.log(i);
输出为
这样很容易造成变量污染,而用let则不会出现这种情况
for(let i = 0; i < 5; i++){}
console.log(i);
还有一个区别,就是如果for循环内部有异步的时候
for(var i = 0; i < 5; i++){
setTimeout(() => {
console.log(i);
}, 0);
}
你以为会输出0、1、2、3、4
实际上会输出5、5、5、5、5
而用let
for(let i = 0; i < 5; i++){
setTimeout(() => {
console.log(i);
}, 0);
}
输出为
这种适合所有的for循环,包括for-in和for-of
for-in和for-of我后面会具体介绍
3.const声明
const和let差不多,只不过const声明的是常量,就是声明后不可改变(除了对象和数组,这个后面说)
const age = 35;
age = 26
这样会报错,因为给常量age赋值
也不允许重复声明
const age = 35;
const age = 26
声明作用域也是块
const age = 35;
if(true){
const age = 26
console.log('内',age);
}
console.log('外',age);
但如果声明的是对象
const age = {};
age.name = '你好'
这样就不会报错,因为const声明的限制只适用于它指向的变量的引用。换句话说,就是const指向的是一个对象,那么修改对象内部不违反const限制;数组同理
关于for-in和for-of
对于数组来说,for-in获取的是下标,for-of获取的是内容
const age = ['你','我','他','它'];
for(var i in age){
console.log('for-in',i);
}
for(var i of name){
console.log('for-of',i);
}
输出为
如果变量是对象,for-in
const age = {
name: '123',
age: 46,
title: '789'
};
for(var i in age){
console.log('for-in',i);
}
输出为
for-of
const age = {
name: '123',
age: 46,
title: '789'
};
for(var i of age){
console.log('for-of',i);
}
报错