关于 JS 闭包的一些理解

98 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 4 天,点击查看活动详情

闭包

闭包是指那些引用了另一个函数作用域中变量的函数,通常实在嵌套函数中实现的

function createComparisonFunction(propertyName) {
  return function (object1, object2) {
    // 下面两行代码引用了外部函数的变量 propertyName
    let value1 = object1[propertyName];
    let value2 = object2[propertyName];
    if (value1 < value2) {
      return -1;
    } else if (value1 > value2) {
      return 1;
    } else {
      return 0;
    }
  };
}

函数执行过程中作用域链的变化

函数执行时,每个执行上下文都会有一个包含其中变量的对象

执行上下文

执行上下文是评估执行 JavaScript 代码的环境的抽象概念。 JavaScript 代码在运行时,都是在执行上下文中运行的。

执行上下文的类型

执行上下文存在三种类型

  • 全局执行上下文: 这是默认的上下文,任何不再函数内部的代码都在全局上下文中。他会执行两件事: 创建一个全局对象 (在浏览器中为 window 对象,在 node 环境下为 global 对象),并且设置this 指向这个全局对象; 一个程序中有且只有一个全局执行上下文

  • 函数执行上下文: 每当一个函数被调用是,都会为这个函数创建一个新的执行上下文。每个函数都有他自己的执行上下文。函数执行上下文可以有任意多个。每当创建一个函数执行上下文是,都会按照一定的顺序执行一系列步骤

  • Eval 函数执行上下文: eval 函数内部的代码会有属于它自己的执行上下文。

function compiler(value1, value2){
  if(value1 > value2){
    return 1
  }else if(value1 < value2){
    return -1
  }else{
    return 0
  }
}
let result = compiler(1,10)

执行上下文建立步骤

    1. 创建阶段 创建执行上下文
    1. 创建作用域链 创建作用域链
    1. 创建活动对象 创建活动对象后,会将对用对象推入作用域链的最前端 创建作用域链
    1. 执行代码

this 对象

在闭包中使用 this 会变得复杂。如果内部函数没有使用箭头函数定义,则内部函数的 this 对象会在运行是绑定到函数的执行上下文中。在全局中调用,非严格模式下, this 只想 window,严格模式下,thisundefined

立即调用的函数表达式

立即调用匿名函数又被成为立即调用的函数表达式(IIFE)。

// 立即调用函数
(function(){})()

使用 IIFE 锁定参数值

let divs = document.querySelectorAll('div'); 
// 达不到目的!每次点击打印都为 divs.length
for (var i = 0; i < divs.length; ++i) {
  divs[i].addEventListener('click', function() {
    console.log(i);
  });
}

使用 IIFE 解决上述问题

let divs = document.querySelectorAll('div');
for (var i = 0; i < divs.length; ++i) {
  divs[i].addEventListener('click', (function (frozenCounter) {
    return function () {
      console.log(frozenCounter);
    };
  })(i));
}