美文网首页
深入Js之我是如何搞懂作用域和闭包的

深入Js之我是如何搞懂作用域和闭包的

作者: 蛙哇 | 来源:发表于2020-04-16 15:39 被阅读0次

写在前面

理解作用域之前,我们需要先了解 JavaScript 的执行机制、调用栈和变量提升等知识点。如果想要深入了解概念可以谷歌查阅资料。

  • JavaScript 执行机制是先编译再执行,JavaScript 执行一段代码,JavaScript 引擎先会对其进行编译,并创建执行上下文
  • JavaScript 通过栈这种数据结构来管理执行上下文,创建好的执行上下文会被压入执行上下文栈中,执行上下文栈又称为调用栈。
  • 变量提升是指在 JavaScript 代码执行过程中,JavaScript 引擎把变量的声明部分和函数声明部分提升到代码开头的‘行为’变量被提升后会被赋予默认值 undefined。

作用域

作用域是指程序中定义变量的区域,该位置决定了变量的生命周期。通俗地理解,作用域就是变量与函数的可访问范围,即作用域控制着变量和函数的可见性和生命周期。

ES6 之前,ES 只有全局作用域和函数作用域。

  • 全局作用域中对象在代码中的任何地方都能被访问,其生命周期伴随着页面的生命周期。
  • 函数作用域就是在函数内部定义的变量或者函数,并且定义的变量或者函数只能在函数内部被访问。函数执行结束之后,函数内部定义的变量会被销毁。

ES6 新增 let 和 const 关键字实现块级作用域。

ES5 由于变量提升带来的变量会在不被察觉的情况下被覆盖掉、for 循环中本该被销毁的变量没有被销毁等一系列问题,为解决这些问题,ES6 引入 let 和 const 关键字,从而使 JavaScript 也能像其他语言一样拥有了块级作用域。

词法作用域

词法作用域定义:

词法作用域指变量的作用域不是执行时决定而是在定义时决定,也就是说通过静态分析就能确定,词法作用域取决于源码,因此词法作用域也叫做静态作用域。

我们可以通过下图进一步理解:

image

从图中可以看出,词法作用域就是根据代码的位置来决定的,其中 main 函数包含了 bar 函数,bar 函数中包含了 foo 函数,因为 JavaScript 作用域链是由词法作用域决定的,所以整个词法作用域链的顺序是:foo函数作用域-> bar 函数作用域-> main 函数作用域-> 全局作用域。词法作用域是代码阶段就决定好的,很函数是怎么点用的没有关系。

闭包

MDN 中对闭包的定义:

函数和对其周围状态(词法环境)的引用捆绑在一起构成闭包。

接下来我们结合下面代码来理解什么是闭包:

function foo() {
    var name = 'Top'
    let test1 = 1
    const test2 = 2
    var innerBar = {
        getName: function() {
            console.log(test1)
            return name
        },
        setName: function(newName) {
            name = newName
        }
    }
    return innerBar
}

var bar = foo()
bar.setName('You')
bar.getName()
console.log(bar.getName)

从上面的代码中可以看出,innerBar 是一个对象,包含了 getName 和 setName 的两个方法(通常我们把对象内部的函数称为方法)。你可以看到,这两个方法都是在 foo 函数内部定义的,并且这两个方法内部都使用了 name 和 test 两个变量。

根据词法作用域的规则,内部函数 getName 和 setName 总是可以访问它们外部函数 foo 中的变量, 所以当 innerBar 对象返回给全局变量 bar 时,虽然 foo 函数已经执行结束,但是 getName 和 setName 函数依然可以使用 foo 函数中的变量 name 和 test1。我们就可以把这个称之为 foo 函数的闭包。

好了,现在我们可以给闭包一个正式的定义了:在 JavaScript 中,根据词法作用域的规则,内部函数总是可以访问其外函数中声明的变量,当通过调用以恶搞外部函数返回一个内部函数后,即使该外部函数已经执行结束了,但是内部函数引用外部函数的变量依然保存在内存中,我们就把这些变量的集合称为闭包,比如外部函数 foo,那么这些变量的集合就称为 foo 函数的闭包。

写在最后

用心写篇文章不易,如果内容中有不妥的地方欢迎指正,当然博客只是学习参考的依据,真正要学到掌握还是需要自己下功夫和研究的。毕竟别人的理解并不一定是自己的理解。如果对你有所帮助欢迎点赞收藏,码字不易,大家加油!!!

相关文章

  • 深入Js之我是如何搞懂作用域和闭包的

    写在前面 理解作用域之前,我们需要先了解 JavaScript 的执行机制、调用栈和变量提升等知识点。如果想要深入...

  • js闭包的理解

    什么是闭包 通俗的来讲,个人觉得闭包就是延长变量作用域的函数。众所周知js的作用域分为全局作用域和链式作用域。在函...

  • JS博客

    JS构造函数及new运算符 JS原型对象和原型链 函数作用域和作用域链 干货分享:让你分分钟学会JS闭包 深入理解...

  • JS 闭包(Closure)

    参考阮一峰老师的JS 闭包 理解闭包前需要理解变量作用域、变量提升 JS作用域 那如何让它依次打印,12345呢;...

  • 进击的 JavaScript(三) 之 函数执行过程

    理解js 的执行过程是很重要的,比如,作用域,作用域链,变量提升,闭包啊,要想明白这些,你就得搞懂函数执行时到底发...

  • js 闭包

    一、js 作用域 讲闭包首先就要理解 js 的作用域。再 ES5 中,js 有两种作用域,全局作用域和函数作用域(...

  • 作用域和闭包

    目录 概述 作用域编译过程词法作用域全局作用域函数作用域 闭包循环和闭包闭包的用途性能 总结 概述 作用域和闭包一...

  • js函数中的this

    前两篇文章“执行环境和作用域”和“js中的闭包”,我对谈了执行环境、作用域、作用域链和闭包的理解。但当牵涉到对象中...

  • 学习JavaScript闭包和作用域笔记

    JS JavaScript闭包和作用域 闭包 JavaScript高级程序设计中对闭包的定义:闭包是指有权访问另外...

  • Javascript 闭包

    如果要了解闭包,我们需要先了解闭包的由来,闭包的产生,源于JS的词法作用域 词法作用域 作用域是指一个 变量能够访...

网友评论

      本文标题:深入Js之我是如何搞懂作用域和闭包的

      本文链接:https://www.haomeiwen.com/subject/vwarvhtx.html