第三篇 作用域、作用域链、执行上下文、函数、内存泄漏和垃圾回收

发布时间 2023-03-28 14:11:20作者: caix-1987

1、作用域

作用域表示当前的执行上下文,值和表达式在其中可见或可被访问到的上下文。作用域决定了代码区块中变量和其他资源的可见性。

1、全局作用域

   在代码中任何地方都能访问到的对象,拥有全局作用域。
   
   window对象的属性、方法
   
   定义在最外层的变量、函数、对象
   
   未定义直接赋值的变量
   
2、局部作用域

   局部作用域相当于函数作用域,指函数内部的空间。函数内部的变量,在外部无法访问。
   
3、块级作用域

   块级作用域指被大括号{}包裹在内的部分。比如,如果if语句使用{}包裹,就生成了一个块级作用域。

2、作用域链

当在某个函数的内部作用域中查找某个变量时,如果没有找到就会到他的父级作用域中查找,如果父级也没找到就会接着一层一层的向上寻找,直到找到全局作用域还是没找到的话,就结束寻找,认定为变量未定义。这种一层一层的作用域嵌套关系,就是作用域链。

作用域存在的意义
   
  变量隔离,不同作用域下同名变量不会出现冲突。

3、函数

函数定义
1、函数申明

   函数申明会被提升

2、函数表达式

   不能提升

3、箭头函数

   没有 this 和 arguments

4、function 构造器

   JavaScript 中每个函数是 Function 对象,所以要定义函数,可以直接调用 Function 对象的构造器。
   
   let sum = new Function('param1', 'param2', 'return param1 + param2');

5、Generator 函数

   Generator函数会在每个请求的基础上生成多个值,并在这些请求之

4、函数重载

1、是函数或者方法有相同的名称,但是参数列表不相同的情形,这样的同名不同参数的函数或者方法之间,互相称之为重载函数

2、重载函数通常用来声明一组功能相似的函数,这样做减少了函数名的数量,避免了名字空间的污染,对于程序的可读性有很大的好处。

 js 因为后面定义的同名函数会覆盖前面的函数,所以 js没有函数重载

5、执行上下文

执行上下文就是一个评估和执行 JavaScript 代码的环境的抽象概念。通俗地说,就是每当 Javascript 代码在运行的时候,它都是在执行上下文中运行。

JavaScript 中有三种执行上下文

1、全局执行上下文 

2、函数执行上下文

3、Eval 函数执行上下文

执行上下文的生命周期包括三个阶段:创建阶段 → 执行阶段 → 回收阶段

在 JavaScript 代码执行前,执行上下文将经历创建阶段。在创建阶段会发生三件事:

  this 值的决定,即我们所熟知的 This 绑定。

  创建词法环境组件

  创建变量环境组件
  
this的绑定

   在全局执行上下文中,this 的值指向全局对象。(在浏览器中,this引用 Window 对象)。
  
  在函数执行上下文中,this 的值取决于该函数是如何被调用的。
  
  如果它被一个引用对象调用,那么 this 会被设置成那个对象,否则 this 的值被设置为全局对象或者 undefined(在严格模式下)。
  
  
注意: 

作用域就是一个独立的区域,它可以让变量不会向外暴露出去。作用域最大的用处就是隔离变量。内层作用域可以访问外层作用域。一个作用域下可能包含若干个执行上下文。 

执行上下文创建阶段时,引擎检查代码找出变量和函数声明,虽然函数声明完全存储在环境中,但是变量最初设置为 undefined(var 情况下),但未初始化(let 和 const 情况下)。

所以可以在声明之前访问 var 定义的变量(虽然是 undefined),但是在声明之前访问 let 和 const 的变量会得到一个引用错误。

总结一下:

  JavaScript 属于解释型语言,JavaScript 的执行分为解释和执行两个阶段,这两个阶段所做的事并不一样
  
  解释阶段:

    词法分析
   
    语法分析
   
    作用域规则确定
   
  执行阶段:

    创建执行上下文
    
    执行函数代码
    
    垃圾回收

6、内存泄漏与垃圾回收

内存泄漏
 1、程序未能释放那些已经不再使用的内存,造成内存的浪费。
 
 2、一般是堆区内存泄漏,栈区不会泄漏。
 
 3、基本类型的值存在内存中,被保存在栈内存中,引用类型的值是对象,保存在堆内存中。所以对象、数组之类的,才会发生内存泄漏。
 
 哪些情况会出现内存泄漏:
 
 1、意外的全局变量
 
   当我们使用默认(不通过var申明)绑定定义变量,this会指向全局。
   
 2、被遗忘的定时器和回调函数
 
    当不需要setInterval或者setTimeout时,定时器没有被clear,定时器的回调函数以及内部依赖的变量都不能被回收,造成内存泄漏。
    
 3、闭包
 
    闭包可以维持函数内局部变量,使其得不到释放,造成内存泄漏。
    
 如何减少内存泄漏:
 
 1、减少不必要的全局变量,使用严格模式避免意外创建全局变量,严格模式下this指向undefined。
 
 2、在你使用完数据后,及时解除引用(闭包中的变量,dom引用,定时器清除)。
 
 3、组织好你的逻辑,避免死循环等造成浏览器卡顿,崩溃的问题。
垃圾回收机制

原理:按照固定的时间间隔,周期性的找出不再继续使用的变量,然后释放其占用的内存。

意义:在不需要字符串、对象的时候,需要释放其所占用的内存,否则将会消耗完系统中所有可用的内存,造成系统崩溃,这就是垃圾回收机制所存在的意义。

方法:
 
  1、标记清除
  
    当变量进入环境时(例如在函数中声明一个变量),将这个变量标记为“进入环境”,当变量离开环境时,则将其标记为“离开环境”。标记“离开环境”的就回收内存。
    
  2、引用计数 【被废弃的垃圾收集策略】