欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 会展 > 简单理解闭包|作用域和作用域链|执行上下文

简单理解闭包|作用域和作用域链|执行上下文

2024/11/19 4:51:31 来源:https://blog.csdn.net/qq_53911056/article/details/140715097  浏览:    关键词:简单理解闭包|作用域和作用域链|执行上下文

本文主要介绍对闭包|作用域和作用域链|执行上下文三个的理解。

1.闭包

(1)定义

闭包指有权访问另一个函数作用域中变量的函数。

(2)闭包的基本特性

函数嵌套内部函数可以访问外部函数的作用域,包括参数和局部变量,即使外部函数已经执行完毕。

持久性闭包的生命周期比其外部函数的生命周期更长。只要闭包存在,就可以继续访问和操作其外部函数的变量。

(3)闭包的用途

数据封装和隐私:通过闭包,可以隐藏函数的具体实现和状态,只对外提供公共的接口函数。这有助于实现数据封装和隐藏内部实现细节。

回调函数和异步编程:在JavaScript等语言中,闭包常用于处理回调函数,帮助异步编程中维持上下文(即变量作用域)的连续性。

模拟私有变量:在JavaScript等没有原生私有变量概念的语言中,闭包可以用来模拟私有变量和私有方法。

示例:

function createCounter() { let count = 0; // 外部函数的局部变量 return function() { // 内部函数,闭包 count += 1; return count; } 
} const counter = createCounter(); 
console.log(counter()); // 输出: 1 
console.log(counter()); // 输出: 2 
......
// 注意:createCounter函数已经执行完毕,内部变量count仍可以被counter函数访问和修改

在这个例子中,createCounter 函数创建了一个局部变量 count,并返回了一个内部函数。这个内部函数就是一个闭包,因为它可以访问和修改其外部函数 createCounter 的局部变量 count。当 createCounter 函数已经执行完毕,count 变量仍然被保存在内存中,具有持久性。

2.作用域和作用域链

(1)作用域(Scope)

作用域定义了变量和函数在代码中的可访问性。简单来说,它决定了在哪里可以访问到特定的变量或函数。在JavaScript中,主要有两种作用域:全局作用域和局部作用域(也称为函数作用域,ES6后引入了块级作用域,如letconst声明的变量)。let/const/var的区别及理解

  • 全局作用域:在代码的任何地方都可以访问到的变量和函数拥有全局作用域。在浏览器环境中,全局作用域是window对象,而在Node.js中,全局作用域是global对象。

注意:全局作用域缺点就是过多使用全局作用域变量会污染全局命名空间,容易造成命名冲突。

  • 局部作用域:在函数或代码块(ES6+)内部声明的变量或函数只能在其声明的函数或代码块内部访问。

除了全局作用域和局部作用域,还有块级作用域。块级作用域指的是变量或常量在代码块(如大括号{}包围的区域)内部定义后,其作用范围仅限于该代码块内部。

(2)作用域链(Scope Chain)

作用域链是JavaScript在查找变量时的一个过程或机制。当JavaScript需要访问一个变量时,它会从当前作用域开始查找该变量。如果当前作用域中没有找到该变量,它就会依次向上级作用域查找,直到全局作用域window对象。这个逐级查找的过程就形成了作用域链。

作用域链的作用:保证对执行环境有权访问的所有变量和函数的有序访问,通过作用域链可以访问到外层的变量和函数。

示例

var x = 'global'; 
function outer() { var y = 'outer'; function inner() { var z = 'inner'; console.log(x); // 查找顺序:inner -> outer -> global,找到 'global' console.log(y); // 查找顺序:inner -> outer,找到 'outer' console.log(z); // 查找顺序:inner,找到'inner'}inner(); console.log(z); // z is not defined//访问z变量在outer作用域中,会报错,因为z只在inner作用域中 
} 
outer();

在这个例子中,inner函数的作用域链包括inner自身的作用域、outer函数的作用域以及全局作用域。当inner函数内部尝试访问变量x时,由于innerouter作用域中都没有x变量,所以会继续在全局作用域中查找,成功找到x的值为'global'

3.执行上下文

(1) 定义

执行上下文是指函数调用时在执行栈中产生的当前函数(或全局对象,如浏览器中的window)的执行环境。这个环境像是一个隔绝外部的容器,保管着可访问的变量、this对象等。

JavaScript中任何代码都是在执行上下文中运行的。执行上下文为代码的执行提供了必要的环境和信息。

(2)生命周期

执行上下文的生命周期可以分为三个阶段

创建阶段:在这个阶段,JavaScript引擎会进行词法分析、语法分析,确定作用域规则,并创建变量对象。对于全局执行上下文,变量对象就是全局对象(如window);对于函数执行上下文,变量对象包括函数参数、内部变量和函数声明等。同时,建立作用域链,确定this的指向。

执行阶段:在这个阶段,JavaScript引擎会逐行执行代码,进行变量赋值、函数调用等操作。执行上下文会根据词法环境和变量环境来执行代码,维护执行过程中的状态,如变量的值和执行的位置。如果遇到函数调用,会创建新的函数执行上下文,并将其压入执行栈的顶部。当函数执行完毕后,相应的执行上下文会从执行栈中弹出,控制权交给当前的栈顶执行上下文。

销毁阶段:当执行上下文执行完毕后,它会被销毁,并释放相关的资源。

(3)执行上下文栈

定义:执行上下文栈是一种用于管理执行上下文的数据结构,它遵循后进先出的原则。每当JavaScript引擎开始执行一段代码时,就会创建一个新的执行上下文,并将其压入执行栈中。当前正在执行的代码始终位于栈顶,执行完毕后会弹出栈顶的执行上下文。

作用:执行上下文栈确保了代码的执行顺序和上下文环境的正确管理。它允许JavaScript引擎在多个执行上下文之间切换,并在适当的时候销毁不再需要的执行上下文。

(4) 执行上下文的类型

JavaScript中有三种执行上下文:

全局执行上下文:任何不在函数内部的都是全局执行上下文,当JavaScript程序开始运行时创建的第一个执行上下文创建一个全局的window对象,设置this的值等于这个全局对象。

函数执行上下文:在调用函数时创建的执行上下文,它代表函数的作用域,而this的值取决于函数的调用方式。

Eval函数执行上下文:不常用。

简单来说,执行上下文是在执行JavaScript代码前,先解析代码。解析时先创建全局执行上下文环境,把代码中即将执行的变量和函数声明都拿出来,变量先赋值为undefined,函数先声明好。完成后,才开始正式的执行程序。在一个函数执行之前也会创建一个函数执行上下文环境,不过函数执行上下文会多this、arguments、函数的参数。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com