进击的 JavaScript 变量

174 阅读4分钟

定义变量就是申请一块内存空间,用于保存数据。

变量的使用

  • 声明变量
    • var 变量名
    • 声明后其值为 undefined
  • 变量赋值
    • 变量名 = xxx
    • 变量可以被重新赋值,新的值会覆盖原来的值

访问一个未被赋值的变量可以,但访问一个未声明的变量会报错。
JavaScript 允许不写 var 而直接赋值,这样就相当于给 window 的某个属性赋值。

标识符命名规范

在开发中凡是需要自行命名的位置,称为标识符。

  • 标识符可由英文字母大小写、_、$、数字构成
  • 标识符可由英文字母大小写、_、$ 开头
  • 不可以与关键字保留词重复
  • 标识符应该做到望文生义
  • 大驼峰、小驼峰命名法 ...

变量提升

JS 中存在变量提升

  • 所有的变量声明(赋值语句不会),会自动的提到代码的最顶部
  • 但是,这种提升,不会超越脚本块
  • JS 允许定义多个同名变量,但变量提升后会合并成一个

全局变量

JavaScript 大部分的宿主环境都会提供一个特殊对象,该对象可以直接在 JS 代码中访问,该对象叫做全局对象。

全局对象的属性可以直接使用,而不需要写上全局变量名。

在浏览器环境中,全局对象为 window

通过 var 定义的变量,实际上会成为 window 对象的属性。

如果变量没有被赋值,则该变量不会覆盖 window 对象上的同名属性。

    // window 对象有个属性是 name,所以
    var name;
    console.log(name);   // 打印为空,而不是 undefined
    // 定义了 name,又没有赋值,所以用的是 window.name 的值
    
    // window.name 比较特殊,无论赋值什么,它都是字符串
    name = undefined;   // typeof name --> 'string'
    name = null;   // typeof name --> 'string'
    console.log(name);   // "null"

内存与变量存储

变量.png

内存分为栈内存堆内存,他们是内存的不同区域,不过它们的结构和存值方式都差不多。
引用名 -> [ 地址值 | 存储值 ]

堆和栈是两种不同的数据结构,我们可以简单的理解为,栈内存是内存中一片连续的区域,数据必须按内存地址顺序存放。而堆是内存中一个一个的块状区域,它不用非得按照内存地址顺序取用。

通常我们可以认为:

  • 原始类型的变量,由栈内存储存,直接存放具体的值
  • 引用类型的变量,由栈内存和堆内存共同储存
    • 堆内存存放具体的对象的值
    • 栈内存存放指向存放该对象的堆内存的首地址

⭐赋值行为与内存表现

1、变量重新赋值,并不是说覆盖原有的内存的值,而是新申请一块内存,写入新的值,并将引用名指向它。
2、变量间相互赋值,是让变量指向另一个变量所在的内存空间。

    var a = 123;   // 申请一块新的内存空间,引用名为 a,a -> [ 0x0001 | 123 ]
    a = 456;       // 申请一块新的内存空间,将 a 指向它,a -> [ 0x0002 | 456 ]
    var b = a;     // 引用名 b 也指向 a 指向的空间,b ->
    //                                             a -> [ 0x0002 | 456 ]

3、凡是出现对象字面量的位置,都一定会在堆内存中新申请一块空间存放,引用名在栈内存中指向这个新的地址。

    var obj1 = { name: 'yu' };
    var obj2 = { name: 'yu' };
    
    obj1 == obj2   // false

⭐扩展

V8 引擎的垃圾回收器,会定期发现内存中再也无法访问到的对象,并标记为垃圾,之后垃圾回收器会在合适的时间将其占用的内存释放。
具体可看这篇文章:点击查看

其实并不是所有原始类型变量都放在栈内存 --- 解释函数闭包现象。
具体可看这篇文章:点击查看


写在最后

One day you'll leave this world behind.So live a life you will remember! --- Avicii

我是暮星,一枚有志于在前端领域证道的攻城狮。

优质前端内容持续输出中......,欢迎点赞 + 关注

点赞.jpeg