var、let和const简单总结

438 阅读3分钟

varletconst

很久不写JavaScript了, 对新的特性也不甚了解, 其实也不算新了, 看了一篇介绍定义变量的关键词的文章, 这里记录一下, 以便以后查阅.

在以前var适用于所有场景, 唯一的对手是``, 也就是没有修饰符.

对于函数外的场景, 二者是一致的, 区别在于在函数内部.

image-20180913181535617

image-20180913181619977

var的特性

  1. 全局作用域

    var hello = 'hello'
    
    function world() {
        var abc = hello
        console.log(abc)
    }
    world()  // hello
    

    由于hello是全局的, 所以在world方法中可以访问.

  2. 函数级作用域

    function world() {
        var abc = 'hello'
        console.log(abc)
    }
    world() // hello
    console.log(abc) // ReferenceError: abc is not defined
    

    由于abc的作用域是函数内部, 所以在函数外部无法访问在函数内部通过var声明的变量.

  3. 可被重新声明

    var abc = 'hello'
    var is_postive = true
    if (is_postive) {
        var abc = 'world'
    }
    console.log(abc) // world
    
  4. 可被重新赋值

    var abc = 'hello'
    abc = 'world'
    
    console.log(abc) // world
    
  5. 变量提升

    console.log(abc) // undefined
    var abc = 'hello'
    

    实际上它是被解释成这样执行的:

    var abc;
    console.log(abc); // abc未定义
    abc = 'hello'
    

    所以, 其实abc的声明是被提升到了最顶部, 但是赋值是undefined.

let的特性

  1. 全局作用域

    let abc = 'hello'
    
    function hello() {
        console.log(abc)
    }
    hello() // hello
    

    代码块外部的let, 作用域范围和var一样, 是全局的.

  2. 块作用域

    所谓块, 是指代码块. 具体就是在代码中被{}包起来的部分. 要区别于前面说的var的函数级作用域.

    let is_postive = true
    if (is_postive) {
        let abc = 'hello'
    }
    console.log(abc) // ReferenceError: abc is not defined
    

    注意这里和前面的变量提升部分的区别, 变量被提升后, 因为已经“声明”, 所以不会报错, 只是值变成了undefined, 而这里是纯粹的没有声明, 所以会报一个引用错误.

    let abc = 'hello'
    let is_postive = true
    if (is_postive) {
        let abc = 'world'
        console.log(abc) // world
    }
    console.log(abc) // hello
    

    从这里可以看出, 全局的abc和代码块中的abc是互不影响的.

  3. 不可被重新声明

    为了解决var声明的变量可以被重复声明的问题, 才引入了let, 所以

    let abc = 'hello'
    let abc = 'world' // SyntaxError: redeclaration of let abc
    
  4. 可被重新赋值

    这个特性其实是区别于const

    let abc = 'hello'
    abc = 'world'
    console.log(abc) // world
    
  5. 变量提升

    变量提升到顶部和var相同, 但它并没有被赋值undefined, 其实它并没有被初始化, 所以

    console.log(abc)
    let abc = 'hello' // ReferenceError: can't access lexical declaration `abc' before initialization
    

    值得一提的是, 只有在上下文存在对abclet形式的赋值时, 才会报上述错误, 如果仅仅是console.log(cde)这种, 其实和在其下面使用var声明变量效果一样.

const的特性

  1. 全局作用域

    varlet

  2. 块作用域

    let

  3. 不可被重新声明

    其实可以理解成PHP中的const(常量), 声明和赋值必须在同一条语句, 一旦完成, 就不可改变(限作用域内).

    const abc = 'hello'
    const abc = 'world' //SyntaxError: redeclaration of const abc note: Previously declared at line 1, column 6
    

    前提是在相同作用域内

    const abc = 'hello'
    
    if (true) {
        const abc = 'world'
        console.log(abc) // world
    }
    console.log(abc) // hello
    
  4. 不可被重新赋值

    const abc = 'hello'
    abc = 'world' // TypeError: invalid assignment to const `abc'
    

    但如果用const声明的变量是对象时

    const abc = {'k1': 'v1', 'k2': 'v2'}
    console.log(abc) //Object { k1: "v1", k2: "v2" }
    abc.k1 = 'v3'
    console.log(abc) //Object { k1: "v3", k2: "v2" }
    

    当然, 这种情况下重新给变量整体赋值还是不允许的

  5. 变量提升

    let

总结

关键词 全局作用域 函数作用域 块作用域 重新声明 重新赋值
var YES YES NO YES YES
let YES NO YES NO YES
const YES NO YES NO NO