输出3个10 :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>let-var</title>
</head>
<body>
<script>
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[1](); // 10
a[2](); // 10
a[9](); // 10
</script>
</body>
</html>
原因:var是全局的
<script>
var a =10
var a =12
var a =11
console.log(a)//11
</script>
上述的等价于:var变量提升
<script>
var a = [];
var i = 0
a[i] = function () {
console.log(i);
};
var i = 1
a[i] = function () {
console.log(i);
};
var i = 2
a[i] = function () {
console.log(i);
};
var i = 3
a[i] = function () {
console.log(i);
};
var i = 4
a[i] = function () {
console.log(i);
};
var i = 5
a[i] = function () {
console.log(i);
};
var i = 6
a[i] = function () {
console.log(i);
};
var i = 7
a[i] = function () {
console.log(i);
};
var i = 8
a[i] = function () {
console.log(i);
};
var i = 9
a[i] = function () {
console.log(i);//i是全局的i
};
var i = 10
a[i] = function () {
console.log(i);
};
console.log(i);//10
a[1](); // 10
a[2](); // 10
a[9](); // 10
</script>
let-声明的变量仅在块级作用域内有效
<script>
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[1]()//1
a[6](); // 6
</script>
等价于:
<script>
var a = [];
{let i = 0
{
a[i] = function () {
console.log(i);//只是当前的i
};
}
}
{let i = 1
{
a[i] = function () {
console.log(i);
};
}
}
{let i = 2
{
a[i] = function () {
console.log(i);
};
}
}
a[1]()//1
a[2](); // 2
</script>
for循环有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域
<script>
for (let i = 0; i < 3; i++) {
let i = '33';
console.log(i);
}
33
// 33
// 33
</script>
在代码块内,使用let命令声明变量之前,该变量都是不可用的{}内前面就算使用了var声明该变量也是不可以使用的。这在语法上,称为“暂时性死区”temporal dead zone,简称 TDZ)——前面不可以使用该变量作为全局变量。变量使用let命令声明,所以在声明之前,都属于x的“死区”,只要用到该变量就会报错。
<script>
var i=1
{ console.log(i)
let i=12}
</script>
变量使用let命令声明,所以在声明之前,都属于变量的“死区”,只要用到该变量就会报错。但是变量不使用let声明,反而不会报错
<script>
if (true) {//代码块
// TDZ开始——使用变量前且在代码块内就会出现TDZ暂时性死区
tmp = 'abc'; // ReferenceError
console.log(tmp); // ReferenceError
let tmp; // TDZ结束
}
</script>
<script>
if (true) {//代码块
let tmp; // TDZ结束
console.log(tmp); // undefined--没有赋值
}
</script>
<script>
if (true) {//代码块
// TDZ开始——使用变量前且在代码块内就会出现TDZ暂时性死区
let tmp; // TDZ结束
tmp = 123;
console.log(tmp); // 123
}
</script>
暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。
函数f()执行后,输出结果为undefined,原因在于变量提升,导致内层的tmp变量覆盖了外层的tmp变量。
<script>
var tmp = new Date();
function f() {
console.log(tmp);
if (false) {
var tmp = 'hello world';
}
}
f(); // undefined
</script>
外层代码块不受内层代码块的影响
function f1() {
let n = 5;
if (true) {
let n = 10;
}
console.log(n); // 5
}
ES6 允许块级作用域的任意嵌套,上面代码使用了一个五层的块级作用域,每一层都是一个单独的作用域。第四层作用域无法读取第五层作用域的内部变量。
<script>
{{{{
{let insane = 'Hello World'}
console.log(insane); // 报错//不在同一个块域内--变量不行
}}}};
</script>
内层作用域可以定义外层作用域的同名变量
<script>
{{{{
let insane = 'Hello World';
{let insane = 'Hello World';}
}}}};
</script>
ES6 规定,块级作用域之中,函数声明语句的行为类似于let,在块级作用域之外不可引用。
- 允许在块级作用域内声明函数。
- 函数声明类似于var,即会提升到全局作用域或函数作用域的头部。
- 同时,函数声明还会提升到所在的块级作用域的头部。
块级作用域内部,优先使用函数表达式,而不是函数声明 ,ES6 的块级作用域必须有大括号小括号不算,ES6 的块级作用域必须有大括号,不存在块级作用域,而let只能出现在当前作用域的顶层