前端面试必学!JS闭包底层原理( 深入js作用域AO GO)

本文详细阐述了JavaScript的AO(执行上下文)、GO(全局对象)和作用域链原理,通过实例讲解闭包形成过程,并探讨了防抖和节流的典型应用。重点剖析了闭包如何通过作用域链保持变量持久性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

请添加图片描述

在深入闭包的底层原理之前,先深入JS作用域

AO

AO的步骤:

  1. 再函数被调用之前,创建AO(Activation Object)对象,又叫执行期上下文;(上下文是唯一的,一个函数被多次被调用时会创建多个上下文)
  2. 寻找形式参数和变量声明作为AO的属性名,并赋值为undefined;
  3. 传入实际参数的值;
  4. 在函数体内寻找函数声明,放入作为AO的属性,并赋值为其函数体。
先看一个阿里面试题的例子:
function test(a,b){
    console.log(a)     
    function a(){};
    console.log(a)
    console.log(c)
    console.log(b)
    var b = function(){}
    console.log(b)
    function c(){}
}
test(1,2)

//解析
//在test被调用之前,会创建执行上下文 AO:{};寻找形式参数和变量声明作为AO的属性名,并赋值为undefined
AO{
    a:undefined
    b:undefined
    c:undefined
}
//首先看a : 在test(1,2)传入实际参数后  可以知道 a被赋值1  ===>  a:1
//然后再函数体内寻找函数声明 * 函数声明一定要以函数function开头 不是以function的函数不能作为声明函数  test函数中存在 "function a(){}" 给a赋予函数体
// 此时 a:function(){}
test(1,2) 控制台分别输出
ƒ a(){}
ƒ a(){}
ƒ c(){}
2
ƒ (){}


1.2 Go

GO GO步骤:

创建GO(Global Object)对象; 寻找变量声明作为GO的属性名,并赋值为undefined;
寻找函数声明,放入作为GO的属性,并赋值为其函数体。
----------------------------------------------------同AO一样----------------------------------------------------

1.3 scope

【scope】:作用域链,是 [AO+Go]的集合
运行期上下文:当函数执行时,会创建一个名为执行期上下文的内部对象,它定义了一个函数执行时的环境。
函数每次执行时其上下文是唯一的,多次调用一个函数会生成多个执行期上下文,当函数调用完,其对应的执行期上下文被销毁。
查找变量时则从作用域的顶端开始查找。

2.闭包底层原理

2.1了解闭包底层原理+scope chain

function a(){
        var aa=123
        function b(){
            var bb=234
            console.log(aa)
        }
        return b
    }
    var test = a()
    test()
//我们知道 这个test()会在控制台输出 123,为什么b被保存到外部之后,还能够拿到aa的值呢
//首先在function a执行之前 会创建一个作用域链[[scope]],[[scope]]里面包含了[scope chain] ,scope chain就是AO+GO的集合

首先在a()执行之前会产生如图所示的作用域链
在这里插入图片描述

在a函数执行之前,a预编译创建的AO一定是放在 [scope chain] 的首端,AO里面就是存放着的a的参数和变量声明

b() 定义的时候,看到的世界其实是和a函数一样,其实,b函数的出生 就是站在a函数的肩膀上的

在这里插入图片描述

a执行才让b定义,所以a和b所看到的世界都是一样的,scope chain可以看做如下形式;

上面的示例中,b被return到外部 ;当a执行完毕,销毁scope chain 的时候 ;b执行,既然a和b所看到的世界都是一样的,那当a的scope chain 销毁的的时候 ,执行b,b看到的世界和a一样,可以知道 即使a被销毁了,b依旧能够访问到aa变量 ; 那么这就是闭包形成的底层原理!!!!
在这里插入图片描述

2.2闭包经典应用+节流防抖案例

##防抖案例
function debounce(fun,delay){
        let timer
        return function(args){
            clearInterval(timer)
            timer = setTimeout(function(){
                fun(args)
            },delay)
        }
    }
// debounce返回了一个函数保存在外部 
    function inputFun(a){
        console.log(a)
    }
    const debounceInput = debounce(inputFun,1000)
    let a=111
    debounceInput(a)
##节流
function throttle(func,wait){
        let timeOut
        return function(){
            if(!timeOut){
                timeOut = setTimeout(
                    function(){
                        timeOut = null
                        func()
                    },
                    wait
                )
            }
        }
    }
//func为要执行的函数,wait 是等待时长
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值