总结:

1.ECMAScript 的语法很大程度上借鉴了 C 语言和其他类 C 语言,如 Java 和 Perl。
2.ECMAScript 中一切都区分大小写,无论是变量、函数名还是操作符。
3.关键字和保留字不能做函数名或变量名
4.标识符,第一个字符必须是一个字母、下划线(_)或美元符号($),剩下的其他字符可以是字母、下划线、美元符号或数字(标识符就是变量、函数、属性或函数参数的名称)。
5.严格模式:严格模式是一种不同的 JavaScript 解析和执行模型,可以在全局和单独的函数里使用;
作用是处理些不规范的写法
6.语句后面尽量要加分号;作用:
记着加分号有助于防止省略造成的问题,比如可以 避免输入内容不完整
加分号也便于开发者通过删除空行来压缩代码(如果没有结尾的分号,只 删除空行,则会导致语法错误)。
有助于在某些情况下提升性能,因为解析器会尝试在合适的 位置补上分号以纠正语法错误。
7.if语句尽量用花括号包裹代码
作用:在控制语句中使用代码块可以让内容更清晰,在需要修改代码时也可以减少出错的可能性。
8.声明变量的3种方式:let,const,var,尽量不要给变量赋与声明时类型不一样的值
9.var声明的变量:
var 声明的范围是函数作用域;
有变量提升,在声明变量之前,变量的值是undefined;
可以在同一个作用域下,多次声明同名变量;(由于声明会被提升,JavaScript 引擎会自动将多余的声明在作 用域顶部合并为一个声明。)
全局作用域下声明的变量,会成为window的属性
10.let声明的变量:
let 声明的范围是块作用域,在块级作用域内部声明的变量,块级作用域外是取不到的;
块作用域 是函数作用域的子集,因此适用于 var 的作用域限制同样也适用于 let。
在同一个作用域下,不能多次声明同名变量
不会变量提升,在 let 声明之前的执行瞬间被称为“暂时性死区”
let 在全局作用域中声明的变量不会成为 window 对象的属性
11.const声明的常量:
常量的值不能修改,声明的常量是对象,可以修改对象里的属性;
不能用 const 来声明迭代变量(因为迭代变量会自增):for (const i = 0; i < 10; ++i) {} // TypeError:给常量赋值
12.const的优势:
使用 const 声明可以让浏览器运行时强制保持变量不变;
也可以让静态代码分析工具提前发现不 合法的赋值操作;
让开发者更有信心地推断某些变量的值永远不会变;
同时也能迅速发现因 意外赋值导致的非预期行为;




以下执行结果是什么?为什么?

function test () {
debugger
message = ‘hi’
}
test()
console.log(message,window.message) // hi hi
image.png
当赋值给未声明的变量, 则执行赋值后, 该变量会被隐式地创建为全局变量(它将成为全局对象的属性)。
声明和未声明变量之间的差异是:
1. 声明变量的作用域限制在其声明位置的上下文中,而非声明变量总是全局的。

function x() { y = 1; // 在严格模式(strict mode)下会抛出 ReferenceError 异常
var z = 2;
}
x();
console.log(y); // 打印 “1”
console.log(z); // 抛出 ReferenceError: z 未在 x 外部声明
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/var

let和var哪个是函数作用域?哪个是块级作用域?

用 var 声明的变量的作用域是它当前的执行上下文,它可以是嵌套的函数,或者对于声明在任何函数外的变量来说是全局。https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/var
let声明的变量只在其声明的块或子块中可用,块级作用域是函数作用域的一个子级https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/let

打印结果是?原因?

for (var i = 0; i < 5; i++) {
setTimeout(() =>console.log(i)) // 5 5 5 5 5
}
1.for每循环一次创建新的块级作用域,块级作用域保存不了var声明的函数作用域的变量,var声明的变量是挂载在函数作用域下的,等于回调函数执行;
2.由于var有变量提升 var只会跑一次
3.var 声明的范围是函数作用域,所以,回调函数执行时,函数作用域只有一个 i,i是从函数作用域下拿的,此时i已经for循环结束了的值;
let i = 0
for (i; i < 5; i++) {
setTimeout(() =>console.log(i)) // 5 5 5 5 5
}
这种情况回调函数打印i的值也是5,回调函数执行时,for循环已经结束了,而打印的i不是for作用域下的,for作用域没有把i存储下来,是外部作用域的,所以,拿到的是循环结束的i值;
for (let i = 0; i < 5; i++) {
setTimeout(() =>console.log(i)) // 1 2 3 4 5
}
for循环里需要有自己的变量,用来在每个迭代中储存 i 的值;
这个for的块作用下声明的变量,所以,回调函数是从自己所在的块作用域下拿的i,就能保存每次循环i的值;相当于每循环一次,有一个新的块级作用域保存这个i,回调函数拿的i就是刚更新的i,跳出块作用域,回调拿的是循环结束的值;

在退出循环时,迭代变量保存的是导致循环退出的值:在之后执行超时 逻辑时,所有的 i 都是同一个变量,因而输出的都是同一个最终值。var 声明的范围是函数作用域,for是块级作用域(用var声明的变量没有块级作用域),for循环里的回调相当于在外部取的i,所以,回调是在循环退出之后取的i值;而用let的话,let 声明的范围是块作用域,for每循环一次,回调取最新的i值

使用const的优势?

使用 const 声明可以让浏览器运行时强制保持变量不变;
也可以让静态代码分析工具提前发现不合法的赋值操作;
让开发者更有信心地推断某些变量的值永远不会变;
同时也能迅速发现因 意外赋值导致的非预期行为;

拓展阅读

一文读懂块语句中的函数声明:https://mp.weixin.qq.com/s/0CI53KqjzkEfPp7FvC-GcQ