JavaScript闭包和作用域链的定义实现

yizhihongxing

JavaScript闭包和作用域链的定义实现

什么是闭包?

在JavaScript中,闭包是指每个函数在创建时会生成一个自己的执行环境,这个执行环境可以访问到它自身定义的变量、参数,也可以访问父级的变量,而且这个执行环境可以一直存在,即使函数执行完,此时这个执行环境也不会被销毁。

简单来说,就是可以访问父级作用域的函数,创建出来的执行环境,这种执行环境中包含了函数内部定义的变量、参数以及外层函数和全局作用域中定义的变量。

闭包的实现方式

闭包的实现方式很简单,即函数内部又嵌套了一个函数,并且内部的函数引用了外部函数的变量或参数。这样的话,内部函数就形成了一个闭包,因为它可以访问到外部函数中的变量或参数。

下面是一个简单的闭包示例:

function outer() {
  var a = 1;
  return function inner() {
    console.log(a);
  }
}

var innerFunc = outer();
innerFunc(); // 输出:1

在这个示例中,outer返回了内部函数inner。内部函数使用了外部函数outer中的变量a,这种使用即为闭包。

什么是作用域链?

在JavaScript中,每一个执行环境都会有一个变量对象,叫做活动对象(activation object,AO)或者执行上下文(Execution context)。

"作用域链"是JavaScript中非常重要的概念之一。每一个函数的执行上下文中有一个变量对象,而这个变量对象中包含了当前作用域中所有的局部变量。在获取一个变量的时候,JavaScript会从当前执行上下文的变量对象中寻找,如果找不到则会从父级执行上下文的变量对象中寻找,直到找到全局执行上下文的变量对象。

即,当一个变量在当前执行上下文中被引用时,JavaScript会按照作用域链的顺序依次查找该变量所在的执行上下文,直到找到该变量所在的变量对象为止。

作用域链的实现方式

在JavaScript中,作用域的链式结构可以用一组对象来实现,这个对象集合被称为“作用域链”。

作用域链的实现与闭包密切相关,当一个函数调用时,它会创建一个新的执行上下文,并且在该执行上下文中自动创建一个新的作用域链,这个链的头节点指向该执行上下文的变量对象。

下面是一个示例:

var a = 1;
function outer() {
 var b = 2;
 function inner() {
   var c = 3;
   console.log(a + b + c);
 }
 inner();
}
outer(); // 输出:6

在这个示例中,当执行outer函数时,会在全局上下文中自动创建一个outer的函数执行上下文,它会在其自身的变量对象上查找变量b,并在其作用域链的下一级作用域对象上查找变量a,最后,在inner的执行上下文中查找到变量c。使用作用域链,我们可以在当前作用域上方的作用域中查找变量a的值。

示例说明

示例一

function getCounter() {
  var count = 0;
  return function inc() {
    count++;
    console.log(count);
  }
}

var counter = getCounter();
counter(); // 输出:1
counter(); // 输出:2

在这个示例中,函数getCounter返回了一个内部函数inc(即闭包),它引用了getCounter函数中的变量count。这里我们通过将闭包inc的引用赋值给counter,并调用它两次,捕获和维护了count变量的状态信息,每次调用输出递增的计数器值。

示例二

function createAdditionFunc(x) {
  return function(y) {
    return x + y;
  };
}

var addTen = createAdditionFunc(10);
console.log(addTen(5)); // 输出:15

在这个示例中,createAdditionFunc返回了一个闭包函数,该函数可以捕获到外部函数中传入的参数x的值,并返回一个内部函数addition,该函数在被调用时,可以接收参数y,并将外部函数的x和参数y相加并返回。

我们通过在创建addTen时向createAdditionFunc中传入参数10,就得到了一个新的闭包函数addTen,它的执行结果就是x为10时的返回结果。在我们调用addTen(5)时,就得到了15这个结果。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JavaScript闭包和作用域链的定义实现 - Python技术站

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

相关文章

  • JavaScript中的this引用(推荐)

    JavaScript中的this引用(推荐) 在JavaScript中,this是一个非常重要的关键字,它指向了当前执行代码的上下文对象。但是,它的使用也非常容易出现问题,特别是当它嵌套在其他对象中时。在本文中,我们将详细讲解this的引用,以及如何正确地使用它。 什么是this? this是一个指向当前执行代码的上下文对象的关键字。在JavaScript中…

    JavaScript 2023年6月10日
    00
  • 详解Typescript 严格模式有多严格

    详解Typescript 严格模式有多严格 简介 Typescript 自2.3版本开始引入了“严格模式”(Strict mode),它通过加强类型检查、禁用一些不安全的语法和行为等手段来让代码更规范、更健壮,从而减少意外的运行时错误。 在这篇文章中,我们将详细讲解 Typescript 严格模式的多个方面,并给出一些示例代码来进一步说明各个模式之间的区别。…

    JavaScript 2023年6月10日
    00
  • js内置对象处理_打印学生成绩单的简单实现

    下面将详细讲解“js内置对象处理_打印学生成绩单的简单实现”的完整攻略。 前置知识 在学习这个问题之前,你需要了解以下知识: JavaScript对象和数组的基础概念 for循环和while循环的基础使用方式 键值对的概念 代码的排版和注释 控制台输出console.log()的使用方法 如果你对以上概念不熟悉,建议先学习相关的基础教程。 问题描述 在这个问…

    JavaScript 2023年5月28日
    00
  • 详解用场景去理解函数柯里化(入门篇)

    详解用场景去理解函数柯里化(入门篇)完整攻略 什么是函数柯里化? 函数柯里化是一种将具有 n 个参数的函数转换成只接受一个参数的函数,并返回一个新函数的技术。这个新函数会接受剩余的参数并返回结果。这个过程就像为函数的第一个参数绑定值一样,常用的方式是使用闭包保存参数和状态,再通过函数的多次调用形成链式调用的效果。 柯里化的优势和适用场景 函数柯里化可以让你更…

    JavaScript 2023年5月19日
    00
  • Router解决跨模块下的页面跳转示例

    下面我就给你详细讲解一下“Router解决跨模块下的页面跳转示例”的完整攻略。 什么是Router Router即路由器,它可以在前端页面中实现页面之间的跳转。在Vue中,可以通过vue-router来实现路由功能。它基于Vue.js,可以非常方便地集成到Vue.js应用中。Vue Router可以让我们通过多个URL来展示多个页面,也可以在不同页面间进行导…

    JavaScript 2023年6月11日
    00
  • JavaScript关于数组的四道面试题

    以下是JavaScript关于数组的四道面试题的详细攻略: 面试题一:如何将数组扁平化? 问题描述 给定一个多维数组,如何将其转为一维数组,即扁平化? 解决方案 我们可以使用ES6的 flat 方法,该方法接收一个可选参数depth,指定展开的深度。当不传depth时,默认展开所有层级。 同时,为了兼容性,我们也可以使用递归实现深度优先的扁平化。 示例代码如…

    JavaScript 2023年5月27日
    00
  • js 函数性能比较方法

    当面临选择不同实现方式时,我们必须评估其可能影响到代码性能的部分。在 JavaScript 中函数的性能是由多种因素决定的。接下来将会介绍两种比较 JS 函数性能的方法。 1. 使用性能测试工具 我们可以使用性能测试工具,如 jsbenchmark 或者 jsperf,直接进行性能测试。这些测试工具提供了一些常见的测试用例,我们可以根据自己的需要编写自己的测…

    JavaScript 2023年5月27日
    00
  • js实现日历与定时器

    JS实现日历与定时器完整攻略 1. JS实现日历 1.1 核心思路 获取当地时间(年、月、日); 定义一个方法,将获取到的时间以日历的形式渲染到页面中; 监听页面上的事件,实现日历的下一页、上一页功能; 实现日历的跳转到具体某一天的功能。 1.2 代码实现 // 获取当前日期 function getDate() { const today = new Da…

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