目录:
-
块级绑定、变量提升、暂时性死区;
-
var 声明方式;
-
let 声明方式;
-
const 声明方式;
-
循环内的块级绑定;
-
作用区别总结;
1、块级作用域、变量提升、暂时性死区
在讲声明方式之前,我们先了解几个基本概念,从而更好的理解这几个声明方式。
(1)块级作用域:块级声明也就是让所声明的变量在指定的块的作用域外无法被访问.块级作用域(词法作用域),在一个函数内部或者在{ }内部。
(2)变量提升:如果我们使用 var 声明变量,如果在函数内,不管我写在什么地方,都会被视为写在函数顶部,如果不在函数内,则视为全局作用域的顶部,就是所谓的变量提升。
(3)暂时性死区:使用let , const 声明的变量,在达到声明之前.都是无法访问的.就算是相对安全的操作(比如typeof),也是一样的。
function getVal(cond) {
if (cond) {
var color = 'blue';
return color;
} else {
// color 在此处可以被访问 值为 undefined
console.log(color);
return null
}
}
getVal()
上面代码可以写成这样,因为在预编译阶段var声明的变量已经自动提升到了当前作用域的顶端
function getVal(cond) {
var color;
if (cond) {
color = 'blue';
return color;
} else {
// color 在此处可以被访问 值为 undefined
console.log(color);
return null
}
}
getVal()
2、var 声明方式
- 可以重复声明,覆盖上一个值
- 存在变量提升
- 不存在暂时性死区
- 不存在块级作用域
- var在全局下声明的变量会挂载到window
// var 声明方式
var a = 1;
var a = 2;
console.log(a); 可以重复声明不会报错。覆盖上个值 打印出 2
console.log(b); 变量提升了,不会报错 打印出undefind。 没有暂时性死区
var b = 1;
{
var c = 5;
}
console.log(c); 可以打印出 5 , 没有块级作用域
console.log(window); 展开能看到 windo下面有以上声明的几个变量。 挂载到window
3、let 声明方式
- 不能重复声明
- 不存在变量提升
- 存在暂时性死区
- 存在块级作用域
- let 在全局下声明的变量不会挂载到window
// // let 声明方式
let a = 1;
let a = 2;
console.log(a); 报错 不能重复声明. 在不同的代码块中可以重复声明
console.log(b); 报错 存在暂时性死区, 没有变量提升
let b;
b = 3
{
let d = 7;
}
console.log(d); 报错 存在块级作用域
let c = 5;
console.log(window); window 下找不到c ,用let 声明的变量不会挂载到window
4、const 声明方式
- 不能重复声明
- 不存在变量提升
- 存在暂时性死区
- 存在块级作用域
- let 在全局下声明的变量不会挂载到window
它是个常量,它的值是不能改变的,能变的只能是内部成员!!!其余跟 let 一样。
// const 声明方式
const obj = {
age:1
}
obj.name = 2
console.log(obj); 正常打印 添加了个属性,本身对象没改变
const obj = {
age:1,
name:2
} 报错。 这样添加属性,改变了对象本身,常量不能被改变
const a = 1;
a = 10 报错 值不能被改变
5、循环内的块级绑定
// 循环内的块级绑定
for (var index = 0; index < 5; index++) {
console.log(index); 0 1 2 3 4
}
console.log(index); 5
for (let index = 0; index < 5; index++) {
console.log(index); 0 1 2 3 4
}
console.log(index); 报错
外面拿不到index值,外面可以手动提升变量,写成这样就能拿到
let index;
for (index = 0; index < 5; index++) {}
console.log(index); 5
for (const index = 0; index < 5; index++) {
console.log(index); 循环一次就报错 0
}
循环内的函数,解决闭包问题:
// 循环中的函数 解决闭包
var arr = [];
for (var i = 0; i < 10; i++) {
arr.push(function () {
console.log(i)
})
}
arr.forEach(function (fn) {
fn()
}) 10个10
我们本身的预期是希望输出0-9的数字,但是实际结果是数字10被输出了10次.
我们在修正这个问题的时候可以使用立即调用函数表达式,就可以在每次迭代中强制性的创建变量的一个新的副本.
var arr = [];
for (var i = 0; i < 10; i++) {
arr.push((function (value) {
return function () {
console.log(value)
}
})(i))
}
arr.forEach(function (fn) {
fn()
}) 输出0 1 2 3 4 5 6 7 8 9
上面在循环内使用立即调用函数表达式,变量 i 被传递给了立即调用函数表达式,
去创建了value变量为自身的副本,并在自己当中
利用let 可以简化以上代码。在每交迭代中.都创建一个新的同名变量,对其进行初始化.
var arr = [];
for (let i = 0; i < 10; i++) {
arr.push(function () {
console.log(i)
})
}
arr.forEach(function (fn) {
fn()
}) 输出0 1 2 3 4 5 6 7 8 9
总结:
1.let或const有块级作用域
2. var 只有全局和函数作用域
3. let 不能重复声明,const也不能重复声明
4. 如果使let 或 const 必须在使用声明.如果在使用后声明,会产生暂时性死区
5. 可以解决循环中的闭包的问题
6. var在全局下声明的变量,会挂载到window下面
7. let或const不会挂载到window下面.