var与let、const的区别
什么是变量提升?
JavaScript 中,函数及变量的声明都将被提升到函数的最顶部。
JavaScript 中,变量可以在使用后声明,也就是变量可以先使用再声明。
一)var声明变量存在变量提升,let和const不存在变量提升
console.log(a); // undefined ===> a已声明还没赋值,默认得到undefined值
var a = 100;
console.log(b); // 报错:b is not defined ===> 找不到b这个变量
let b = 10;
console.log(c); // 报错:c is not defined ===> 找不到c这个变量
const c = 10;
再来看这段代码
//代码 代码哈哈
function fn() {
//var a
if (true) {
console.log(a + ' now')
}
else {
var a = 1
console.log(2)
}
}
fn() // a -> undefined
我们发现不执行的代码也会影响会执行的代码,因为var a会提升到if语句的前面
需要注意的是:
undefined
可以翻译为不明确,not defined
可以翻译为未定义
在Java中变量的分为全局变量(成员变量)或者局部变量,在方法体中定义的变量都是局部变量,否则是全局变量(即在方法体外,在类中定义的变量)
在JavaScript中,在方法体外外用var定义的变量其它方法可以共享,在方法中用var定义的变量只有该方法内生效。
二)let、const都是块级局部变量
顾名思义,就是只在当前代码块起作用
{
let a = 1
}
console.log(a) // undefined
const 的特性和 let 完全一样,不同的只是
1)声明时候必须赋值
const a
编译器报错
控制台报错
SyntaxError: Missing initializer in const declaration
2)只能进行一次赋值,即声明后不能再修改
const a=1
a=2
编译器报错
控制台报错
TypeError: Assignment to constant variable.
3)如果声明的是复合类型数据,可以修改其属性
三)同一作用域下let和const不能声明同名变量,而var可以
const a =2
const a=1
SyntaxError: Identifier 'b' has already been declared
面试题
简单的Demo
for (let i = 0; i < 5; i++) {
console.log(i)
}
上面的代码我们知道打印结果是 0, 1, 2, 3, 4,但是你们有没有想过这个变量i的作用域到底是什么呢?
有人说在这个for循环里呀,但是我这里想说的是这个i作用域是在括号()里。正常的代码是这样的:
1.首先这个变量_i的作用域是在()里才有效的,循环体里是不能访问到_i的
2.每次循环的时候创建一个i变量,将括号里的_i赋值到变量i上
3.最后i++后再将变量i的值赋值回_i上
当然这个过程是很复杂的,可以用下面代码理解,但是JS的实现机制是很复杂的,这里想要说明的let i的作用域有时候并不是我们所理解的那样的。
for (let _i = 0; i < 5; i++) {
let i = _i
console.log(i)
// i++ 先做
_i = i
}
JavaScript中let、const、var 的区别
在ES5中,声明变量只有var和function两种形式。但是因为var声明的变量会有一定的缺点(内层变量可能覆盖外层变量的问题以及用来计数的循环变量泄露为全局变量,下面有介绍),ES6提出了使用let和const声明变量,弥补了ES5中var的缺点。
————————————————————————————————————————
————————————————————————————————————————
————————————————————————————————————————
————————————————————————————————————————
目录
1、是否存在变量提升?
var
声明的变量存在变量提升(将变量提升到当前作用域的顶部)。- 即变量可以在声明之前调用,值为
undefined
。 let
和const
不存在变量提升。- 即它们所声明的变量一定要在声明后使用,否则报
ReferenceError
错。
console.log(f) //undefined
var f = 1 ;
console.log(g) //ReferenceError: g is not defined
let g = 2;
console.log(h) //ReferenceError: g is not defined
const h = 2;
2、是否存在暂时性死区?
let
和const
存在暂时性死区。即只要块级作用域内存在let
命令,它所声明的变量就“绑定”(binding)
这个区域,不再受外部的影响。
var tmp = 123;
if (true) {
tmp = 'abc'; // ReferenceError
let tmp;
}
- 以上代码if后面{}形成了块级作用域,由于使用let声明了tmp,则这个变量就绑定了块区域,在声明之前使用,会报错。
在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称
TDZ)。总之,暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。
3、是否允许重复声明变量?
var
允许重复声明变量。let
和const
在同一作用域不允许重复声明变量。
var f = 4;
var f = 5;
console.log(5) //5
let g = 6;
let g = 7;
console.log(7) //SyntaxError: Identifier 'g' has already been declared
const h = 8;
const h = 9;
console.log(h) //SyntaxError: Identifier 'g' has already been declared
4、是否存在块级作用域?
4.是否存在块级作用域?
- var不存在块级作用域。
- let和const存在块级作用域。
什么是块级作用域:
ES5中作用域有:全局作用域、函数作用域。没有块作用域的概念。因此也有一系列的问题。
1、内层变量可能覆盖外层变量的问题
var a = 2;
function fun(){
console.log(a) //undefined
if(false){
var a = 3;//变量提升带来的,尽管存在块级作用域,但是var声明的变量会跨越这个域。
}
}
fun()
2、用来计数的循环变量泄露为全局变量。
var s = 'hello';
for (var i = 0; i < s.length; i++) {
console.log(s[i]);
}
console.log(i); // 5 i循环结束后,泄露成了全局变量
ECMAScript 6(简称ES6)中新增了块级作用域。块作用域由{ }包括,if语句和for语句里面的{ }也属于块作用域。
1、解决内层变量可能覆盖外层变量的问题
var b = 2;
function fun1(){
console.log(b) //2 访问的外层变量
if(false){
let b = 3;//不存在变量提升,变量存在于块级作用域之中。
}
}
fun1()
2、解决用来计数的循环变量泄露为全局变量。
var s1 = 'hello';
for (let j = 0; j < s1.length; j++) {
console.log(s1[j]); //j存在于块级作用域之中,和其绑定
}
console.log(j); // 报错 j is not defined
5、 是否能修改声明的变量?
————————————————————————
3w
5. 是否能修改声明的变量?
var和let可以。
const声明一个只读的常量。一旦声明,常量的值就不能改变。const声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值。
const f = 10;
// f= 11;
// console.log(f) //报错 不能进行重复声明
const obj = {
name: ‘小明’,
age: 18
}
obj.age = 20
console.log(obj) //{ name: ‘小明’, age: 20 }
//const声明常量,不允许对变量重新赋值。对于引用类型的值而言,只要在栈内存保存的地址值不变即可。