一、标识符
第一个字符必须是一个字母、下划线(_)、美元符号($)
二、严格模式
ES5规范增加了严格模式(strict mode),目的是处理ES3不规范的写法,'strict mode'是一个预处理语句,可以写进函数体开头,这个预处理指令告诉浏览器引擎切换为严格模式,大部分浏览器都支持。
function doSomething() {
"use strict";
// 函数体
}
三、分号
每写一条语句最好加上分号,不加也可以,由解析器负责确定语句在哪里结尾,分号的好处
a.防止省略造成的问题
b.提升性能,不加分号,解析器会自动在每行末尾加上分号,会耗费一部分性能资源
c.便于开发者通过删除空行来压缩代码
四、代码块
在控制语句中使用代码块可以让内容更清晰,在需要修改代码时也可以减少出错的可能性。
// 有效,但容易导致错误,应该避免
if (test)
console.log(test);
// 推荐
if (test) {
console.log(test);
}
五、保留字和关键字不能用做标识符和属性
通俗来说,保留字就是未来规范要用到的,未来成为关键字
ES6关键字
ES6保留字
六.变量
三个关键字:var、let、const
var:所有ECMAScript版本可用
let、const:ES6及以后版本可用
1.var关键字
1.var声明作用域
1)var定义变量不赋值,值默认为undefined
2)var操作符定义的变量会成为包含它的函数的局部变量,随着函数的执行退出而销毁,在函数内省略var操作符,创建的变量是全局变量,不会随着函数的执行退出而销毁
3)区分是局部作用域还是全局作用域
function test(){
name = 'Marry';//全局变量
}
test();//执行函数时创建name变量
console.log(name);//Marry
————————————————————————————————————————
function test(){
var name = 'Marry';//局部变量
}
test();//执行函数时创建name变量
console.log(name);//报错
注意:在局部作用域内,通过省略var操作符定义的变量,虽为全局变量,但是不推荐这么做,严格模式下,会报错。严格模式下,这种在局部作用域定义全局变量的行为是错误的
2.var声明存在变量提升(hoist)
function test(){
console.log(name);
var name = 'Marry';
}
test();//undefined
=================================
等价于
function test(){
var name;
console.log(name);
name = 'Marry';
}
test();//undefined
2.let声明
let和var差不多,但存在区别,var声明的范围是函数作用域,let声明的范围是块作用域
一般情况下,‘{}’大括号表示一个块,所以块作用一定是函数作用域的子集
if(true){
var name = 'Marry';
console.log(name);//Marry
}
console.log(name);//Marry
=======================对比===========================
if(true){
let name = 'Marry';
console.log(name);//Marry
}
console.log(name);//ReferenceError: name is not defined
怎么理解作用域?
var、let就是告诉javascript引擎,声明的变量,能在哪个范围内是有效的、有作用的,比如上述第一个例子var声明的name是在全局有效的;let声明的name在if代码块外面是无效的。
父代码块包含子代码块的情况
情形一:同一个代码块let声明的变量不能已经被声明或者即将被声明,但是不同代码块是可以重复声明
function test(){
let name = 'Marry';
let name = 'Marry';//SyntaxError: Identifier 'name' has already been declared
if(true){
let name = 'Bob';
}
}
test();
=====================对比==============================
function test(){
let name = 'Marry';
if(true){
let name = 'Bob';//不会报错
}
}
//可以理解为两个name虽然变量一样,但实际上是不一样的,两个name指定的作用域不同
//声明的时候为其指定作用域
test();
情形二:子代码块可以拿到父代码块的变量,但是父代码块无法拿到子代码块的变量
function test(){
let name = 'Marry';
if(true){
name = 'Bob';
}
console.log(name);//Bob
}
test();
//子代码块if里的name就是父代码块里的name.
=============对比====================
function test(){
if(true){
let name = 'Bob';
}
console.log(name);//ReferenceError: name is not defined
}
test();
如何区分两个变量是否是一个变量?声明的时候就指定了其作用域,笔者个人理解;
比较变量名是否一样,
作用域是否一样
暂时性死区
var声明会存在变量提升,而let不会变量提升
在let声明的变量前使用这个变量,代码执行瞬间,称为暂时性死去(temporal dead zone)
console.log(name);//ReferenceError: name is not defined
let name = 'Marry';
===============对比============
console.log(name);//Marry
var name = 'Marry';
2.全局声明
let在全局声明时不会成为window对象的属性,而var则会;前提是在浏览器javascript执行环境下,存在windows对象,而在其他环境下比如nodejs,是不存在window对象
let name = 'Marry';
console.log(window.name);//undefined 是undefined的原因是想window对象添加了name属性,初始化为undefined
==============对比=================
var name = 'Marry';
console.log(window.name);//Marry
3.for循环中的let声明
for (var i = 0;i<5;i++){
setTimeout(()=>{
console.log(i);
},0)
}//输出:5 5 5 5 5;
=============对比====================
for (let i = 0;i<5;i++){
setTimeout(()=>{
console.log(i);
},0)
}//输出:0 1 2 3 4;
首先要区分异步和同步,同步会先执行完再执行异步,这里先记住,后面会再解释.
所以var声明的for循环体会先执行5次,再执行5次setTimeout里的代码,此处var声明的作用域是全局作用域,五次循环都是对同一个i进行操作,最后i为5,所以输出5 5 5 5 5;
而let声明的i,作用域为5个不同的代码块,理解为5个不同的i,对应输出为0 1 2 3 4;
3.const声明
const声明的变量不允许修改,基本类型就是值不能更改,引用类型地址不能修改,比如什么一个对象,对象的属性是可以修改的
const也不允许重复声明
4.声明风格
不使用var
const优先,let次之