let 和 const
声明的 let 变量只作于于代码块内部,外部访问会报变量没有被定义的错误。
而 var 变量在没有声明时访问,只会返回 undefined,并不会报错。
什么叫代码块内部昵?简单来说就是被{}所包裹的内容。
当在()中声明的 let 变量,也只能在它后面的{}中访问。即{}可以看做 let 作用域的子作用域。
js
var a = 1;
{
var b = 2;
let c = 3;
}
//或
for (var b1 = 1; b1 <= 3; b1++) {
console.log(b1);
}
for (let c1 = 1; c1 <= 3; c1++) {
console.log(c1);
}
//这里的a、b、b1都能在外部访问。而c、c1只能在内部访问。变量提升:当声明的 var 变量,变量会自动提升为全局变量。不管是在函数外部还是在函数内部,只要在定义之后都可以访问。
js
for (var b1 = 1; b1 <= 3; b1++) {
console.log(b1);
console.log(b2);
for (var b2 = 1; b2 <= 3; b2++) {
console.log(b1);
console.log(b2);
}
console.log("------------------------------------");
}
console.log(b1);
console.log(b2);
//这里都能访问b1,b2。只是在内部第一层第一次访问b2时会返回undifined。对应的用 let 声明:
js
for (let c1 = 1; c1 <= 3; c1++) {
console.log(c1);
for (let c2 = 1; c2 <= 3; c2++) {
console.log(c1);
console.log(c2);
}
console.log("------------------------------------");
}
//这里内部第二层可以访问到c1,也就是说这里的作用域包括了它的子作用域。var 变量名相同时:
同层:
js
var a = 1;
var a = 2;
//a=2,即他们共享内存地址。不同层:
js
for (var b1 = 1; b1 <= 3; b1++) {
console.log(b1);
console.log(b1);
for (var b1 = 1; b1 <= 3; b1++) {
console.log(b1);
console.log(b1);
}
console.log("------------------------------------");
}
console.log(b1);
console.log(b1);
//第一层b1和第二层b2共享内存地址。
//这里外部循环只会执行一次,即内部循环跳出时,外部的第二次循环b2的值已经是4。
//由于for循环特性,依然会执行b++,所以最后输出的b1的值为5let 变量名相同时:
同层:
js
let a = 1;
let a = 2;
console.log(a);
//会报错,提示'a'has already been declared不同层:
js
for (let c1 = 1; c1 <= 3; c1++) {
console.log(c1);
for (let c1 = 1; c1 <= 3; c1++) {
console.log(c1);
console.log(c1);
}
console.log("------------------------------------");
}
//
//第一层c1和第二层c1有单独的内存地址。
//这里第一层和第二层的c1名字虽然是一样的,但是在自己的块内只访问自己的变量。
//即第一层只访问第一层的变量,第二层访问第二层的变量。相互之间不影响。var 变量于 let 变量同名时:
同层:
js
var b = 1;
let b = 7;
console.log(b);
//会报错,'b' has already been declared
let b = 1;
var b = 7;
//会报错,'b' has already been declared
for (let b1 = 1; b1 <= 3; b1++) {
var b1 = 7;
console.log(b1);
}
//这样写也会报错
for (var b1 = 1; b1 <= 3; b1++) {
let b1 = 7;
console.log(b1);
}
//按理来说,这样也应该叫同层,会报错。但是不会,会正常的输出三个7。不同层:
js
var b = 1;
for (let b = 1; b <= 3; b++) {
console.log(b);
}
console.log(b);
//正常输出
let b = 1;
for (var b = 1; b <= 3; b++) {
console.log(b);
}
console.log(b);
//会报错,'b' has already been declared
for (var b1 = 1; b1 <= 3; b1++) {
let b1 = 7;
console.log(b1);
}
console.log(b1);
//正常输出
for (let b1 = 1; b1 <= 3; b1++) {
var b1 = 7;
console.log(b1);
}
//会报错,'b' has already been declared综上述,可得出结论:
- for()里面的域可以看作是它外部域的子域,是它后面{}的父域。
- var 可以设置同名变量,因为会自动提升为全局变量,共享内存地址。
- let 同层不可以设置同名变量。
- var 和 let 变量名相同时,不可以在同一层。
- var 和 let 变量名相同时,var 变量可以在 let 变量的外层,而 let 变量不能在 var 变量的外层。
const
const:
- 实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。
- 对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。
- 但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const 只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了
简单来说就是对于简单数据类型,如果用 const 声明之后是不可以更改的,但是如果用 const 声明的是对象或者数组是可以更改的。
const 为常量时不可修改,声明时必须要初始化。
js
const a = 1;
a = 2; //报错const 为对象或数组时:
js
const a = ["1", "2"];
a.push("3");
console.log(a);
//可以对数组进行修改
function f() {
console.log("1");
}
const a = f();
function f() {
console.log("2");
}
//这里输出"2",可以对函数对象修改函数作用域
ES6 规定,块级作用域之中,函数声明语句的行为类似于 let,在块级作用域之外不可引用:
js
function f() {
console.log("f0");
function f() {
console.log("f01");
}
f();
}
f();
//输出"f0" "f01"
function f() {
console.log("f0");
function f1() {
console.log("f1");
}
f1();
}
f();
f1(); //到这里的时候报错,外部不能访问内部函数。