首页 > 系统相关 >JavaScript高级程序设计笔记04 变量、作用域与内存

JavaScript高级程序设计笔记04 变量、作用域与内存

时间:2022-10-10 15:23:37浏览次数:43  
标签:变量 04 作用域 JavaScript 对象 GC 内存 上下文

变量、作用域与内存

变量

特定时间点一个特定值的名称。

  • 分类

    • 原始值:按值访问

      • 复制:两个独立使用、互不干扰
    • 引用值(由多个值构成的对象):按引用访问

      操作对象时,实际上操作的是对该对象的引用(reference)而非实际的对象本身

      • 复制:复制的值实际上是一个指针,指向存储在堆内存中的对象。实际上两个变量指向同一个对象
      • 函数传参:都是按值传递,如果是引用值,就跟引用值变量的复制一样
  • 判断类型

    • typeof

      最适合用来判断一个变量是否为原始类型,对引用值的用处不大。

    • instanceof

      什么类型的对象(由对象的原型链决定)

作用域

  • 执行上下文

    变量或函数的上下文决定了它们可以访问哪些数据,以及它们的行为。每个上下文都有一个关联的变量对象(variable object),而这个上下文中定义的所有变量和函数都存在于这个对象上。

    全局上下文是最外层的上下文。根据ECMAScript实现的宿主环境,表示全局上下文的对象可能不一样。在浏览器中,就是常说的window对象。

    上下文在其所有代码都执行完毕后会被销毁,包括定义在它上面的所有变量和函数。

    上下文栈。当代码执行流进入函数时,函数的上下文被推倒一个上下文栈上;在函数执行完毕之后,上下文栈会弹出该函数上下文,将控制权返还给之前的执行上下文。

    作用域链(scope chain)。决定了各级上下文中的代码在访问变量和函数时的顺序。代码正在执行的上下文的变量对象始终位于作用域链的最前端;全局上下文的变量对象始终是作用域链的最后一个变量对象。上下文之间的连接是线性的、有序的,内部可以访问外部,外部无法访问内部。

    函数参数被认为是当前上下文中的变量。

    标识符解析。搜索过程始终从作用域链的最前端开始,逐级往后,直到找到或者到达最后端。

    局部作用域中定义的变量会产生遮蔽(上层同名变量)效果,引用全局变量可以使用完全限定的写法:window.propName。

  • 增强作用域链

    在作用域链前端临时添加一个上下文。

    • try/catch的catch语句:创建一个新的变量对象(包含要抛出的错误对象的声明)
    • with:添加指定的对象

    eval():修改作用域链。

  • 不同关键字的声明

    • var

      通过var定义的全局变量和函数都会成为window对象的属性和方法。

      使用var声明变量时,变量会被自动添加到最接近的上下文。

      会导致变量声明被提升,在(代码中)变量声明之前就可以访问到变量。

    • let/const

      顶级声明不会定义在全局上下文中,但在作用域链解析上效果是一样的。

      块作用域由最近的一对包含花括号界定。不能重复声明。

      const声明不能重新赋值,单一类型且不可修改。

      V8引擎针对const的优化:const声明的变量都替换成实际的值,而不通过查询表进行变量查找。

  • 变量查找(作用域链)

    标识符查找:局部上下文->沿作用域链

    访问局部变量比全局变量要快,因为不用切换作用域。

垃圾回收。GC

执行环境负责在代码执行时管理内存(内存分配和闲置资源回收)。

基本思路:确定哪个变量不会再使用,然后释放它占用的内存。此过程是周期性的,每隔一定时间就会自动运行。(近似且不完美的方案,是否还有用属于“不可判定”的问题。不是所有时候都会很明显)

  • 如何标记未使用的变量,两种主要的标记策略:

    • 标记清理mark-and-sweep:最常用

      过程:

      1. 标记内存中存储的所有变量;
      2. 将所有在上下文中的变量,以及被在上下文中的变量引用的变量的标记去掉;
      3. 之后再被加上标记的变量,就是待删除的了,因为任何在上下文中的变量都访问不到它们了;
      4. GC程序做一次内存清理,销毁带标记的所有值并收回它们的内存。
    • 引用计数reference counting

      GC下次运行的时候会释放引用数为0的值的内存。

      严重的问题:循环引用。典型:IE8及更早版本的BOM和DOM(使用COM对象)。

      应该在确保不使用的情况下切断原生JavaScript对象与DOM元素之间的连接。

      把变量设置为null实际上会切断变量与其之前引用值之间的关系。

  • GC调度(性能)

    最好的办法:写代码时做到,无论什么时候开始收集垃圾,都能让它尽快结束工作

    现代GC程序会基于对JavaScript运行时环境的探测来决定何时运行。

    探测机制:基本上是根据已分配对象的大小和数量来判断。(V8的堆增长策略:根据活跃对象的数量外加一些余量来确定何时再次垃圾回收。)

    不推荐主动触发垃圾回收。(某些浏览器可以)

    • 减少GC次数(减少不合理分配)
    • 尽快完成回收
  • 内存管理

    分配给浏览器的内存通常比分配给桌面软件的要少很多,分配给移动浏览器的更少。——> 主要出于安全考虑,避免运行大量JavaScript的网页耗尽系统内存而导致操作系统崩溃。

    这个内存限制不仅影响变量分配,也影响调用栈以及能够同时在一个线程中执行的语句数量。

    内存占用量保持在一个较小的值可以让页面性能更好。优化内存占用的最佳手段:保证在执行代码时只保存必要的数据。如果数据不再必要就解除引用(设置为null)——尤其是全局变量和全局对象的属性,下次垃圾回收时会被回收。

    • 利用let/const提早回收:块作用域比函数作用域更早终止

    • v8引擎的隐藏类:几个实例共享同一个构造函数和原型。

      给实例增加新属性或删除其属性,就不能共享一个隐藏类。——最佳实践:不想要的属性设置为null,达到删除引用值供GC程序回收的效果。

      避免“先创建再补充”式的动态属性赋值。

    • 内存泄漏

      1. 意外声明全局变量
      2. 闭包
    • 静态分配与对象池(合理分配,避免多余GC:保住因释放内存而损失的性能)

      减少浏览器执行垃圾回收的次数。

      浏览器决定何时运行GC程序的一个标准,就是对象更替的速度。——》一个策略:使用对象池(管理一组可回收的对象)

      可使用数组来维护,但必须留意不要招致额外的垃圾回收。

标签:变量,04,作用域,JavaScript,对象,GC,内存,上下文
From: https://www.cnblogs.com/halftonine/p/16775849.html

相关文章

  • 004 二分法
    //二分法判断一个数是否存在(有序数组)publicstaticBooleanBSExist(int[]arr,intnum){if(arr==null||arr.length==0){returnfal......
  • 004Java的一些基本概念
    004Java的一些基本概念1、Java特性和优势Java至少具有以下特性:简单性(没有头文件、没有指针运算、也没有分配内存等操作)面向对象(万物皆对象)可移植性(一次编写,到处运行......
  • Javascript获取当前年月日并计算
    需求:表单初始加载,获取系统当前时间,加半年和一年给两个日期字段赋值步骤:1.获取当前年,当前月,当前日期2.对年月日进行运算,完成后拼接赋值代码如下:(泛微E9)......
  • 带有pwn环境的Ubuntu22.04快速安装
    pwn环境ubuntu22.04快速安装(有克隆vmk)ubuntu更新到了22.04版本,经过本人测试后非常的好(ma)用(fan),该版本和mac很相像,而且用起来也比较丝滑,只不过配置上稍微有一些多,也比较繁琐......
  • IIS设置了歌词为text/plain格式,但是.net core项目还是访问不了,404,是应.net core里没有
     IIS设置了歌词为text/plain格式,但是.netcore项目还是访问不了,404,是应.netcore里没有支持在StartUp静态文件支持里添加上就可以了。varprovider=newFileExtensio......
  • Java-Day04 Scanner/if-else/switch-case/for
    2022/10/9一、Scanner:从键盘获取数据1.要使用Scanner首先需要导入包:importjava.util.Scanner;2.使用方法:Scanner变量名=newScanner(System.in);/......
  • javascript parse date string - js 字符串转日期
    一、日期数字newDate().getTime()//1665370859678数字表示从UTC+0时区的1970年1月1日0时0分0秒开始的那一刻起,所经过的毫秒数。无论是在北京还是伦敦,此时此刻,无论......
  • 实时营销引擎在vivo营销自动化中的实践 | 引擎篇04
    作者:vivo互联网服务器团队本文是《vivo营销自动化技术解密》的第5篇文章,重点分析介绍在营销自动化业务中实时营销场景的背景价值、实时营销引擎架构以及项目开发过程中......
  • MatrixOne从入门到实战04——MatrixOne的连接和建表
    MatrixOne从入门到实战——MatrixOne的连接和建表前景回顾前几篇文章,为大家介绍了MatrixOne这个产品,以及编译、部署MatrixOne的服务。直通车:MatrixOne从入门到实践——......
  • JavaScript中实现不可变对象
     实现不可变数据有三种主流的方法深克隆,但是深克隆的性能⾮常差,不适合⼤规模使用Immutable.js,Immutable.js性能良好,但是需要学习额外的APIimmer,利用Proxy特性,⽆需学......