回顾ES5变量定义

语法

ES6标准发布之前,使用var定义一个变量

  1. var a = 1;
  2. var b = true;
  3. var c = array();
  4. var d = {};
  5. var e = 'hello';

全局作用域和函数作用域

使用var定义的变量具有全局作用域和函数作用域

全局作用域

  1. if(true) {
  2. var a=12;
  3. }
  4. console.log(a); //可以访问

代码说明:
即便在if代码块中定义了变量a,变量a被视为全局变量,在if代码块之外可以访问

函数作用域

  1. function b() {
  2. var c=0;
  3. console.log(c); //0
  4. function d() {
  5. console.log(c);//0
  6. }
  7. }
  8. console.log(c); //Uncaught ReferenceError: c is not defined

代码说明:

  • 变量在函数中定义,在函数外部不能访问(报错:Uncaught ReferenceError: c is not defined)
  • 在函数体内可以访问,子函数(函数b)也可以访问

ES6中的块作用域

let关键字

let在ES6中引入的用于定义变量的关键字,语法与var一样

  1. let a = 1;
  2. let b = true;
  3. let c = array();
  4. let d = {};
  5. let e = 'hello';

使用let具有块作用域,既仅限于代码块(一对大括号之间{}

  1. if(true) {
  2. let a=12;
  3. }
  4. console.log(a); //Uncaught ReferenceError: c is not defined

代码说明:
由于let定义的变量是块作用域,仅能在当前代码块范围内访问,因此在代码块访问就会报错

let特性:

  1. TDZ(暂时性死区)

    1. if(true) {
    2. console.log(b);
    3. let b = true;
    4. }

    代码说明:
    由于let定义的变量不会产生变量提升,在定义之前访问会产生报错

  2. 不能使用let定义相同名称的变量(包括函数和对象)

    1. let a = 1;
    2. let a = true; //报错,前面已经使用let定义了名为'a'的变量
    3. function a() {};//同样报错,前面已经使用let定义了名为'a'的变量
    4. let a = {};//同样报错,前面已经使用let定义了名为'a'的变量
  3. for循环中,存在父子作用域的情况

    1. for(let i=0; i<10; i++) {
    2. let i='a';
    3. console.log(i);
    4. }

    代码说明:

  • 循环定义的那部分代码是父作用域,第一个定义的变量i,属于父作用域
  • 循环体内的代码块,是子作用域,因此再次使用let定义相同名称的变量i并不会产生报错

const关键字

const语法和特性与let几乎一样

  1. const a = 1;
  2. const b = true;
  3. const c = array();
  4. const d = {};
  5. const e = 'hello';

与let的区别在于,const定义的关键字不能重新被赋值

  1. const a = 1;
  2. a = true; //报错:Uncaught TypeError: Assignment to constant variable.

使用const定义的对象,其属性是可以修改的

  1. //对象
  2. const a = { name:1 };
  3. a.name = 'hello'; //修改变量
  4. a.age = 12; //新增属性
  5. //数组
  6. const a = ['a'];
  7. a.push('b'); //新增元素

但是,直接对变量名赋值则会产生报错

  1. //对象
  2. const a = { name:1 };
  3. a = { age:2 }; //报错
  4. //数组
  5. const a = ['a'];
  6. a = ['b']; //报错