概览
语句块(或其他语言中的复合语句)用来组织零个或多条语句。用一对花括号界定语句块。
{
statement_1;
statement_2;
...
statement_n;
}
语句块通常在流程控制语句 (如if
, for
, while
)中使用.如:
while (x < 10) {
x++;
}
注意语句块不是以分号结尾.
其他语言中通常将语句块称为 复合语句. 语句块允许你在Javascript需要一行语句的时候使用多行语句. 在JavaScript中使用语句块是种很常见的做法. 与之相反的做法是使用 empty语句, empty语句 可以在需要语句的环境下不提供任何语句.
块级作用域
- 使用 var
通过var声明的变量没有块级作用域.
var x = 1;
{
var x = 2;
}
console.log(x); // 输出 2
- 使用 let 和 const
与 var 不同, 使用 let 和 const 声明的变量是有块级作用域的.
let x = 1;
{
let x = 2;
}
console.log(x); // 输出 1
x = 2 被限制在块级作用域中, 也就是它被声明时所在的块级作用于.
const 的结果也是一样的:
const c = 1;
{
const c = 2;
}
console.log(c); // 输入1, 而且不会报错
补充
如果一个变量已经用其他方式声明,再直接使用let或const声明会报错:
var a = 3;
let a = 5; // Uncaught SyntaxError: Identifier 'a' has already been declared
但如果是在块级作用域内就不会:
var a = 3;
{
let a = 5;
}
console.log(a); // 5
let
描述
let允许你声明一个作用域被限制在块级中的变量、语句或者表达式。与var关键字不同的是,var声明的变量只能是全局或者整个函数块的。
作用域规则
let声明的变量只在其声明的块或子块中可用,这一点,与var相似。二者之间最主要的区别在于var声明的变量的作用域是整个封闭函数。
简化内部函数代码
当用到内部函数的时候,let会让你的代码更加简单:
var list = document.getElementById("list");
for (let i = 1; i <= 5; i++) {
var item = document.createElement("LI");
item.appendChild(document.createTextNode("Item " + i));
let j = i;
item.onclick = function (ev) {
console.log("Item " + j + " is clicked.");
};
list.appendChild(item);
}
上面这段代码的意图是创建5个li,点击不同的li能够打印出当前li的序号。如果不用let,而改用var的话,将总是打印出 Item 5 is Clicked,因为 j 是函数级变量,5个内部函数都指向了同一个 j ,而 j 最后一次赋值是5。用了let后,j 变成块级域(也就是花括号中的块,每进入一次花括号就生成了一个块级域),所以 5 个内部函数指向了不同的 j 。
在程序或者函数的顶层,let并不会像var一样在全局对象上创造一个属性,比如
var x = 'global';
let y = 'global';
console.log(this.x); // "global"
console.log(this.y); // undefined
let 的暂存死区与错误
在同一个函数或同一个作用域中用let重复定义一个变量将引起 TypeError。
if (x) {
let foo;
let foo; // TypeError thrown.
}
在 ECMAScript 2015中, let将会提升这个变量到语句块的顶部。然而,在这个语句块中,在变量声明之前引用这个变量会导致一个 ReferenceError的结果, 因为let变量 在"暂存死区" (从块的开始到声明这段).
function do_something() {
console.log(foo); // ReferenceError
let foo = 2;
}
let 在循环中
可以用let来代替var,在for定义块中使用块级变量。
for (let i = 0; i < 10; i++) {
console.log(i); // 0, 1, 2, 3, 4 ... 9
}
console.log(i); // i is not defined
const
const 声明创建一个只读的常量。这不意味着常量指向的值不可变,而是变量标识符的值只能赋值一次。(译者注:JavaScript中的常量和Java,C++中的常量一个意思。注意区分常量的值和常量指向的值的不同)
描述
这个声明创建了一个常量,可以在全局作用域或者函数内声明常量,常量需要被出事或。这就是说,在定义常量的同时必须出事或(这是有意义的,鉴于变量的值在初始化后就不能改变)。
常量拥有块作用域,和使用let定义的变量十分相似。常量的值不能通过再赋值改变,也不能再次声明。一个常量不能和他所在的作用域内的其他变量或函数拥有相同的名称。
例子
下面的例子演示了常量的特性。在浏览器的控制台试一下这个例子。
// 注意: 常量在声明的时候可以使用大小写,但通常情况下会使用全部大写英文。
// 定义常量MY_FAV并赋值7
const MY_FAV = 7;
// 在 Firefox 和 Chrome 这会失败但不会报错(在 Safari这个赋值会成功)
MY_FAV = 20;
// 输出 7
console.log("my favorite number is: " + MY_FAV);
// 尝试重新声明会报错
const MY_FAV = 20;
// MY_FAV 保留给上面的常量,这个操作会失败
var MY_FAV = 20;
// MY_FAV 依旧为7
console.log("my favorite number is " + MY_FAV);
// 下面是一个语法错误
const A = 1; A = 2;
// 常量要求一个初始值
const FOO; // SyntaxError: missing = in const declaration
// 常量可以定义成对象
const MY_OBJECT = {"key": "value"};
// 重写对象和上面一样会失败
MY_OBJECT = {"OTHER_KEY": "value"};
// 对象属性并不在保护的范围内,下面这个声明会成功执行
MY_OBJECT.key = "otherValue"