JavaScript是ECMAScript的实现,ECMAScript是JavaScript的标准。
在声明变量的声明命令上,ES5只有var命令、function命令2种,ES6有let命令、const命令、import命令、class命令4种,因此ES6有6种声明命令。
一 变量与宿主环境的关系
-
宿主环境
宿主环境是指不仅提供基本的ECMAScript实现,同时也会提供该语言的扩展,以便语言与环境之间交互 -
常见的宿主环境
- Web浏览器环境
- Node环境
- WebWorker环境
-
顶层对象
- 浏览器环境:window对象
- Node环境:global对象
- ES5中声明的全局对象等价于顶层对象
- ES6中声明的全局对象不属于顶层对象的属性
- 通用方法,会使用 this
var a = 1;
console.log('window.a: ', window.a);//1
let b = 1;
console.log('b: ', window.b);//undefined
存在的问题
ES5的顶层对象在各种环境的实现不统一
二 var命令
- 定义变量
var(操作符)+ 变量名(标识符) ;
1、未初始化的变量,会保存一个特殊值 undefined
2、省略var操作符的变量,会成为全局变量
-
初始化变量
直接给变量赋值即可,赋值的同时,并不会标记类型 -
修改值的变化
修改变量值的同时,修改值的类型 -
命令特点
三 let命令
- 定义变量
- let 变量名 = 值;
- 命令特点
1、不存在变量提升
所声明的变量一定要在声明后使用
console.log(foo);//undefined
var foo = 2;
// console.log(bar);//let.js:4 Uncaught ReferenceError: Cannot access 'bar' before initialization
let bar = 3;
console.log(bar); //3
2、暂时性死区
- 只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响
- 在代码块内,使用let命令声明变量之前,该变量都是不可用的。在语法上称为“暂时性死区”(TDZ)
- 本质:只要进入当前作用域,所要使用的变量就已经存在,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量
3、不允许重复声明
let不允许在相同作用域内重复声明同一个变量
function a(){
let a = 1;
var a = 10;//Uncaught SyntaxError: Identifier 'a' has already been declared
}
a();
function b(){
let a = 10;
let a = 1;//Uncaught SyntaxError: Identifier 'a' has already been declared
}
b();
function func(arg){
let arg; // Uncaught SyntaxError: Identifier 'arg' has already been declared
}
func();
function func(arg){
{
let arg; //正常执行
}
}
func();
4、块级作用域
没有块级作用域导致不合理的场景:
-
内层变量可能会覆盖外层变量
-
用来计数的循环变量泄露为全局变量
-
使用场景
- for循环计数器
var a = [];
//var声明的i,在全局范围内都有效
for(var i = 0; i < 10; i ++){
// 数组a的成员中的i指向的都是同一个i,也就是最后一轮的i值
a[i] = function(){
console.log(i);
}
}
a[6]();//10
var b = [];
for(let i = 0; i < 10; i ++){
// 变量i是let声明的,当前的i只在本来循环有效,每轮的i都是新值
b[i] = function(){
console.log(i);
}
}
b[6]();//6
// for循环特点:设置循环变量的部分是一个父作用域,而循环体内部是一个单独的子作用域
// 函数内部的变量i 与循环变量i不在同一个作用域,而是有各自单独的作用域
for(let i = 0; i < 3; i++){
let i = 'abc';
console.log(i);// 3 abc
}
四 const命令
- 定义变量
声明一个只读的常量 - 初始化变量
const一旦声明常量,就必须立即初始化,不能留到以后赋值 - 修改值的变化
- 保证的不是变量的值不得改动,而是变量指向的那个内存地址不得改动
const foo = {
};
foo.prop = 123;
console.log('foo.prop: ', foo.prop);//123
foo = {
};
console.log('foo: ', foo);//Uncaught TypeError: Assignment to constant variable
- 当地址指向一个对象,不可变的只是这个地址,不能把变量指向另一个地址,但对象本身是可变的,依然可以为其添加新属性
const c = [];
c.push('hello');
c.length = 0;
console.log('c: ', c); // []
c = ['dave'];
console.log('c: ', c);// Uncaught TypeError: Assignment to constant variable
- 命令特点
- 声明只读常量
- 变量指向的内存地址不得改动