浅析JavaScript作用域链、执行上下文与闭包

yizhihongxing

让我来为你详细讲解一下“浅析JavaScript作用域链、执行上下文与闭包”的完整攻略。

一、作用域链

作用域是指程序中的变量能够被访问的范围。JavaScript采用的是词法作用域,也就是在定义变量时就确定了变量的作用域。作用域链就是由当前执行环境与其上层环境的变量对象组成的链表。在查找变量时,会沿着这个链表一级一级地向上查找,直到找到为止。如果最终还没有找到,则会返回一个“undefined”的值。

例如,我们定义了以下代码:

function foo() {
  var x = 10;
  function bar() {
    console.log(x);
  }
  return bar;
}
var b = foo();
b();

在上面的代码中,变量x同时存在于函数foo和函数bar的作用域中,因为JavaScript采用的是词法作用域,所以变量x在函数bar中的值也是10。在执行b()时,JavaScript引擎会从bar函数的活动对象开始,查找变量x,由于没有找到,会继续往上一层的作用域中查找,即函数foo的变量对象中查找,最终找到了x的值为10。

二、执行上下文

执行上下文是执行JavaScript代码时所在的环境。一个执行上下文可以包含多个作用域链,也就是说,一个函数执行时会创建一个执行上下文。每个执行上下文都有三个重要的属性:变量对象、作用域链和this指针。

2.1 变量对象

变量对象是一个包含执行上下文中定义的所有局部变量的对象。在函数执行前,JavaScript引擎会先创建一个变量对象,然后将其中的所有形参、函数声明和变量声明都添加到变量对象中。

例如,在以下代码中:

function foo(x, y) {
  console.log(x + y)
}
foo(1, 2)

在函数foo执行之前,JavaScript引擎会先创建一个变量对象,然后将xy作为形参添加到变量对象中。

2.2 作用域链

作用域链是由执行上下文的变量对象和其所有上层环境的变量对象组成的链表。在查找变量时,JavaScript引擎会沿着作用域链一级一级向上查找,直到找到变量为止。如果最终还没有找到,就会返回一个“undefined”的值。

以函数bar为例,在函数执行时,JavaScript引擎会创建一个执行上下文。其中的作用域链就是由bar函数的变量对象和它上一层的函数foo的变量对象组成的链表。

2.3 this指针

this指针指向函数执行的上下文对象。在全局执行上下文中,this指向全局对象window。而在函数执行过程中,this指向的则是当前函数的调用对象。

例如,在以下代码中:

var name = 'global';
function foo() {
  console.log(this.name);
}
var obj = {
  name: 'object',
  foo: foo
}
foo(); // 输出 global
obj.foo(); // 输出 object

在全局执行上下文中,this指向全局对象window,因此在函数foo中,this.name的值为global。而在调用对象为obj时,this指向obj对象,因此在执行obj.foo()时,this.name的值为object

三、闭包

闭包是指一个函数可以访问另一个函数作用域中的变量,即使这个函数已经返回了。在JavaScript中,闭包是通过函数中嵌套函数来实现的。

例如,在以下代码中:

function counter() {
  var count = 0;
  return function() {
    count++;
    console.log(count);
  }
}
var c1 = counter();
c1(); // 输出 1
c1(); // 输出 2
var c2 = counter();
c2(); // 输出 1

在函数counter中,我们定义了一个变量count,然后返回了一个嵌套在其中的函数。这个嵌套的函数就可以访问到变量count的值,并且每次调用都会对其进行修改。由于嵌套函数可以访问到其外层函数的局部变量,因此我们可以将函数counter看作是一个闭包。

四、结语

通过以上的浅析,我们可以更好地理解JavaScript中作用域链、执行上下文与闭包的概念和实现原理。作用域链可以帮助我们在查找变量时快速找到其所在的作用域,而执行上下文则是一个包含作用域链、变量对象和this指针的对象。而通过闭包,我们可以更方便地访问函数外层的变量,从而实现更加灵活的编程。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:浅析JavaScript作用域链、执行上下文与闭包 - Python技术站

(0)
上一篇 2023年6月10日
下一篇 2023年6月10日

相关文章

  • 基于JS组件实现拖动滑块验证功能(代码分享)

    基于JS组件实现拖动滑块验证功能的攻略如下: 1. 需求分析 首先需要了解业务需求和实现方式,即用户需要通过拖动滑块来完成验证。可以使用JS组件来实现这个功能。 2. 准备工作 在实现之前,需要准备一个简单的web页面,引入所需的JS文件,以及动态生成所需的HTML元素等。完整的代码在下面的代码块中: <!DOCTYPE html> <ht…

    JavaScript 2023年6月10日
    00
  • vscode下vue项目中eslint的使用方法

    下面将详细讲解”VSCode下Vue项目中ESLint的使用方法”。 1. 确认环境安装及配置 在使用 ESLint 前,首先确保环境已经安装: Node.js 安装:前往 Node.js 官网 下载对应版本进行安装。 Vue CLI 安装:使用 npm 全局安装。 npm install -g vue-cli ESLint 安装:使用 npm 全局安装。 …

    JavaScript 2023年6月11日
    00
  • js导出txt示例代码

    JS导出文本文件是一种非常常见的操作,本文将详细讲解JS导出Txt示例的完整攻略。 具体步骤 第一步:准备要导出的文本内容 在JS中,我们需要定义一些变量来存储要导出的文本内容。这些变量可以是任何数据类型,比如字符串、数组等。 let textToExport = "这是一段要导出的文本内容"; 第二步:创建要导出的链接 在JS中,我们使…

    JavaScript 2023年5月27日
    00
  • 详解ES6之用let声明变量以及let loop机制

    以下是关于“详解ES6之用let声明变量以及let loop机制”的完整攻略: 一、let声明变量 ES6中新增了let关键字,用于声明变量。let作用域是块级的作用域,而不是全局作用域。 1. let的基本使用 使用let声明变量,可以通过相同的语法进行赋值和修改值。例如: let count = 1; count = 2; console.log(cou…

    JavaScript 2023年6月10日
    00
  • js时间戳和c#时间戳互转方法(推荐)

    下面为您详细讲解“js时间戳和c#时间戳互转方法(推荐)”的完整攻略。 背景介绍 在前端开发和后端开发的交互过程中,可能会涉及到时间的转换,例如前端的js时间戳和后端的c#时间戳。在这种情况下,需要掌握js时间戳和c#时间戳的互转方法。 js时间戳和c#时间戳的定义 js时间戳:指距离1970年1月1日00:00:00的毫秒数。可以使用 Date.now()…

    JavaScript 2023年5月27日
    00
  • java后台实现js关闭本页面,父页面指定跳转或刷新操作

    实现JS关闭本页面、父页面指定跳转或刷新操作需要通过JavaScript与Java后台交互实现。下面详细讲解完整攻略: 第一步:前端代码js关闭本页面 在前端通过JavaScript实现关闭本页面的方法为: window.close(); 第二步:通过Java后台实现父页面跳转或刷新操作 通过Java后台实现父页面的跳转或刷新操作需要借助JavaScript…

    JavaScript 2023年6月11日
    00
  • tree shaking对打包体积优化及作用

    什么是Tree Shaking Tree Shaking 是指在打包过程中,检测出未被引用的代码,并在最终打包结果中将这些未引用的代码(也被称为“未引用代码(dead code)”)移除。Tree Shaking 目的是为了精简打包后的代码和减小文件体积,提升网页加载速度。 在理解 Tree Shaking 之前需要了解几个概念:- 模块 (Module):…

    JavaScript 2023年6月11日
    00
  • Ajax请求时无法重定向的问题解决代码详解

    标题:Ajax请求时无法重定向的问题解决代码详解 问题背景 在使用Ajax发送请求时,由于其异步请求的特性以及浏览器的同源策略,可能会出现无法重定向的问题。在某些情况下,我们希望在请求成功后自动跳转到另一个页面或者链接,要如何解决呢? 解决方案 方案一:在服务端进行重定向 我们可以在服务端进行处理,当接收到Ajax请求时,服务端判断请求来源是否为Ajax,并…

    JavaScript 2023年6月11日
    00
合作推广
合作推广
分享本页
返回顶部