目录
1.语法
1.借鉴了 C 语言和其他类 C 语言,如 Java和 Perl
2.ECMAScript 中一切都区分大小写
3.标识符: 第一个字符必须是一个字母、下划线( _ )或美元符号( $ );
剩下的其他字符可以是字母、下划线、美元符号或数字。
ECMAScript 标识符使用驼峰大小写形式
4.ECMAScript 5 增加了严格模式(strict mode)的概念
在脚本开头加上这一行:"use strict";选择这种语法形式的目的是不破坏 ECMAScript 3语法。
2.关键字和保留字
关键字
ECMA-262 第 6 版规定的所有关键字如下:
break do in typeof
case else instanceof var
catch export new void
class extends return while
const finally super with
continue for switch yield
debugger function this
default if throw
delete import try
保留字
始终保留:
enum
严格模式下保留:
implements package public
interface protected static
let private
模块代码中保留:
await
3.变量
声明变量: var 、 const 和 let 。其中, var 在ECMAScript 的所有版本中都可以使用,而 const 和 let 只能在 ECMAScript 6及更晚的版本中使用。它们的区别主要在于变量的作用域和可变性。
1.var
var 是早期 JavaScript 中用于声明变量的关键字,它声明的变量具有函数作用域或全局作用域。例如:
var a = 1;
function foo() {
var a = 2;
console.log(a); // 2
}
foo();
console.log(a); // 1
在上面的代码中,我们使用 var 声明了一个变量 a,并分别在函数内部和外部赋值为不同的值。由于 var 声明的变量具有函数作用域,因此在函数内部声明的 a 变量与函数外部的 a 变量并不相同。
可以通过省略 var 操作符定义全局变量,但不推荐这么做。在局部作用域中定义的全局变量很难维护,也会造成困惑。这是因为不能一下子断定省略 var 是不是有意而为之。在严格模式下,如果像这样给未声明的变量赋值,则会导致抛出 ReferenceError 。
2.let
let 用于声明可变的变量,它与 var 的用法类似,但是 let 声明的变量只在块级作用域内有效。例如:
let a = 1;
{
let a = 2;
console.log(a); // 2
}
console.log(a); // 1
在上面的代码中,我们使用 let 声明了一个变量 a,并分别在代码块内部和外部赋值为不同的值。由于 let 声明的变量只在块级作用域内有效,因此在代码块内部声明的 a 变量与代码块外部的 a 变量并不相同。
使用 let 在全局作用域中声明的变量不会成为 window 对象的属性( var 声明的变量则会)
3.const
const 是常量的意思,用于声明不可变的变量,也就是一旦赋值就不能再修改。const 声明的变量必须在声明时初始化,并且不能再次赋值。例如:
const PI = 3.14;
PI = 3; // TypeError: Assignment to constant variable.
在上面的代码中,我们使用 const 声明了一个常量 PI,并且赋值为 3.14。由于 PI 是一个常量,所以在之后不能再次赋值,否则会抛出 TypeError 错误。
总的来说,const、let 和 var 都用于声明变量,但是它们的用法和作用域不同。const 用于声明不可变的常量,let 用于声明可变的变量并且具有块级作用域,而 var 用于声明具有函数作用域或全局作用域的变量。在实际编程中,我们应该根据实际情况选择不同的关键字来声明变量。
4.作用域
const和let变量特点
在 JavaScript 中,块级作用域指的是由一对花括号({})包围的代码块,它可以限制变量的作用域只在代码块内部有效。这与 JavaScript 中的函数作用域和全局作用域不同,函数作用域只在函数内部有效,而全局作用域在整个程序中都有效。
块级作用域可以使用 let 和 const 关键字来声明变量,这些变量只在代码块内部有效。例如:
{
let a = 1;
const b = 2;
}
console.log(a); // ReferenceError: a is not defined
console.log(b); // ReferenceError: b is not defined
在上面的代码中,变量 a 和 b 只在代码块内部有效,如果在代码块外部访问这些变量,就会抛出 ReferenceError 错误。
另外,块级作用域还可以用来解决变量提升的问题。在 ES6 之前,JavaScript 只有函数作用域和全局作用域,变量的作用域是由函数或程序的顶层作用域决定的,这会导致变量的声明会被提升到函数或顶层作用域的顶部,而不是在变量被声明的位置。
使用块级作用域可以解决这个问题,因为在块级作用域中声明的变量不会被提升,而是只在块级作用域内部有效。例如:
console.log(a); // undefined
var a = 1;
console.log(b); // ReferenceError: b is not defined
{
let b = 2;
}
在上面的代码中,变量 a 的声明会被提升到程序的顶部(提升仅仅是定义,并不会进行赋值),因此第一行代码输出 undefined(而不是报错)。而变量 b 使用 let 声明,只在代码块内部有效,因此在代码块外部访问变量 b 会抛出 ReferenceError 错误。
总的来说,块级作用域是 JavaScript 中实现更加严格的作用域限制和变量声明的基本机制,它可以提高代码的可读性和可维护性,避免了变量提升和变量作用域的问题。
var变量带来的问题
在 let 出现之前, for 循环定义的迭代变量会渗透到循环体外部:
for (var i = 0; i < 5; ++i) {
// 循环逻辑
}
console.log(i); // 5
改成使用 let 之后,这个问题就消失了,因为迭代变量的作用域仅限于 for 循环块内部:
for (let i = 0; i < 5; ++i) {
// 循环逻辑
}
console.log(i); // ReferenceError: i 没有定义
在使用 var 的时候,最常见的问题就是对迭代变量的奇特声明和修改:
for (var i = 0; i < 5; ++i) {
setTimeout(() => console.log(i), 0)
}
// 你可能以为会输出 0、1、2、3、4
// 实际上会输出 5、5、5、5、5
之所以会这样,是因为在退出循环时,迭代变量保存的是导致循环退出的值:5。在之后执行超时
逻辑时,所有的 i 都是同一个变量,因而输出的都是同一个最终值。