js 重难点——闭包+作用域链

108 阅读3分钟

作用域链和闭包是 JavaScript 中非常重要的概念,它们为我们理解语言的作用域和变量的生命周期提供了关键的知识。在本文中,我将会深入讨论这两个概念,并探讨它们在实际开发中的应用和影响。

作用域链

在 JavaScript 中,作用域链是通过词法环境来确定某个作用域的外层作用域的一种链状关系。当代码在一个作用域中查找变量时,它会首先在当前作用域中查找,如果找不到,就会顺着作用域链向上一级作用域中继续查找,直至找到该变量或者抵达全局作用域。(函数的词法环境就是他的外层作用域即上一级作用域,简单来讲,函数声明在哪就是词法环境就是哪。)作用域链的形成是由代码的结构和函数的嵌套关系所决定的。

例子:

var a = 2
function add(){
    var b = 10
    return a + b
}
add()

图解:(箭头代表查找顺序)

闭包1.png

作用域链的理解有助于我们正确地使用变量,避免变量名冲突以及更好地理解闭包的工作原理。

闭包

闭包是 JavaScript 中一个非常强大的特性,它可以让内部函数访问外部函数中的变量。当外部函数返回一个内部函数后,即使外部函数已经执行完毕,但内部函数依然可以访问外部函数中的变量。这是因为闭包中包含了外部函数的词法环境,使得外部函数中的变量在内存中得以保存。

上面是比较官方的说法。通俗来说,当一个函数执行完毕,按理说该函数执行上下文应该被清除掉,但因为这个函数中有变量在外层需要被使用,这个时候就会把这个函数其余不需要的清除,留下需要被使用到的东西,这些留下的就叫做这个函数的闭包,其实就是清了,但没完全清除。

闭包的优点之一是能够实现私有化变量,这意味着我们可以创建只能在特定作用域中访问的变量,从而更好地控制数据的可见性和安全性。然而,闭包也可能导致内存泄漏的问题(内存泄漏是专业术语,但它其实是指程序在动态分配内存后,由于某种原因未能释放或重新分配这部分内存,导致系统的可用内存不断减少,直至耗尽,从而影响系统的正常运行。),因为外部函数中的变量会被持续引用,即使其在逻辑上已经不再需要。

作用域链和闭包的应用

例子:

function a(){
    function b(){
        var name = 1
        console.log(count);
    }
    var count = 2
    return b
}
var c = a()
c()

图解:(箭头代表查找顺序)

闭包2.png

在实际开发中,作用域链和闭包也经常被用于异步编程、事件处理和内存管理等方面。了解它们的内部工作原理有助于我们更好地利用这些特性,并避免一些潜在的陷阱和性能问题。

总结来说,作用域链和闭包是 JavaScript 中极其重要的概念,它们对于理解语言的核心机制以及编写高效、健壮的代码都具有重要意义。