一、区分大小写
ECMAScript中一切都区分大小写。
例如:test、Test是两个不同的变量;typeof是关键字不能作为函数名,但是Typeof可以。
二、标识符
标识符就是变量、函数、属性或函数参数的名称。使用驼峰大小写形式(不强制)。
1、标识符的第一个字符必须是一个字母、下划线_或美元符号$
2、剩下的字符可以是字母、下划线、美元符号或数字
三、注释
单行注释 //这是单行注释
块注释 /*这是块注释*/
四、严格模式
es5增加了严格模式的概念。es3中不规范的写法在该模式下会被处理,对不安全的活动抛出错误。
目的:不破坏es3语法。
启用严格模式:
1、整个脚本:在脚本开头加 “use strict”;
2、指定函数严格模式下执行:函数体开头加“use strict”;
五、语句
语句以分号;结尾,省略则由解析器确定语句在哪结尾。
加分号:便于开发者删除空行压缩代码;有助于在某些情况下提升性能。
多条语句合并的代码块,花括号{}标识开始和结束。
像if之类的控制语句只有一句时建议别省略花括号
if(test) console.log(test);//有效,但容易导致错误
if(test) {console.log(test);}//推荐
六、关键字与保留字
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
未来的关键字:不能用作标识符,但可用作对象的属性名(最好都不要作为标识符和属性名,以兼容未来的es版本)
始终保留 enum
严格模式下保留 implements、package、public、interface、protected、static、let、private
模块代码中保留 await
七、变量
变量可用于保存任何类型的数据。每个变量只不过是一个用于保存任意值的命名占位符。
声明变量使用关键字var、const或let
1、var
demo被定义为一个保存字符串hi的变量。像这样初始化变量不会将它标识为字符串类型,只是简单的赋值。随后可以改变保存的值,也可以改变值的类型。
var demo="hi";//变量初始化,可同时定义变量并设置它的值
demo=100;//合理但不推荐
(1)var声明作用域
使用var操作符定义的变量会成为包含它的函数的局部变量。
function test(){
var demo="hi";//局部变量,变量将在函数退出时被销毁
}
test();
console.log(demo);//出错。
function test(){
demo="hi";//全局变量。调用一次test(),就定义了这个变量并且可以在函数外部访问到。不推荐这么做
}
test();
console.log(demo);//hi
定义多个变量可使用逗号分隔。
var demo="hi",
found=false,
age=20;
严格模式下不能定义名为eval、arguments的变量(会导致语法错误)。
(2)var声明提升
使用var声明的变量会自动提升到函数作用域顶部。
提升(hoist):把所有变量声明都拉到函数作用域的顶部。
function(){
console.log(age);
var age=20;
}
foo();//undefined
上面代码等价于下面这段代码
function(){
var age;
console.log(age);
age=20;
}
foo();//undefined
多次声明一个变量也没有问题
function(){
var age=18;
var age=28;
var age=38;
console.log(age);
}
foo();//38
2、let
(1)let声明作用域
let和var作用差不多,但let声明的范围时块作用域,而var声明的范围是函数作用域。
if(true){
var name="Matt";
console.log(name);//Matt
}
console.log(name);//Matt
if(true){
var age=20;
console.log(age);//20
}
console.log(age);//ReferenceError: age没有定义
let也不允许同一块中重复声明
var name;
var name;
let age;
let age;//SyntaxError; 标识符age已经声明过了
混用let,var声明冗余会报错。这两个关键字声明的并不是不同类型的变量,只是指出变量在相关作用域如何存在。
var name;
let name;//SyntaxError
let age;
var age;//SyntaxError
(2)暂时性死区
let声明的变量不会在作用域中被提升。
//name 会被提升
console.log(name);//undefined
var name="Matt";
//age不会被提升
console.log(age);//ReferenceError:age没有定义
let age=20;
在let声明之前的执行瞬间被称为”暂时性死区“,在此阶段引用任何后面才声明的变量都会抛出ReferenceError。
(3)全局声明
与var关键字不同,使用let在全局作用域中声明的变量不会成为window对象的属性(var声明的变量则会)。
var name="Matt";
console.log(window.name);//Matt
let age=20;
console.log(window.age);//undefined
不过,let声明仍然是在全局作用域中发生的,相应变量会在页面的生命周期内存续。因此,为了避免SyntaxError,必须确保页面不会重复声明同一个变量。
(4)条件声明
let这个新的es6声明关键字,不能依赖条件声明模式。
在使用var声明变量时,由于声明会被提升,JavaScript引擎会自动将多余的声明在作用域顶部合并为一个声明。因为let的作用域是块,所以不可能检查前面是否已经使用let声明过同名变量,同时也就不可能在没有声明的情况下使用它。
(5)for循环中的let声明
let出现之前,for循环定义的迭代变量会渗透到循环体外部
for(var i=0;i<5;i++){
//循环逻辑
}
console.log(i);//5
for(let i=0;i<5;i++){
//循环逻辑
}
console.log(i);//ReferenceError:i没有定义
使用var,在退出循环时,迭代变量保存的是导致循环退出的值:5.
for(var i=0;i<5;i++){
setTimeout(()=>console.log(i),0)
}
//输出5,5,5,5,5
使用let声明迭代变量时,JavaScript引擎在后台会为每个迭代循环声明一个新的迭代变量。
for(let i=0;i<5;i++){
setTimeout(()=>console.log(i),0)
}
//输出0,1,2,3,4
3、const
const行为与let基本相同,但用cosnt声明变量时必须同时初始化变量,且尝试修改const声明的变量会导致运行时错误。const也不允许重复声明,声明作用域也是块
const age=20;
age=36;//TypeError:给常量赋值
const声明的限制只适用于它指向的变量的引用。如果const变量引用的是一个对象,修改对象内部的属性不违反const限制。
const person={};
person.name="Matt";//可行
不能用const声明迭代变量。可以每次迭代只是创建一个新变量。
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
4、推荐声明风格
(1)不使用var,使用let和const有助于提升代码质量。因为变量有了明确的作用域、声明位置,以及不变的值。
(2)const优先,let次之。使用const声明可以让浏览器运行时强制保持变量不变,也可以让静态代码分析工具提前发现不合法的赋值操作。优先使用const来声明变量,只在提前知道未来会有修改时,再使用let。这样可以让开发者更有信心地推断某些变量的值永远不会变,同时也能迅速发现因意外赋值导致的非预期行为。