1. 在ES2015之前, JavaScript只有两种类型的作用域: 全局作用域和局部(函数)作用域。
2. ES2015引入了两个重要的JavaScript新关键词: let和const。
3. let和const都是用来声明变量的。
4. let和const这两个关键字在JavaScript中提供了块作用域(Block Scope)变量和常量。
5. 块作用域
5.1. 通过var关键词声明的变量没有块作用域。
5.2. var在块{}内声明的变量可以从块之外进行访问。和在块外声明变量没什么两样, 还是是全局变量。因此一般不在块中使用var声明变量, 在全局使用var声明变量就可以了。
5.3. 实例
{
var a = 5; // 给a初始化为5
}
document.write('a = ' + a + "<br />"); // 输出a = 5
5.4. 可以使用let关键字声明拥有块作用域的变量。
5.5. let在块{}内声明的变量无法从块外访问。
5.6. 实例
{
let b = 10;
// let在块内声明的变量, 只能在块内访问。
document.write('b = ' + b + "<br />"); // 输出b = 10
}
// 块外不能访问b, 访问b, 报错
6. 循环作用域
6.1. 循环中使用var声明的变量是全局变量。
for(var i = 1; i <= 3; i++){
document.write('i = ' + i + "<br />");
}
document.write('i = ' + i + "<br />"); // 输出i = 4
document.write('i = ' + window.i + "<br />"); // 输出i = 4
var obj = {id: 1001, name: 'zs'};
for(var item in obj){
document.write('item = ' + item + "<br />");
}
document.write('item = ' + item + "<br />"); // 输出item = name
document.write('item = ' + window.item + "<br />"); // 输出item = name
6.2. 循环中使用let声明的变量, 在循环外不能访问。
for(let j = 1; j <= 3; j++){
document.write('j = ' + j + "<br />");
}
// 不能访问j
for(let key in obj){
document.write('key = ' + key + "<br />");
}
// 不能访问key
7. 函数作用域
7.1. 在函数内声明变量时, 使用var和let很相似。它们都有函数作用域:
function myFunction1() {
var bookName = "Effective Java"; // 函数作用域
document.write('bookName = ' + bookName + "<br />"); // bookName = Effective Java
}
myFunction1();
// document.write('bookName = ' + bookName + "<br />"); // 访问bookName会报错
function myFunction2() {
let mobileName = "huawei"; // 函数作用域
document.write('mobileName = ' + mobileName + "<br />"); // mobileName = huawei
}
myFunction2();
// document.write('mobileName = ' + mobileName + "<br />"); // 访问mobileName会报错
8. 全局作用域
8.1. 如果在块外声明声明, 那么var和let也很相似。它们都拥有全局作用域:
var c = 15; // 全局作用域
let d = 20; // 全局作用域
9. html中的全局变量
9.1. 使用JavaScript的情况下, 全局作用域是JavaScript环境。
9.2. 在html中, 全局作用域是window对象。
9.3. 通过var关键词定义的全局变量属于window对象:
var c = 15;
document.write('c = ' + c + "<br />"); // c = 15
document.write('c = ' + window.c + "<br />"); // c = 15
9.4. 通过let关键词定义的全局变量不属于window对象, 属于JavaScript环境:
let d = 20;
document.write('d = ' + d + "<br />"); // d = 20
document.write('d = ' + window.d + "<br />"); // d = undefined
10. 重新声明
10.1. 允许在程序的任何位置使用var重新声明JavaScript变量:
var I = 'I_01'; // 允许
var I = 'I_02'; // 允许
function myFn01(){
var II = 'II_01'; // 允许
var II = 'II_02'; // 允许
}
10.2. 在相同的作用域, 通过let重新声明一个var变量是不允许的:
var III = 'III_01'; // 允许
let III = 'III_02'; // 不允许
function myFn02(){
var III = 'III_01'; // 允许
let III = 'III_02'; // 不允许
}
10.3. 在相同的作用域, 通过var、let重新声明一个let变量是不允许的:
let IV = 'IV_01'; // 允许
var IV = 'IV_02'; // 不允许
function myFn03(){
let IV = 'IV_01'; // 允许
var IV = 'IV_02'; // 不允许
}
let V = 'V_01'; // 允许
let V = 'V_02'; // 不允许
{
let V = 'V_01'; // 允许
let V = 'V_02'; // 不允许
}
function myFn04(){
let V = 'V_01'; // 允许
let V = 'V_02'; // 不允许
}
11. 提升
11.1. 通过var声明的变量会提升到顶端。
p = 120;
var p;
document.write('p = ' + p + "<br />"); // p = 120
11.2. 通过let定义的变量不会被提升到顶端。
11.3. 在声明let变量之前就使用它会导致ReferenceError。
// q = 125; 报错
let q;
12. 例子
12.1. 代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>let关键字</title>
</head>
<body>
<script type="text/javascript">
{
var a = 5; // 给a初始化为5
}
document.write('a = ' + a + "<br />"); // 输出a = 5
{
let b = 10;
// let在块内声明的变量, 只能在块内访问。
document.write('b = ' + b + "<br />"); // 输出b = 10
}
// 块外不能访问b, 访问b, 报错
for(var i = 1; i <= 3; i++){
document.write('i = ' + i + "<br />");
}
document.write('i = ' + i + "<br />"); // 输出i = 4
document.write('i = ' + window.i + "<br />"); // 输出i = 4
var obj = {id: 1001, name: 'zs'};
for(var item in obj){
document.write('item = ' + item + "<br />");
}
document.write('item = ' + item + "<br />"); // 输出item = name
document.write('item = ' + window.item + "<br />"); // 输出item = name
for(let j = 1; j <= 3; j++){
document.write('j = ' + j + "<br />");
}
// 不能访问j
for(let key in obj){
document.write('key = ' + key + "<br />");
}
// 不能访问key
function myFunction1() {
var bookName = "Effective Java"; // 函数作用域
document.write('bookName = ' + bookName + "<br />"); // bookName = Effective Java
}
myFunction1();
// document.write('bookName = ' + bookName + "<br />"); // 访问bookName会报错
function myFunction2() {
let mobileName = "huawei"; // 函数作用域
document.write('mobileName = ' + mobileName + "<br />"); // mobileName = huawei
}
myFunction2();
// document.write('mobileName = ' + mobileName + "<br />"); // 访问mobileName会报错
var c = 15;
document.write('c = ' + c + "<br />"); // c = 15
document.write('c = ' + window.c + "<br />"); // c = 15
let d = 20;
document.write('d = ' + d + "<br />"); // d = 20
document.write('d = ' + window.d + "<br />"); // d = undefined
p = 120;
var p;
document.write('p = ' + p + "<br />"); // p = 120
// q = 125; 报错
let q;
</script>
</body>
</html>
12.2. 效果图