1.const
-
const 声明一个只读的常量,一旦声明,常量的值就不能改变
-
const 用于声明一个或多个常量,声明时必须进行初始化,且初始化后值不可再修改:
-
const 的本质: const 定义的变量并非常量,并非不可变,它定义了一个常量引用一个值。使用 const 定义的对象或者数组,其实是可变的。
const value=1;
value=2;//不能修改,Uncaught TypeError: Assignment to constant variable.
当声明复杂数据类型的时候,物理指针不可改变,但是可以改变数据内的属性值,以及可以给数据添加新属性等操作
数组:
// 创建常量对象
const car = {type:"Fiat", model:"500", color:"white"};
// 修改属性:
car.color = "red";
// 添加属性
car.owner = "Johnson";
console.log(car.color);//red
console.log(car.owner);//Johnson
但是我们不能对常量对象重新赋值:
const cars = ["Saab", "Volvo", "BMW"];
cars = ["Toyota", "Volvo", "Audi"]; // 错误
2.let
let用来声明变量,并且会在当前作用域形成代码块
代码块:{}是一个代码块
{
let value=1;
}
使用let声明的变量,只能在当前代码块中访问,类似函数作用域。
{
let value=1;
console.log(value)//1
}
console.log(value)//Uncaught ReferenceError: value is not defined
let声明的变量不会被提升
function fn1(){
console.log(a)
let a=2;
}
fn1();//报错,Cannot access 'a' before initialization
//var 声明的变量会被提升
function fn2(){
console.log(a)
var a=1;
}
fn2();//undefined,因为a被变量提升了,相当于先var a,再console.log(a),最后a=1
function fn3(){
a=1;
console.log(a)
var a;//变量提升
}
fn3()//1
for循环中使用let定义变量
for (var i = 0; i < 3; i++) {
for (var i = 0; i < 3; i++) {
console.log(i)//只打印了0,1,2,因为i为全局变量,第二层for循环结束i为3,不能再满足第一层for循环了
}
}
for (let i = 0; i < 3; i++) {
for (let i = 0; i < 3; i++) {
console.log(i)//打印三次0,1,2,因为let是块级作用域,第二层i并不会影响第一层i
}
}
for (var i = 0; i < elements.length; i++) {
elements[i].onclick = function () {
console.log(i);
}
}
elements[0].onclick() //3
elements[1].onclick() //打印出来为3,,因为i是全局的,最终i为3
//可以通过闭包解决这个问题
for (var i = 0; i < elements.length; i++) {
elements[i].onclick = (function (i) {
console.log(i);
})(i)
}
//通过块级作用域解决
for (let i = 0; i < elements.length; i++) {
elements[i].onclick = function () {
console.log(i);
}
}
注:使用let/const关键字声明变量的for循环,除了会创建块级作用域,let/const还会将它绑定到每个循环中,确保对上个循环结束时候的值进行重新赋值,简而言之就是每次循环都会声明一次(对比var声明的for循环只会声明一次)
本质:
const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了
3.总结(var,let,const)
-
let 声明的变量只在 let 命令所在的代码块({})内有效。
-
使用 var 关键字声明的变量不具备块级作用域的特性,它在 {} 外依然能被访问到。
-
let 声明的变量只在 let 命令所在的代码块 {} 内有效,在 {} 之外不能访问,var作为局部变量时在整个封闭的函数內可以使用。
-
使用var关键字声明的全局作用域变量属于window对象。
-
使用let关键字声明的全局作用域变量不属于window对象。
-
使用var关键字声明的变量在任何地方都可以修改。
-
在相同的作用域或块级作用域中,不能使用let关键字来重置var关键字声明的变量,不能使用let关键字来重置let关键字声明的变量。
-
let关键字在不同作用域,或不用块级作用域中是可以重新声明赋值的。
-
在相同的作用域或块级作用域中,不能使用const关键字来重置var和let关键字声明的变量,不能使用const关键字来重置const关键字声明的变量
-
const 关键字在不同作用域,或不同块级作用域中是可以重新声明赋值的:
-
var关键字定义的变量可以先使用后声明。
-
let关键字定义的变量需要先声明再使用。
-
const关键字定义的常量,声明时必须进行初始化,且初始化后不可再修改。