详细聊聊浏览器是如何看闭包的

yizhihongxing

浏览器是如何看闭包的?

首先,让我们来回顾一下什么是闭包。闭包是在定义函数时创建的一种特殊作用域。可以访问父级作用域中定义的变量和函数,即使父级作用域已经被销毁了。这使得我们可以创建私有变量和函数,也可以用于实现某些高级特性,例如函数记忆和柯里化等。

那么,当浏览器解析Javascript代码时,是如何看待闭包的呢?以下是完整攻略:

  1. 函数作用域

Javascript 采用的是函数作用域,在函数内部定义的变量和函数只能在该函数内部被访问,即使其他代码块也不能访问。当函数执行结束后,这些变量和函数的引用也随之销毁。

function foo() {
  var a = 1;
  function innerFoo() {
    console.log(a);
  }
  innerFoo();
}
foo();  // 输出 1
  1. 闭包

当函数中嵌套函数并且内部函数可以访问父级函数中的变量时,就产生了闭包。内部函数可以访问父级函数中的变量,并且随着父级函数的执行而存活,不受父级函数执行完毕的影响。

function foo() {
  var a = 1;
  function innerFoo() {
    console.log(a);
  }
  return innerFoo;
}
var inner = foo();
inner();  // 输出 1

在这个例子中,当调用 foo 函数时,内部函数 innerFoo 被返回并赋值给变量 inner。此时,innerFoo 函数依然可以访问到父级函数 foo 中的变量 a。当调用 inner 函数时,输出变量 a 的值 1。

  1. 内存空间的管理

由于闭包的特殊作用域,函数执行结束后不能立即销毁内存,因为内部函数可能会持有外部变量的引用。这就需浏览器在内存空间中维护完整的作用域树并对其进行垃圾回收。

在一些复杂的场景中,闭包可能会导致内存泄漏问题。当内部函数持有父级函数中的变量引用并且父级函数不被销毁时,内存就会一直被占用。因此,我们应该避免滥用闭包,尤其是在循环中使用闭包引用循环变量。

示例一:

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

var counter1 = createCounter();
counter1();  // 输出1
counter1();  // 输出2

var counter2 = createCounter();
counter2();  // 输出1

在这个例子中,createCounter 函数返回了一个匿名函数,并且内部函数可以访问父级函数中的变量 count,每次调用内部函数 count 的值都会加 1。我们可以创建多个计数器并且每个计数器都有自己的 count 变量。

示例二:

function bindEvent() {
  var btns = document.querySelectorAll('button');
  for (var i = 0; i < btns.length; i++) {
    btns[i].addEventListener('click', function () {
      console.log(i);
    });
  }
}

bindEvent();

在这个例子中,我们希望为每个按钮添加点击事件,并在点击时输出按钮的索引。如果你以为这样写是正确的,那么你就错了。由于内部函数持有外部变量的引用,所有点击事件中输出的 i 都是相同的,并且等于 for 循环结束后的值 btns.length。正确的写法是使用闭包将 i 保存在一个新的函数作用域中。

function bindEvent() {
  var btns = document.querySelectorAll('button');
  for (var i = 0; i < btns.length; i++) {
    (function (index) {
      btns[index].addEventListener('click', function () {
        console.log(index);
      });
    })(i);
  }
}

bindEvent();

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详细聊聊浏览器是如何看闭包的 - Python技术站

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

相关文章

  • Typescript中函数类型及示例详解

    Typescript中的函数类型可以通过声明函数的参数类型、返回值类型及函数主体来限制函数的使用。在使用Typescript开发中,了解函数类型及其使用方法是非常重要的,下面介绍Typescript中函数类型的详细攻略。 一、函数类型的定义 在Typescript中,可以使用以下两种方式来定义函数类型: 1.函数声明式定义函数类型 如下例所示,我们使用声明式…

    JavaScript 2023年6月10日
    00
  • JavaScript中闭包的写法和作用详解

    JavaScript中闭包的写法和作用详解 什么是闭包 闭包是指有权访问另一个函数作用域中的变量的函数。闭包是JavaScript中最强大的特性之一,也是最容易误用而降低性能的特性之一。 举个例子: function outer() { let name = "Bob"; function inner() { console.log(na…

    JavaScript 2023年6月10日
    00
  • PHP使用正则表达式获取微博中的话题和对象名

    使用正则表达式获取微博中的话题和对象名是一个常见的需求,本篇攻略将详细介绍如何使用PHP实现这一功能。 步骤一:获取微博内容 首先,我们需要获取微博的内容。可以使用curl等工具,通过API或者爬虫获取微博的HTML源代码。在本例中,我们使用curl来获取微博的HTML源代码。 $ch = curl_init(); curl_setopt($ch, CURL…

    JavaScript 2023年6月10日
    00
  • Jil,高效的json序列化和反序列化库

    Jil是一个高效的Json序列化和反序列化库,完全基于C#实现。它被设计为尽可能快地进行序列化、反序列化操作,同时也是安全和灵活的。 安装 你可以从NuGet库中安装Jil:通过Package Manager控制台输入命令”Install-Package Jil”或者在Visual Studio中选择“项目” -> “管理NuGet软件包”,在搜索框中…

    JavaScript 2023年5月27日
    00
  • gulp-htmlmin压缩html的gulp插件实例代码

    下面是“gulp-htmlmin压缩html的gulp插件实例代码”的完整攻略。 什么是gulp-htmlmin gulp-htmlmin 是一个用于压缩 HTML 文件的 Gulp 插件。 安装gulp-htmlmin 在使用 gulp-htmlmin 之前,需要先安装 Gulp 和 gulp-htmlmin,可以使用以下命令安装: npm install…

    JavaScript 2023年6月10日
    00
  • js闭包和垃圾回收机制示例详解

    1. 什么是JavaScript闭包? 在JavaScript中,当一个函数访问到它定义的外部变量时,就创建了闭包。通俗的说,闭包就是一个函数和执行该函数的环境的组合体。 闭包的作用在于:可以将数据进行封装,使得外部无法访问到函数内部的数据,而只能通过暴露出的接口方法进行访问。这种特性很常见,比如函数库的实现、异步回调等等,都需要使用闭包。 下面是一个简单的…

    JavaScript 2023年6月10日
    00
  • 原生js实现无限循环轮播图效果

    原生JS实现无限循环轮播图的步骤如下: 定义样式和HTML结构 先定义轮播图的样式和HTML结构,可以用一个ul包含多个li标签,每个li标签里放置一张图片。 <div> <ul class="slider"> <li><img src="image1.jpg" alt=&qu…

    JavaScript 2023年6月11日
    00
  • JSON.parse损坏大数字的原因解析及解决方案

    出现问题的原因: 在使用JSON.parse()解析带有大数字的JSON字符串时,很可能会出现精度丢失的问题,导致解析后的数据与原数据不一致。这是由于JavaScript语言中最大的安全数字为 9007199254740991(2^53 – 1),超过这个数字范围后,会发生精度损失,从而导致数据不准确。 解决方案: 为了避免这种情况的发生,我们可以将JSON…

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