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

浏览器是如何看闭包的?

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

那么,当浏览器解析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日

相关文章

  • js获取事件源及触发该事件的对象

    获取事件源对象和触发该事件的对象是 Javascript 事件处理的重要操作。下面,我将为大家分享完整的攻略。 获取事件源对象 事件源对象指的是触发该事件的元素或节点。通常,我们使用 event.target、event.srcElement 等属性来获取事件源对象。 event.target:事件发生时,事件的目标节点(最深嵌套的节点)。 event.sr…

    JavaScript 2023年6月10日
    00
  • Promise+async+Generator的实现原理

    下面是 Promise+async+Generator 的实现原理的完整攻略: Promise 的实现 Promise 内部维护了一个状态值,有三种状态:pending, fulfilled 和 rejected。 在 Promise 内部定义了 resolve 和 reject 两种方法,用于设置异步操作成功和失败后的返回结果。 Promise 内部还定义…

    JavaScript 2023年5月27日
    00
  • js正则表达式讲解之index属性(RegExp对象)

    JS正则表达式讲解之index属性(RegExp对象) 什么是正则表达式的index属性? 在JavaScript中,正则表达式是RegExp对象的实例。RegExp对象有一个名为index的属性,用于表示正则表达式匹配的最后一个字符的位置。 例如,对于字符串”hello world”,正则表达式/world/匹配的最后一个字符是d,其在字符串中的位置是8(…

    JavaScript 2023年6月10日
    00
  • JavaScript 语法集锦 脚本之家基础推荐

    JavaScript 语法集锦 脚本之家基础推荐 简介 脚本之家作为国内知名的编程学习网站之一,提供了全面而丰富的 JavaScript 学习资源。其中,JavaScript 语法集锦作为脚本之家网站中最为基础和重要的知识点之一,需要我们关注和掌握。 本篇攻略将整理和总结脚本之家网站中 JavaScript 语法集锦的相关内容,帮助初学者对 JavaScri…

    JavaScript 2023年5月18日
    00
  • JS sort排序详细使用方法示例解析

    JS sort排序详细使用方法示例解析 在 Javascript 中,sort() 是一个常用的排序函数。sort() 可以按照数组元素的字母排序,也可以按照数字大小排序。 sort() 语法 sort() 函数的语法如下: array.sort(sortFunction) 其中,sortFunction 是可选的参数。如果省略该参数,那么 sort() 函…

    JavaScript 2023年6月11日
    00
  • 12个提高JavaScript技能的概念(小结)

    下面我将详细讲解“12个提高JavaScript技能的概念(小结)”的完整攻略。 1. 箭头函数 箭头函数是 ES6 中的新语法,它可以让我们更方便、简洁地创建函数,而且还有一些特殊的作用域规则。箭头函数的语法示例如下: const sum = (a, b) => a + b; 在上面的示例中,我们定义了一个名为 sum 的箭头函数,它接受两个参数 a…

    JavaScript 2023年5月18日
    00
  • JavaScript编写Chrome扩展实现与浏览器的交互及时间通知

    下面是详细讲解“JavaScript编写Chrome扩展实现与浏览器的交互及时间通知”的完整攻略。 1. 创建Chrome扩展 首先,我们需要创建一个Chrome扩展来实现与浏览器的交互和时间通知。在扩展文件夹中创建以下文件和文件夹: manifest.json:必须的扩展文件,其中包含了扩展的名称、描述、版本和其他元数据。 popup.html:扩展的弹出…

    JavaScript 2023年6月11日
    00
  • JavaScript函数调用经典实例代码

    JavaScript函数调用经典实例代码攻略: 一、函数调用方式 JavaScript 中函数的调用分为四种方式: 函数调用 直接调用函数。 javascript function fn1() { console.log(“fn1 被调用了”); } fn1(); 方法调用 将函数作为对象的一个属性,通过该对象调用函数。 javascript var obj…

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