深入理解JS的执行上下文、词法作用域和闭包(下)

简介: 深入理解JS的执行上下文、词法作用域和闭包(下)

四、总结 🎯


执行上下文、词法作用域和闭包的关系


在JavaScript中,执行上下文、词法作用域和闭包之间存在一些复杂的关系。下面详细解释这些关系:

执行上下文:


执行上下文是JavaScript中变量、函数和对象等执行时的上下文环境。JavaScript中,执行上下文主要包括全局执行上下文(Global Execution Context)和函数执行上下文(Functional Execution Context)。


全局执行上下文包含全局作用域中的变量、函数和对象等。函数执行上下文则包含函数词法作用域中的变量、函数和对象等。


当执行一段代码时,首先会创建全局执行上下文,将全局变量、函数和对象等放入其中。然后,按照代码中的函数调用顺序,依次创建函数执行上下文,并将函数词法作用域中的变量、函数和对象等放入其中。


词法作用域:


词法作用域是由代码文本中变量声明的位置决定的。在JavaScript中,词法作用域主要包括函数词法作用域和块级作用域。


函数词法作用域是指函数可以访问其词法作用域中的变量,即使这个函数在其词法作用域之外执行。块级作用域是指使用let、const声明的变量具有块级作用域,只能在声明它们的代码块(如for循环、if语句等)内部访问。


词法作用域主要影响变量的查找和函数的调用。当需要在某个作用域中查找变量或调用函数时,JavaScript会按照词法作用域的规则,从当前作用域开始,向上级作用域逐层查找,直到找到为止。


闭包:


闭包(Closure)是JavaScript中一种重要的概念,它指的是一个函数可以访问其词法作用域中的变量,即使这个函数在其词法作用域之外执行。


闭包的主要特点包括函数可以记住并访问其词法作用域,即使这个作用域在函数执行完毕后被销毁。当一个函数在其词法作用域之外执行时,即使这个作用域在函数执行完毕后被销毁,该函数仍然可以访问其词法作用域中的变量。


总之,执行上下文、词法作用域和闭包之间的关系主要体现在以下几个方面:


  • 执行上下文是JavaScript中变量、函数和对象等执行时的上下文环境,词法作用域主要影响变量的查找和函数的调用。
  • 词法作用域是由代码文本中变量声明的位置决定的,闭包指的是一个函数可以访问其词法作用域中的变量,即使这个函数在其词法作用域之外执行。
  • 闭包可以让函数记住并访问其词法作用域,即使这个作用域在函数执行完毕后被销毁。


实际项目中,可以根据具体需求和场景,灵活地使用执行上下文、词法作用域和闭包等概念。


理解这些概念对编程的重要性 💪


理解执行上下文、词法作用域和闭包对编程的重要性主要体现在以下几个方面:


提高代码的可读性和可维护性:理解这些概念有助于更好地理解JavaScript中的变量作用域和函数调用等问题,从而提高代码的可读性和可维护性。


例如,理解词法作用域可以让我们更好地理解以下代码:

function foo() {
  let a = 1;
  function bar() {
    console.log(a); // 输出 1
  }
  bar();
}

foo();

在这个例子中,bar函数在其词法作用域foo之外执行,但仍然可以访问foo作用域中的变量a。理解词法作用域有助于我们更好地理解这个例子。


避免变量污染和冲突:理解执行上下文和词法作用域可以帮助我们更好地管理变量的作用域,避免全局作用域和函数作用域中的变量冲突。


例如,以下代码会导致全局作用域和函数作用域中的变量冲突:

let a = 1;

function foo() {
  let a = 2;
  console.log(a); // 输出 2
}

foo();
console.log(a); // 输出 2

在这个例子中,全局作用域和函数作用域中的变量a冲突,导致输出结果不符合预期。理解执行上下文和词法作用域有助于我们避免这种错误。


实现模块化和封装:闭包可以让函数记住并访问其词法作用域,即使这个作用域在函数执行完毕后被销毁。这使得我们可以将一组相关的函数和变量封装在一个函数内部,然后返回这个函数的引用,这样就可以在其他地方调用这些函数并访问它们需要的变量。


例如,使用闭包实现一个简单的模块:

function createCart() {
  let products = [];

  function addProduct(product) {
    products.push(product);
  }

  function getProducts() {
    return products;
  }

  return {
    addProduct,
    getProducts
  };
}

const cart = createCart();
cart.addProduct({ id: 1, name: 'Product 1' });
console.log(cart.getProducts()); // 输出:[{ id: 1, name: 'Product 1' }]

在这个例子中,createCart函数返回一个闭包,包含addProduct和getProducts函数以及它们需要的变量products。这样可以实现模块化,将一组相关的函数和变量封装在一个函数内部。


总之,理解执行上下文、词法作用域和闭包对编程的重要性主要体现在提高代码的可读性和可维护性、避免变量污染和冲突以及实现模块化和封装等方面。实际项目中,可以根据具体需求和场景,灵活地使用这些概念。


实际应用中的注意事项和最佳实践 👀


在实际应用中,关于执行上下文、词法作用域和闭包,有一些注意事项和最佳实践:

使用letconst声明变量:在声明变量时,建议使用letconst而不是varletconst声明的变量具有块级作用域,可以在声明它们的代码块(如for循环、if语句等)内部访问,而var声明的变量具有函数作用域,可以在整个函数内部访问。


例如,以下代码使用let声明变量:

function foo() {
  let a = 1;
  function bar() {
    console.log(a); // 输出 1
  }
  bar();
}

foo();

而以下代码使用var声明变量:

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

foo();

使用函数执行上下文:在实际项目中,可以使用函数执行上下文来封装一组相关的函数和变量,这样可以实现模块化和封装。


例如,以下代码使用函数执行上下文:

function createCart() {
  let products = [];

  function addProduct(product) {
    products.push(product);
  }

  function getProducts() {
    return products;
  }

  return {
    addProduct,
    getProducts
  };
}

const cart = createCart();
cart.addProduct({ id: 1, name: 'Product 1' });
console.log(cart.getProducts()); // 输出:[{ id: 1, name: 'Product 1' }]

避免全局作用域污染:在实际项目中,避免全局作用域污染非常重要。全局作用域中的变量和函数可能会影响到其他代码,导致难以维护和调试。可以使用闭包来避免全局作用域污染。


例如,以下代码使用闭包避免全局作用域污染:

function createCounter() {
  let count = 0;
  return function() {
    count += 1;
    console.log(count); // 输出 1 2 3
  };
}

const counter = createCounter();
counter();
counter();
counter();

总之,在实际应用中,关于执行上下文、词法作用域和闭包,需要注意使用let、const声明变量,使用函数执行上下文封装相关函数和变量,以及避免全局作用域污染。这些注意事项和最佳实践有助于提高代码的可读性和可维护性,降低代码的耦合度,使代码更加清晰和易于维护。


参考资料

[1]《JavaScript 高级程序设计》

[2] MDN Web Docs: JavaScript


相关文章
|
23天前
|
存储 JavaScript 前端开发
解释 JavaScript 中的作用域和作用域链的概念。
【4月更文挑战第4天】JavaScript作用域定义了变量和函数的可见范围,静态决定于编码时。每个函数作为对象拥有`scope`属性,关联运行期上下文集合。执行上下文在函数执行时创建,定义执行环境,每次调用函数都会生成独特上下文。作用域链是按层级组织的作用域集合,自内向外查找变量。变量查找遵循从当前执行上下文到全局上下文的顺序,若找不到则抛出异常。
21 6
|
24天前
|
JavaScript
闭包(js的问题)
闭包(js的问题)
12 0
|
1月前
|
设计模式 JavaScript 前端开发
js开发:请解释闭包(closure)是什么,以及它的用途。
闭包是JavaScript中的关键特性,允许函数访问并操作外部作用域的变量,常用于实现私有变量、模块化和高阶函数。私有变量示例展示了如何创建无法外部访问的计数器;模块化示例演示了封装私有变量和函数,防止全局污染;高阶函数示例则说明了如何使用闭包创建能接收或返回函数的函数。
16 2
|
1月前
|
存储 缓存 JavaScript
|
1月前
|
自然语言处理 JavaScript 前端开发
探索JavaScript中的闭包:理解其原理与实际应用
探索JavaScript中的闭包:理解其原理与实际应用
20 0
|
2天前
|
测试技术
js_防抖与节流(闭包的使用)
js_防抖与节流(闭包的使用)
7 0
|
1月前
|
JavaScript 前端开发 Java
深入剖析 JavaScript 闭包
深入探讨JavaScript闭包,了解其定义、特性、优缺点及作用。闭包是函数与其引用环境的组合,允许内层函数访问外层作用域,常驻内存可能导致内存泄露。优点包括创建私有变量,缺点则涉及内存使用。闭包在变量搜索中遵循从内到外的规则,并影响变量的作用域和生存周期。理解闭包有助于优化代码并避免性能问题。
21 1
|
1月前
|
JavaScript 前端开发
js开发:请解释什么是作用域(scope),并说明全局作用域、局部作用域和块级作用域的区别。
JavaScript中的作用域规定了变量和函数的可见性与生命周期。全局作用域适用于整个脚本,变量可通过全局对象访问,可能导致命名冲突和内存占用。局部作用域限于函数内部,每次调用创建新作用域,执行完毕后销毁。ES6引入的块级作用域通过`let`和`const`实现,变量仅在其代码块内有效,并有暂时性死区。作用域机制有助于代码组织和变量管理。
23 1
|
1月前
|
自然语言处理 前端开发 JavaScript
深入理解JavaScript中的闭包与作用域链
在JavaScript编程中,闭包和作用域链是两个非常重要的概念,它们对于理解代码的执行过程和解决一些特定问题至关重要。本文将深入探讨JavaScript中闭包和作用域链的原理和应用,帮助读者更好地理解这些概念并能够在实际项目中灵活运用。
|
1月前
|
JavaScript 前端开发
JS作用域与作用域链
JS作用域与作用域链