变量,作用域,内存

10 阅读4分钟

1.变量

变量可以包含原始值和引用值,原始值就是最简单的数据,引用值则是由多个值构成的对象。保存原始值的变量是按值访问的,因为我们操作的就是存储在变量中的实际值;操作对象时,实际上操作的是对该对象的引用,因此保存引用值的变量是按照引用访问的。

2.执行上下文与作用域

变量或函数的上下文决定了它们可以访问哪些数据,以及它们的行为。每个上下文都有一个关联的变量对象,而这个上下文中定义的所有变量和函数都存在于这个对象。虽然无法通过代码访问变量对象,但后台处理数据会用到它。

在浏览器中,全局上下文就是我们常说的window对象,因此所有通过var定义的全局变量和函数都会成为window对象的属性和方法。使用let和const的顶级声明不会定义在全局上下文,但在作用域链的解析上效果是一样的。上下文在其所有代码都执行完毕后会被销毁,包括定义在它上面的所有变量和函数

每个函数都有自己的上下文。当代码执行流进入函数时,函数的上下文被推到一个上下文栈中。在函数执行完之后,上下文栈会弹出该函数上下文,将控制权返还给之前的执行上下文

上下文的代码在执行的时候,会创建变量对象的一个作用域链。这个作用域链决定了各级上下文中的代码在访问变量和函数时的顺序。代码正在执行的上下文的变量对象始终位于作用域链的最前端。如果上下文是函数,则其活动对象用作变量对象。活动对象最初只有一个定义变量:arguments。作用域链中的下一个变量对象来自包含上下文,再下一个变量对象来自再下一个包含上下文,以此类推至全局上下文。

标识符查找:当在特定上下文中为读取或写入而引用一个标识符时,必须通过搜索确定这个标识符表示什么。搜索开始于作用域链前端,以给定的名称搜索对应的标识符。如果在局部上下文中找到该标识符,则搜索停止,变量确定;如果没有找到变量名,则继续沿作用域链搜索(注意,作用域链中的对象也有一个原型链,因此搜索可能涉及每个对象的原型链)这个过程一直持续到搜索至全局上下文的变量对象。如果仍然没有找到标识符,则说明其未声明。

3. 垃圾回收:

标记清理,引用计数

4.内存泄漏:

1.意外声明全局变量,在function中声明变量不加var,const或者let

2.定时器通过闭包引用了外部变量

5.Javascript变量可以保存两种类型的值:原始值和引用值。原始值是以下6种:Undefined,Null,Boolean,Number,String和Symbol

  • 原始值大小固定,因此保存在栈内存上

  • 从一个变量到另一个变量复制原始值会创建该值的第二个副本

  • 引用值是对象,存储在堆内存上

  • 包含引用值的变量实际上只包含指向相应对象的一个指针,而不是对象本身

  • 从一个变量到另一个变量复制引用值只会复制指针,因此结果是两个变量都指向同一个对象

  • typeof操作符和可以确定值的原始类型,而instanceof操作符用于确保值的引用类型

6.任何变量都存在于某个执行上下文中。这个上下文决定了变量的生命周期,以及它们可以访问代码的哪些部分,执行上下文可以总结如下:

  • 执行上下文分全局上下文,函数上下文和块级上下文
  • 代码执行流每进入一个新上下文,都会创建一个作用域链,用于搜索变量和函数
  • 函数或块的局部上下文不仅可以访问自己作用域内的变量,而且也可以访问任何上下文乃至全局上下文中的变量
  • 全局上下文只能访问全局上下文中的变量和函数,不能直接访问局部上下文中的任何数据
  • 变量的执行上下文用于确定什么时候释放内存