JavaScript学习--js预编译 作用域 作用域链 闭包

文章详细介绍了JavaScript的执行过程,包括语法分析、预编译和执行阶段,强调了函数声明和变量提升的概念。接着讨论了作用域、作用域链以及执行期上下文,指出它们如何影响变量查找。文章重点讲解了闭包,说明了闭包的生成机制,即内部函数保留对外部作用域的引用,导致作用域链不释放,可用于实现变量缓存、封装和模块化。最后通过示例展示了闭包的实际应用。
摘要由CSDN通过智能技术生成

前言

闭包可以说是在学习JavaScript中遇到的第一个难点,此贴是本人在学习闭包时留下的学习笔记。

js运行三部曲

  • 语法分析
  • 预编译
  • 解释执行

js代码编写完并执行时,通常都会有这样的三个步骤。
语法分析:通篇执行 检验代码是否出现非逻辑上的错误
预编译:在JavaScript中存在一种预编译的机制,因为这个预编译的机制,导致了js中变量提升的一些问题。

  • 函数声明整体提升
  • 变量声明提升(赋值语句不提升)

这两句话大概概括了预编译的过程 但不全面。

imply global 暗示全局变量

即任何变量,如果变量未经声明就赋值,此变量就为全局变量所有。
一切声明的全局变量,全是window对象的属性

var a = 10;

//	 window {
//		a : 10
//	}
//
// window.a = 10
  • window就是全局的域(global object)
  • 预编译发生在函数执行的前一刻

预编译

预编译四部曲:

  • 创建AO对象 (Activation Object 执行期上下文
  • 找形参和变量声明,将变量的形参名作为AO属性名,值为undefined
  • 将实参值和形参统一
  • 在函数里面找函数声明,值赋予函数体
第一步
AO {

}

//生成AO对象
第二步
AO {
形参 : undefined,
变量 : undefined,
}

//找形参和变量声明,将变量的形参名作为AO属性名,值为undefined
第三步
AO {
形参 : 实参,
变量 : undefined,
}


//将实参值和形参统一
第四步
AO {
形参 : 实参,
变量 : undefined,
函数名 : 函数体,
}

//在函数里面找函数声明,值赋予函数体

当这四步完成后程序就会一行一行解释执行

在全局中的预编译

  • 生成GO对象(Global Object 全局执行上下文)

GO === window

GO完全等价于window对象

作用域 作用域链

  • 作用域 [[scope]] :每个JavaScript函数都是一个对象,对象中有些属性我们可以访问,但有些不可以,这些属性仅供JavaScript引擎存取 [[scope]] 就是其中一个,[[scope]] 指的就是作用域,其中存储了运行期上下文(AO/GO)的集合
  • 作用域链 : [[scope]] 中所存储的执行期上下文对象的集合,这个集合呈链式链接,我们把这种链式链接叫做作用域链。
  • 运行期上下文:当函数执行时,会创建一个称为执行期上下文的内部对象
    一个执行期上下文定义了一个函数执行时的环境,函数每次执行时对应的执行期上下文都是独一无二的,所以多次调用一个函数会导致创建了多个执行期上下文,当函数执行完毕,它所产生的执行期上下文会被销毁。
  • 查找变量:从作用域链顶端开始查找(栈的工作方式)
function a(){

	function b(){
		var b = 234;
	}
	
}

var glob = 100;
a ()

当函数a被定义时
会产生一个全局执行期上下文GO 此时的作用域链为

a.[[scope]] -- > 0 : GO

当函数a执行时
会生成一个a函数的执行期上下文 放在作用域最顶端

a.[[scope]] -- > 0 : AO
						1 : GO

当函数b被定义时
会拿到a执行时的作用域链作为自己的作用域链

b.[[scope]] -- > 0 : AO
						1 : GO

当函数b执行时
会生成一个b函数的执行期上下文 放在作用域最顶端

b.[[scope]] -- > 0 : AO  //b函数的
						1 : AO  //a函数的
						2 : GO

在这里插入图片描述

闭包

有了预编译 作用域 作用域链 的基础, 才能够理解闭包的机制。

闭包:

当内部函数被保存到外部时,将会生成闭包,闭包会导致原有作用域链不释放,造成内存泄漏。


闭包的作用:
  • 实现共有变量
  • 可以做缓存
  • 可以实现封装 属性私有化
  • 模块化开发

例子:


        function a (){
        
            function b (){
                var bbb = 234;
                document.write(aaa);
            }

            var aaa = 123;
            return b;

        }
        
        var demo = a();
        demo();  //输出123

正常来说demo是a函数执行后返回的b函数,demo在a函数的外部,应该是访问不到a函数内部声明的bbb变量才对,但是最终输出却是123,这是因为这段程序发生了闭包。原因是 b函数被定义时它的作用域链继承了a函数执行的作用域链,这个作用域链里的AO对象含有bbb的变量,所以当b函数执行时会在它的作用域链中查找变量bbb 当第一层找不到时会接着在下一层寻找,b函数执行完之后会销毁第一层的AO 而变量bbb在第二层的AO中,所以b函数返回到外部之后执行依然能在它的作用域链之中访问到变量bbb的值,这就是我们说的闭包。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冲鸭嘟嘟可

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值