const
必须声明赋值一气呵成,不能先声明,后面再赋值会报错;
const a;
a=1;//报错
初始化后不能再给这个常量重新赋值(即使改过的值和之前一样也不行)
const a =1;
a=1//报错
const a = 1;
const fn = () => {
// a = 2;//报错,不能对全局常量a重新赋值
// const a = 2;//不报错,作用域的遮蔽,这两个a不是一个a
}
fn();
不知道用const还是let时,先用const(可能该值比较重要不能修改),如果该值确定要修改,可以等报错(前面用const初始化后再改这个常量的值会报错)再把原来的const改回let;
const声明的常量允许在不重新赋值的情况下修改它的值
const person = {
age:18,
sex:'男'
}
//报错,通过重新赋值的方式会报错;
person = {
age:18,
sex:'女'
}
//不报错,能正常修改
person.sex = '女';
let、const、var区别
重复声明:已经存在的变量(不论是通过上面方式存在的,形参也算)又声明了一遍,var允许重复声明,let和const不允许;不允许重复声明指的是不能在同一作用域重复声明;
function fn(a) {
let a = 1;//报错,const一样就不举例了
}
fn();
变量提升:var会将变量的声明提升到当前作用域顶部,let和const不存在提升;
console.log(a);
var a = 1;
//相当于以下
var a;
console.log(a);
a = 1;
暂时性死区:只要作用域内存在let和const,他们所声明的变量或常量就自动‘绑定’这个作用域,不受外部作用域的影响;
let a = 2;
function fn() {
console.log(a);//报错,程序执行之前,作用域里let声明的a就自动‘绑定’这个作用域,打印a时,在函数作用域就算没找到a(因为let不存在提升),也不会顺着作用域链找外面的a
let a = 1;//如果没有这句话,会顺着作用域链去外面找a
}
fn();
window对象的属性和方法:全局作用域中的var声明的变量,function声明的函数自动成为window的属性和方法;如果var声明的变量值是函数(函数表达式形式),这个变量会成为window的方法;let和const不会
var a = 1;
console.log(window.a)//1
function fn() {
//...
}
console.log(window.fn ===fn)//true
//-------------------------------------------------
let b =1;
console.log(window.b)//undefined
const fn1 = function() {
//...
}
console.log(window.fn1)//undefined
块级作用域:var没有块级作用域,let和const有块级作用域
{
var a = 1;
let b = 2;
}
console.log(a);//1
console.log(b);//报错,let所声明的变量,只在let命令所在的代码块内有效
for (let i = 0; i < 10; i++) {
// ...
}
console.log(i);//报错
var a =[];
for(var i =0; i <10; i++){
a[i]=function(){//代码执a[i]的时候,会查找i的值,随着for循环,分别是a[0],a[1],a[2]...
console.log(i);//函数不调用代码不执行,不会去查找i的值
};
}
a[6](); // 10(打印i,全局只有一个i,所以是10)
//每循环一次,就会形成一个块级作用域,每次循环都相当于重新let声明一次i,因为 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 6
console.log(i)//报错,数组每一项依然能够打印出不同的值,但是不能在外部访问变量 i 的值。
//或者说,不能访问到对用户而言的 i,用户能使用的 i 变量已经被销毁了。
//数组每一项的调用却都依然可以正常打印。数组中这些不同的 i 应该被浏览器用特殊的方法保存起来了,并且拒绝我们直接访问。
//把循环拆解相当于:
//第一次:let i = 0; i < 10; {let i = 0;a[0] = function () {console.log(i);} i++
//第二次: i < 10; {let i = 1;a[1] = function () {console.log(i);}} i++
//JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。
//第三次: i < 10; {let i = 2;a[2] = function () {console.log(i);}} i++
//...第七次: i < 10; {let i = 6;a[6] = function () {console.log(i);}} i++
//--------------------------------------
// (let i = 0; i < 10; i++) 设置循环变量的这部分是一个父作用域;
//----------------------------------
// {
// a[i] = function () {
// console.log(i);
// }
// }//循环体内部是一个单独的子作用域。
//---------------以下验证------------------
for (let i = 0; i < 3; i++) {
let i = 'abc';
console.log(i);
}
// abc
// abc
// abc
//上面代码正确运行,输出了 3 次abc。这表明函数内部的变量i与循环变量i不在同一个作用域,有各自单独的作用域(同一个作用域不可使用 let 重复声明同一个变量)。
![](https://img-blog.csdnimg.cn/img_convert/afb5faf5b52f9a2d82d31b1c6493f7ad.png)
![](https://img-blog.csdnimg.cn/img_convert/a2cfe1da97baf95a8dfbfb59000de221.png)
这种每次迭代声明一个独立变量实例的行为同样适用于其他for循环,比如for in 、for of
还有哪些块级作用域,{}、if(){}、do{}while()、while(){}、switch(){}、for in 、for of
函数的{}是函数作用域,对象的{}不构成块级作用域
这个作用域只针对于let/const声明的变量常量是块级作用域,该变量常量只在这个作用域内有效;
作用域分为三种:块级,函数,全局;
一起学习,如有错误还请指出~