3.0 本章内容
(基于ECMAScript第六版)
3.1 语法
3.1.1 区分大小写
变量, 函数名, 操作符都区分大小写 如test与Test是两个不同的变量
类似的typeof不能作为函数名(关键字) 但是Typeof是一个有效的函数名
3.1.2 标识符
定义: 变量, 函数, 属性或函数参数的名称 组成:
- 第一个字符必须是一个字母或下划线或美元符号
- 剩下的字符可以是字母,下划线,美元符号或数字
标识符中的字母可以是拓展ASCII中的字母也可以是Unicode的字母字符, 如à和?(但不推荐使用)
标识符形式: 使用驼峰大小写形式(第一个单词首字母小写其他后面每个单词的首字母大写如: somethingLikeThis)
非强制, 但因为这种形式跟ECMAScript内置函数和对象的命名方式一致, 故推荐(最佳实践)
注意:
关键字, 保留字, true, false和null不能作为标识符
3.1.3 注释
- 单行注释
// 这是单行注释
- 多行注释
/*
这
是
多
行
注
释
*/
3.1.4 严格模式
ECMAScript5 增加了严格模式 严格模式是一种不同的JavaScript解析和执行模型, ECMAScript 3的一些不规范写法在这种模式下会被处理, 对于不安全的活动将抛出错误。
要对整个脚本启用严格模式,在脚本开头加上这一行:
"use strict"
这个一个预处理指令 任何支持的JavaScript引擎看到它都会切换到严格模式。 选择这种语法形式的目的是不破坏ECMAScript 3语法
也可以单独指定一个函数在严格模式下执行, 将上面这句话放到函数体的开头即可:
function demo(){
"use strict";
// ...
}
3.1.5语句
JavaScript中语句可以不加分号:
let a = 100 + 200 // 有效但不推荐
let b = a + 1000; // 加分号也有效, 推荐
不加分号则由解析器确定语句结尾, 而加分号自己确定, 避免省略造成的问题(如输入内容不完整) 加分号便于开发者删除空行来压缩代码(没有分号只删除空行的化会导致语法错误) 加分号也有助于在某些情况下提升性能,因为解析器会尝试在合适的位置补上分号以纠正语法错误。 要养成加分号的好习惯
代码块 多条语句可以合并到一个c语言风格的代码块之中 代码块{}, 左花括号开始, 右花括号结束
if(test){
// ...
}
建议始终在控制语句中使用代码块, 即使例如if中只有一条语句可以省略{}
3.2 关键字与保留字
ECMA-262 描述了一组保留的关键字 这些关键字有特殊的用途, 不能用作标识符或属性名 ECMA-262第六版规定的所有关键字如下
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(现在好像有async/await)
这些词汇不能作为标识符 但是目前还可以用作对象的属性名 不建议使用关键字和保留字作为标识符和属性名
3.3 变量
可以保存任意类型值
var, const, let 声明变量
const与let只能在es6以及更新的版本才能用
3.3.1 var
variable 的缩写
var message;
不进行初始化时默认保存undefined
var message;
console.log(message);
声明时进行初始化
var message = "hello world";
作用域: 函数作用域, 非块作用域
function myFunc(){
var message = "hello world";
}
myFunc();
console.log(message);
省略关键字直接定义变量, 会导致这个变量成为一个全局变量
function myFunc() {
message = "hello world";
}
myFunc();
console.log(message);
不推荐这样使用, 很难维护, 突然冒出来的一个变量都不知道是干啥的 严格模式下这样会报错
定义多个变量
var message1 = "hi",
message2 = "hello world",
message3;
换行与空格缩进非必须, 但是如同上面的形式便于阅读
var声明提升问题: var声明的变量会提升为在函数作用域的顶部声明(不包括赋值, 也就说如果有赋值则在原来位置上赋值)
console.log(message);
var message = "hi";
console.log(message);
上面这段代码相当于下面:
var message;
console.log(message);
message = "hi";
console.log(message);
提升会将所有变量声明都提升到函数作用域的顶部
使用var反复声明同一个变量不会出错
function test() {
var message = 1;
var message = "hi";
var message;
var message = true;
console.log(message);
}
test();
如上段代码可以理解为先提升, 然后有四个message变量的var声明, 合并为一个, 所以不会报错
在全局作用域声明的变量会成为window对象的属性
var message = 'hi';
console.log(window.message);
3.3.2 let
let声明的变量是块作用域
{
let message = "hi";
console.log(message);
}
console.log(message);
块作用域是函数作用域的子集, 所以let声明的变量离开他所在函数时也无法使用
function test() {
let message = "hi";
}
console.log(message);
let不允许在同一作用域出现冗余声明
{
let message;
let message;
}
{
let message;
{
let message;
}
}
{
var message;
let message;
}
暂时性死区
let 声明的变量不会在作用域中提升
{
console.log(message);
let message = "hi";
}
但是js引擎会注意到出现在块后面的let声明, 不过在let声明执行之前, 都无法引用未声明的变量, 这称为暂时性死区
可以理解为实际上有提升(目前大多数都这样认为), 但是由于无法在原let声明出现前引用, 没有形式上如同var一样的提升, 所以看作没有提升
全局声明
let在全局作用域中声明的变量不会成为window对象的属性
var message1 = "hi";
let message2 = "hello world";
console.log(window.message1);
console.log(window.message2);
不过,let声明仍然是在全局作用域中发生的, 相应变量会在页面的生命周期内存续。 因此,为了避免SyntaxError,必须确保页面不会重复声明同一个变量。
** 条件声明 ** 同一作用域用多次用var声明同一个变量不会出问题, 但是对于let你无法检查前面是否已经使用let声明过同名变量
不信你试试
所以let无法依赖于条件声明模式
for循环中的let声明
let解决了循环定义的迭代变量渗透到循环体外部的问题
for(var i = 1; i <= 5; i++) {
}
console.log(i);
for(let j = 1; j <= 5; j++){
}
console.log(j);
var迭代变量问题:
for(var i = 0; i< 5; i++){
setTimeout(()=>console.log(i), 0);
}
这里注意, js是单线程的, 先执行i=0并判断了他比5小后, 开始执行第一次循环体中的内容, 但是这里发现是setTimeout, 而setTimeout是异步的, 于是将他放入一个任务队列, 等到当前的同步任务执行完后在执行这个队列里的任务, 这样就导致了将循环语句执行完了但是把五个setTimeout全加到队列里没有执行, 而最后i=5时循环体不再继续, 这时这个队列里有五个setTimeout函数, 但此时都是公用一个i=5, 就导致了输出了5个5, 这里虽然setTimeout设置的时间为0, 事件本身没有延迟,但是改变了任务执行的先后顺序,执行的先后顺序又导致了微小的延迟(执行其他语句的延迟而非专门等了多少毫秒才执行setTimeout的设置的延迟) 具体可以看看下面这个例子
alert(1);
setTimeout(function() {
alert(2);
},0);
alert(3);
而let可以解决上述问题
使用let时, js引擎在后台会为每个迭代循环声明一个新的迭代变量(虽然都叫i但是相当于在不同的块中) 每个setTimeout引用的都是不同的变量实例
for(let i = 0; i < 5; i++){
setTimeout(()=>console.log(i), 0);
}
这种每次迭代声明一个独立变量实例的行为适用于所有风格的for循环, 包括for-in和for-of循环
3.3.3 const
更新中…
|