语法规则
变量命名
区分大小写的,test和Test是不同的变量
标识符
变量、函数、属性或函数参数的名称,其组成规则是:第一个字符必须是字符,下划线或美元符号;剩下的其它字符可以是字母,下划线,美元符号或数字。标识符按照惯例采用小驼峰式明明,即首字母小写,后面每个单词首字母大写。关键字、保留字、true、false、null不能作为标识符
注释
单行注释:
// 单行注释
多行注释
/*
* 这是多行注释
*/
严格模式
ECMAScript 5中增加的概念,JavaScript的一种解析和执行模型,对于ECMAScript 3的一些不规范的写法进行处理,抛出不安全的活动错误。
启用方式:在脚本开头加上"use strict",这是一个预处理指令。
单独指定一个函数在严格模式下进行:
function doSomething() {
"use strict";
// 函数体
}
关键字和保留字
关键字:
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
关键字指的是ECMA-262中有特殊用途的单词,比如表示控制语句的开始和结束,或执行特定的操作。关键字不能用作标识符或属性名。
保留字
enum(始终保留), implements, package, public, interface, protected, static, let, private(严格模式下保留), await(模块代码中保留)
保留字同样不能用来做标 识符但可以做对象属性名,但不建议。保留字是保留下来给将来做关键字的
变量
ECMAScript变量是松散类型的,即变量可以用来保存任何类型的数据,每个变量是一个用于保存人一直的命名占位符。声明边浪的方式:var,const,let
var
var message
上述代码即声明了一个变量,此时,变量的值是undefined的,因为没有定义初始值。
var message = "hi"
上述代码即对变量进行了赋值,即初始化。这种方式并不会决定变量的类型,后续更改,甚至可以赋值为其他数据类型的值,但不推荐这样做。
var的作用域
使用var在函数内部声明的变量,是局部变量,在函数退出时会被销毁。在定义变量时,省略var操作符,不管是全局作用域内,还是函数作用域内,该变量都是全局变量。但是这种方法,会使得变量变得难以维护。
在同时定义多个变量是,可以使用逗号将其隔开:
var message = "hi",
found = false,
age = 18;
var的作用域提升
先看一段代码:
function foo() {
console.log(age);
var age = 18;
}
foo(); // undefined
上述代码是可以成功执行,不会报错的,这是因为var声明的变量会有作用域提升,也就是说,var声明的变量会自动提升到函数作用域顶部,等价于:
function foo() {
var age;
console.log(age);
age = 18;
}
foo();
另外,使用var来声明变量,是可以多次声明同一个变量的。
let
let和var的作用相似,不同在于,let没有变量提升(暂时性死区:在解析代码时,JavaScript引擎也会注意出现在块后面的let声明,只不过在此之前不能以任何方式来引用未声明的变量。在let声明之前的执行瞬间被称为“暂时性死区”)
,并且声明的范围是块级作用域,var是函数作用域。
if(true) {
var name = "Matt";
console.log(name); // Matt
}
console.log(name); // Matt
------
if(true) {
let age = 18;
console.log(age); // 18
}
console.log(age); // ReferenceError: age未定义
// 这里age的作用域,仅限于花括号内,也就是块级作用域内。
块级作用域是函数作用域的子集,适用于var的作用域限制也适用于let。
let不允许声明同一个变量。但是在不同的块级作用域内,是可以的
var name = 'Nicholas';
console.log(name); // 'Nicholas'
if (true) {
var name = 'Matt';
console.log(name); // 'Matt'
}
let age = 30;
console.log(age); // 30
if (true) {
let age = 26;
console.log(age); // 26
}
let全局声明
let在全局作用域中声明的变量不会成为window队形的属性(var会),但是let声明也能在全局中使用,所以要确保使用let时,页面中不存在重复声明的变量,避免SyntaxError。
for循环中的let声明
使用var在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)
}
// 实际输出结果:5,5,5,5,5
这是因为,在退出循环时,迭代变量保存的是导致循环退出的值5,在之后执行setTimeout时,所有的i都是同一个变量,因而输出的都是同一个最终值。
而使用let时,JS引擎在后台会给每一个迭代循环声明一个新的迭代变量,每个setTimeout引用的变量实例都是不同的,所有console.log输出的是0,1,2,3,4。
for-in和for-of同样适用。
const
const和let大体上是一样的,不同在于声明变量时必须要赋值,且不能修改,也就是定义常量。但是,如果const声明的是一个对象,这个对象内部的属性是可以修改的,因为const声明的限制只适用于它指向的变量的引用。
const不能用在for循环中声明迭代变量,因为迭代变量是会变的,可以用于在for循环中声明一个不会被修改的循环变量。
let i = 0;
for (const j = 7; i < 5; ++i) {
console.log(j);
}
// 7, 7, 7, 7, 7
for (const key in {a: 1, b: 2}) {
console.log(key);
}
// a, b
for (const value of [1,2,3,4,5]) {
console.log(value);
}
// 1, 2, 3, 4, 5
在声明变量时,优先使用const。如果声明的变量需要修改,则使用let。尽量不要使用var。
参考资料
JavaScript高级程序设计(第4版)