Javascript的变量

488 阅读4分钟

简单介绍变量

在js中变量是很灵活的,举个简单的例子:即便一开始赋值了number类型,后续还可以改成字符串。

引用《Javascript高级程序设计》的话是:javascript变量是松散类型的,而且变量不过就是特定时间点一个特定值的名称而已,变量的值和数据类型在脚本生命周期内可以改变

用代码表示就是:

let param = 'val'; 
setTimeout(() => {
    param = 20;
}, 500);

当然为了规范开发,不推荐在开发过程中改变变量保存值的类型,现在的开发人员也会使用ts来让变量类型保持从一而终

数据类型

  • 基础类型(也称为原始类型)

    Undefined, Null, String, Number, Boolean, Symbol, BigInt

    其中SymbolECMAScript6新增的数据类型, BigIntECMAScript2020新增数据类型

  • 复杂类型

    Object(对象) —— 一组数据和功能的集合

变量可以包含两种不同类型的数据

  • 原始值

    最简单的数据,即上文中基础类型的任意一种, 按值访问

  • 引用值

    多个值构成的对象(Object),按引用访问

声明变量

  • var

    var声明的范围是函数作用域

    function test() {
        var name = 'echo'; // 在函数内部声明变量
        age = 12; // 未使用var定义,age就变成了全局变量;严格模式下报错
        var job = 'Doctor';
    }
    test();
    var name = 'Global'; // 声明全局变量
    console.log(name); // 'Global'
    console.log(age); // 12
    console.log(job); // ReferenceError: job is not defined
    

    当函数退出时,函数的内部变量会被销毁(在闭包内引用内部变量时除外)

    使用var声明的变量会自动提升到函数作用域顶部,所以先使用后定义也不会报错

    使用var声明变量时,由于声明会被提升,JavaScript引擎会自动将多余的声明在作用域顶部合并为一个声明(所以重复定义变量也不会报错)

  • let

    let声明的范围是块作用域,块作用域是函数作用域的子集

    不允许同一个块作用域中出现冗余声明(SyntaxError; 标识符 properName 已经声明过了)

    letvar的另一个重要区别是,let声明的变量不会在作用域中被提升。

    在let声明之前的执行瞬间被称为 “暂时性死区”,所以不能先使用后声明,否则会抛出ReferenceError

    使用let在全局作用域中声明的变量不会成为window对象的属性(var声明的则会)

    经典使用场景之一 —— for循环中的变量声明

    有问题的代码

    for(var i = 0; i < 5; i++) {
        setTimeout(() => console.log(i), 0)
    }
    

    运行以上代码,我们期望的值是 0, 1, 2, 3, 4;可实际得到的却是 5, 5, 5, 5, 5。

    那么如果我们把其中的var改成let呢? 没错,期望的结果就会出现!

    这是因为使用let之后,迭代变量的作用域仅限于for循环块内部,js引擎在后台为每个迭代循环声明一个新的迭代变量,每个setTimeout引用的都是不同的变量实例,所以能按期望输出。

    而使用var,迭代变量保存的是导致循环退出的值:5,在之后执行超时逻辑时,所有的i都是同一个变量,就会导致同一个值输出5次。

    这种每次迭代声明一个独立变量实例的行为适用于所有风格的for循环,包括for-infor-of循环

  • const

    let基本相同,唯一区别是它用来声明常量(声明时必须同时初始化变量,且变量不可修改)。

    const name = 'echo';
    name = 'Jon'; // TypeError
    

    const声明的限制只适用于它指向的变量的引用。说人话就是,如果const变量引用的是一个对象,那么这个对象内部可修改。

    const person = {};
    person.name = 'echo'; // ok
    
  • 最佳实践

    有了letconst,在开发中尽量避免使用var,这样有助于提升代码质量

    const优先,let次之 —— 使用const可以让静态代码分析工具提前发现不合法的赋值操作,很多开发者认为应该优先使用const,只在提前知道未来会修改的变量再使用let

理解作用域 & 词法作用域 & 作用域链

现在我们已经能成功创建变量了,那么然后呢?这些变量存储在哪里?程序需要的时候又试如何找到它们的呢?

那么接下来,理解作用域就成为下一个学习点了!