Javascript 变量 作用域 与 内存

  • 原始值与引用值:
    • 原始值:
      • 最简单的数据;
      • 保存原始值的变量是按值访问的;
    • 引用值:
      • 由多个值构成的对象;
      • 操作对象时,实际上操作的是对该对象的引用,而非实际的对象本身;
      • 可随时添加、修改和删除其属性和方法;
    • 复制值:
      • 通过变量把一个原始值赋值给另一个变量时,原始值会被复制到新变量的位置;
      • 把引用值从一个变量赋给另一个变量时,存储在变量中的值也会被赋值到新所在的位置,复制的值实际上是一个指针,它指向存储在堆内存中的对象。
    • 传递参数:
      • 函数传递参数都是按值传递的;
    • 确定类型:
      • instanceof
  • 执行上下文与作用域:
    • 变量或函数的上下文决定了它们可以访问哪些数据,以及它们的行为;
    • 每个上下文都有一个关联的变量对象,而这个上下文中定义的所有变量和函数都存在于这个对象上。
    • 浏览器中,全局上下文即window对象;
    • 上下文在其所有代码都执行完毕后会被销毁,包括定义在它上面的所有的变量和函数;
    • 全局上下文在应用程序退出前才会被销毁,比如关闭网页或退出浏览器;
    • 上下文中的代码在执行的时候,会创建变量对象的一个作用域链;这个作用域链决定了各级上下文中的代码在访问变量和函数时的顺序。
    • 内部上下文可通过作用域链访问外部上下文中的一切,但外部上下文无法访问内部上下文中的任何东西。
    • 局部上下文首先从自己的变量对象开始搜索变量和函数,搜不到就去搜索上一级变量对象。
    • 作用域链增强:
      • 某些语句会导致在作用域链前端临时添加一个上下文,这个上下文在代码执行后会被删除;
        • with语句,会向作用域链前端添加指定的对象;
        • catch语句,会创建一个新的变量对象,这个变量对象会包含要抛出的错误对象的声明;
    • 变量声明:
      • 使用var的函数作用域声明:
        • 变量会被自动添加到最接近的上下文;
        • 如果变量未经声明就被初始化了,那么它会自动被添加到全局上下文。
        • var声明会被拿到函数或全局作用域的顶部,位于作用域中所有代码之前,这个现象叫“提升”;
      • 使用let的块级作用域声明:
        • 块级作用域,由最近的一对包含花括号{}界定;
      • 使用const的常量声明:
        • 使用const声明的变量必须同时初始化为某个值。一经声明,在其生命周期的任何时候都不能再重新赋予新值。
      • 标识符查找:
        • 搜索开始于作用域链前端,如果在局部上下文中找到该标识符,则搜索停止,变量确定;若未找到变量名,则继续沿作用域链搜索,这个过程一直持续到搜索值全局上下文的变量对象。若仍未找到标识符,则说明其未声明。
  • 垃圾回收:
    • 执行环境在代码执行时管理内存,通过自动内存管理实现内存分配和闲置资源回收。
    • 基本思路:确定哪个变量不会再使用,然后释放它占用的内存。
      • 垃圾回收策略之一:标记清理
        • 首先,会标记内存中存储的所有变量;
        • 然后,将所有在上下文中的变量,以及被在上下文中的变量引用的变量的标记去掉;
        • 之后,加上标记的变量是待删除变量;
        • 随后,垃圾回收程序做一次内存清除,销毁带标记的所有值并收回它们的内存;
      • 垃圾回收策略之二:引用清理
        • 思路:对每个值都记录它被引用的次数;
        • 缺点:常会引起内存泄漏;
        • 声明变量并把它赋一个引用值时,这个值的引用值为1;
        • 若同一个值又被赋给另一个变量,那么引用值加1;
        • 若保存对该值引用的变量被其他值给覆盖了,那么引用值减1;
        • 当一个值的引用值为0,则说明没办法再访问这个值了,因此可安全地收回其内存;垃圾回收程序下次运行时会释放引用值为0的值的内存;
    • 常见内存泄漏的原因:
      • (1)全局变量引起的内存泄露
      • (2)闭包引起的内存泄露:慎用闭包
      • (3)dom清空或删除时,事件未清除导致的内存泄漏
      • (4)循环引用带来的内存泄露
    • 性能:
      • 动态改变分配变量、字面量或数组槽位等会触发垃圾回收的阈值。若垃圾回收程序回收的内存不到已分配的15%,这些变量、字面量或数组槽位的阈值就会翻倍。若有一次回收的内存已达已分配的85%,则阈值重置为默认值。
    • 内存管理:
      • 优化内存占用的最佳手段:保证在执行代码时只保存必要的数据。
      • 解除引用:若数据不再必要,则把它设置为null,从而释放其引用。
      • 解除引用的关键:在于确保相关的值已经不在上下文里,下次垃圾回收时会被回收。
        • 通过const和let声明提升性能:
          • 块作用域,而非函数作用域,使用这两个关键字可能会更早地让垃圾回收程序介入,尽早回收应该回收的内存。
        • 隐藏类和删除操作:
          • V8引擎会把创建的对象与隐藏类关联起来,以跟踪它们的属性特征。能够共享相同隐藏类的对象性能会更好。
          • 避免Javascript的“先创建后补充”式的动态属性赋值,并在构造函数中一次性声明所有属性。
          • 最佳实践是把不想要的属性设置为null,这样可保持隐藏类不变和继续共享,同时也能达到删除引用值供垃圾回收程序回收的效果。
        • 静态分配和对象池:
          • 使用对象池:在初始化的某一时刻,可创建一个对象池,用来管理一组可回收的对象。应用程序可向对象池请求一个对象、设置其属性、使用它,然后在操作完成后再把它还给对象池。
  • 欢迎大家留言评论;一起学习,共同进步;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值