六、作用域,作用域链,预编译,闭包基础

news2024/11/23 23:04:36

六、作用域,作用域链,预编译,闭包基础

使用AO,GO说明作用域和作用域链

AO与函数有关,函数能创造出独立的空间,但是这句话不太对,接下来就是解释:

对象

每个对象都有属性和方法:

var obj = {
	name: 'white',
    address: 'xxx',
    teach: function(){}
}

而函数也是一个对象,因为它也有自己的属性,例如.name能访问函数名称,.length能获取形参长度。

函数也是一种对象类型,一种引用值类型,一种引用值

但是对象有一些属性我们无法访问的:JS引擎内部固有的隐式属性(私有属性)。

例如:[[scope]]

[[scope]] (作用域)

它是什么:

  1. 函数创建时,生成的一个JS内部的隐式属性[[scope]],名为作用域,其内部对应存储着scope chain(作用域链)。
  2. 它是存储作用域链的容器,作用域链中存着AO/GO:
    • AO:函数执行期上下文
    • GO:全局的执行期上下文
    • 函数执行完成以后,AO是要被销毁的;每一次新执行函数前一刻(预编译),都会生成新的AO,即AO是一个即时容器。
    • 作用域链让AO,GO按序形成一个链式关系,连接起来。
    • 查找变量从作用域链顶端,依次往下找。

  1. 函数是什么时候被定义(创建):预编译的过程中。
    • 解释:全局函数在被全局预编译的时候定义,此时生成了[[scope]],scope chain中存储GO。
    • 当全局函数被执行的前一刻(在自己函数预编译的过程中),scope chain 中存储了函数的AO,全局的GO。
    • 同理,在全局函数预编译的过程中,内部的函数被定义,生成了自己的[[scope]],scope chain 中存储了外部函数的AO,全局的GO;当内部函数被执行的前一刻(预编译的过程中),在scope chain中存储了自己函数的AO,外部函数的AO,全局的GO。
  2. 每个函数在被定义时,它的作用域链上一定有GO!
  3. 预编译过程分为两种:
    • 全局预编译过程:GO
    • 函数预编译过程:AO

总结:只要函数被定义时就会生成自己的[[scope]],scope chain,作用域链上存在它所处环境的作用域;当函数被执行的前一刻(预编译过程),作用域链上就会存储自己的作用域AO + 之前它所处的作用域。


例如:

function a(){
	function b(){
        var b = 2;
    }
    var a = 1;
    b();
}
var c = 3;
a();

在全局预编译过程中,a被定义,生成[[scope]]:
在这里插入图片描述

这里a函数被执行的前一刻 -> a函数预编译的过程:
在这里插入图片描述

外层函数执行时,内层函数被定义:a函数执行时(函数预编译),b函数被定义:

在这里插入图片描述

这里有点小问题:b函数在被定义时,就已经生成了[[scope]],但是b函数被定义时是在a函数的环境下,所以b函数这时的作用域链就是a函数被执行期的作用域链。

在b函数被执行前一刻(函数b预编译时),存储函数b的作用域链,顶端第0位存储b的AO,a函数的AO和全局的GO依次往下排列。
在这里插入图片描述

b函数被执行结束后,b函数AO被销毁,b函数回归被定义时的状态,作用域链中有a函数的AO,全局的GO。

在这里插入图片描述

a函数被执行结束后,a函数AO被销毁,b函数的[[scope]]被销毁,a函数回归被定义时的状态,作用域链中有全局的GO。

在这里插入图片描述
在这里插入图片描述

外部函数被执行前一刻(预编译),内部函数被定义,例如:

function a(){
    function b(){
  
    }
    b();
}
a();

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

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

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

b执行:b.[[scope]] ->
0:b->AO
1:a->AO
2:GO

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

a结束:a.[[scope]] -> 0:GO
b.[[scope]] X 函数结束;函数结束作用域链回到函数被定义的状态,内部函数作用域[[scope]]结束。

闭包基础

当内部函数被返回到外部并保存时,一定会产生闭包,闭包会使原来的作用域链不释放。
闭包过于深入会导致内存泄漏,或加载过慢。

写闭包,其实是写函数产生的一种现象:作用域链不释放。

产生闭包时:函数内部中初始化的同名变量不属于暗示全局变量,而是变量的重新赋值。

闭包简单解释:

function test1(){
    function test2(){
        /*内部函数被返回到函数外部并保存时,一定会产生闭包
        * 闭包会使原来的作用域链不释放
        * 函数内部中初始化的同名变量不属于暗示全局变量
        */
        //a = 5; 
        var b = 2; 
        console.log(a);
    }
    var a = 1;
    return test2;
}
var c = 3;
var test3 = test1();
test3();

GO中test3是由test1执行时返回的test2函数赋值。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yKHUjbMX-1670923569043)(https://note.youdao.com/yws/res/11949/WEBRESOURCEb955fe45c2b43ec12d51ab2c37d580ca)]

test1被执行的前一刻(函数预编译)test2被声明,此时test2的[[scope]]生成,scope chain生成。此时test2还未被执行,scope chain内部存储着外层函数的执行上下文,即test1的AO,全局的GO。
在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述

做题:

function test(){
    var n = 100;
    function add(){
        n++;
        console.log(n);
    }
    function reduce(){
        n--;
        console.log(n);
    }
    // 把两个函数返回出函数外部
    return [add, reduce]
}
var arr = test();
arr[0]();
arr[1]();

执行结果为:101,100

解释:

GO ={

​ arr: undefined-> Array[add,reduce]

​ test: fucntion()

}

test的AO= {

​ n:undefined ->100,

​ add: function,

​ reduce: function

}

test被执行时,test的scope chain 上有自己的AO,外部的GO。

test被执行时,两个内部函数add,reduce被定义了,未被执行,它们的scope chain上与test的相同,为test的AO,和GO。

test执行完毕,test与自己的AO连接消失,但test的AO被未被销毁,因为add和reduce的scope chain中依然连接着test的AO。

当arr[0]()被执行,即函数add被执行时,它的scope chain上从顶部向下依次为自己的AO,test的AO,和GO。

add在自己的AO中寻找变量n没找到,再去test的AO中寻找变量n找到了,拿来使用。

arr[0],arr[1]执行结束,他们的AO也被销毁,但函数test的AO并没有销毁,还被add和reduce的scope chain 连着。 -->这就导致内存泄漏了

再次使用arr[0]时,add的AO又会被再次生成。而test的AO一直未被销毁…

两种形式的闭包

再说一次闭包的定义:闭包是一种现象。

内部函数被返回到函数外部并保存,一定会产生闭包;而闭包会导致作用域链不被释放。

我自己理解:再加一句:内部的函数共享函数中的变量。

  • 对象的形式写闭包:

    function sunSched(){
        var sunSched = '';
        var operation = {
            setSched: function(thing){
                sunSched = thing;
            },
            showSched: function(){
                console.log("MY schedule on sunday is "
                            + sunSched);
            }
        }
        return operation;
    }
    var sunSched = sunSched();
    sunSched.setSched('paly game'); //这里的 sunSched 相当于函数中的 operation
    sunSched.showSched(); //'MY schedule on sunday is paly game'
    
  • 内部函数的形式写闭包

    function sunSched(){
        var sunSched = '';
        function setSched(thing){
            sunSched = thing;
        }
        function showSched(){
            console.log("MY schedule on sunday is "
                        + sunSched);
        }
        return [setSched, showSched]
    }
    var sunSched = sunSched();
    sunSched[0]('listen to music'); //这里的 sunSched[0] 相当于内部函 setSched
    sunSched[1]()
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/87153.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MobileNetV2原理说明及实践落地

本文参考: 轻量级网络——MobileNetV2_Clichong的博客-CSDN博客_mobilenetv2 1、MobileNetV2介绍 MobileNetV1主要是提出了可分离卷积的概念,大大减少了模型的参数个数,从而缩小了计算量。但是在CenterNet算法中作为BackBone效果并不佳&…

【MATLAB教程案例59】使用matlab实现基于LSTM网络的数据分类预测功能与仿真分析

欢迎订阅《FPGA学习入门100例教程》、《MATLAB学习入门100例教程》 目录 1.软件版本 2.LSTM网络理论概述

荧光点击试剂ICG-N3, ICG-azide,根据具体的需求进行定制, 避免频繁的溶解和冻干,取用时注意干燥

【英文名称】 ICG-azide,ICG-N3 【结 构 式】 【CAS】N/A 【分子式】C48H56N6O4S 【分子量】813.07 【基团】叠氮基基团 【纯度】95% 【规格】1mg,5mg,10mg 【是否接受定制】根据具体的需求进行定制 【外观】 绿色固体(具…

最小二乘问题,,而不是方法

最小二乘是一大类问题,而不是一个简单的方法 适用于:线性(非线性)方程组问题,如果观测带有噪声,我们需要建立最小二乘模型。如果噪声符合高斯分布,即最小二乘问题的解对应于原问题的最大似然解…

千万不要做“舔狗式”营销

不知道在网上做生意的你们是否经常陷入我下面说的这几种尴尬境地:每天都在推广引流,每天都在发广告,但转化率却低得可怜。粉丝质量普遍不行,不精准,好不容易来几个粉,不是白嫖党就是垃圾粉。两句话不对头&a…

C++实现红外Fir谱图文件转BMP图片文件

1、红外图谱文件 红外图谱文件由文件头和温度数据两部分组成,其中文件头 64 个字节,其余字节为温度数据。 如下如: 每个像素用两个字节表示温度(16 位有符号短整数),低字节在前,高字节在后,温度数据单位为 0.1℃,温度数据共 w h 2 字节。文件头定义 如下: 从文件…

Android Studio 开发环境搭建 配置

前言 上一次做 Android 开发还是在大三的 Android 课设项目上「 IPOD - 本地音乐播放器」 开发环境:JDK开发语言:Java开发工具:Android Studio 现在由于工作需要 「面向业务编程」,需要重拾 Android 开发,由于电脑已换…

mysql基础学习(2)-regexp正则表达式的学习

表示例 user 学习: ^匹配以^后面字符开头的所有数据,示例:^str,则匹配str开头的所以数据$匹配以$前面面字符结尾的所有数据,示例:str$,则匹配str结尾的所以数据. 匹配任何单个字符&…

嵌入式分享合集121

一、Matter协议 不是广告啊就是看见了就搬来了 也没用过啊~ 早在2019年底,中国就已成为全球最大的智能家居消费国,占全球智能家居消费市场份额的50%-60%;2021年,中国智能家居市场规模约为5880亿元,同比增长12.7%&…

使用github的pages配合action自动部署vue项目

如果你需要某个 action,不必自己写复杂的脚本,直接引用他人写好的 action 即可,整个持续集成过程,就变成了一个 actions 的组合。这就是 GitHub Actions 最特别的地方。 GitHub 做了一个官方市场,可以搜索到他人提交的…

安全研究 # 课题:二进制成分分析(Binary SCA)

本文参考多篇文章写作而成,出处在文末注明(本文在课题开展过程中长期保持更新)。 二进制成分分析 SCA(Software Composition Analysis)软件成分分析,通俗的理解就是通过分析软件包含的一些信息和特征来实现对该软件的识别、管理、…

奶茶果茶饮品店数字化转型| 奶茶店小程序 | 餐饮外卖系统

奶茶/果茶/饮品店里总是容易聚集大量年轻消费者,尤其品牌开新店或搞促销,往往会排很长的队伍,而茶饮店也会根据季节推出相应的新品或冷热饮品,以保证消费者在任何时候都能喝到应季的饮品。 年轻人是奶茶饮品店的主要消费者&#x…

第九章 webpack5高级优化——提升开发体验

之前我们所配置的webpack打包出来的文件在浏览器里面进行调试,是非常困难的。 查看打包出来的js文件: /** ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development").* This devtool is neither m…

SpringCloud全系列知识(6)——RabbitMQ(消息队列)

消息队列(MQ)—RabbitMQ 一 初识MQ 1.同步通信与异步通信 1.同步通信的问题 同步调用的优点在于时效性高,可以立即得到结果 微服务之间基于Feign的调用属于同步方式,存在一些问题 耦合性:业务较多时,扩展…

分布式数据库与集中式数据库的差异

第一章:分布式数据库与集中式数据库的差异 1. 数据库是核心的IT基础设施 • 互联网业务增长,带动核心系统升级 • 核心系统引入数据库分布式与云化改造,支撑横向平滑扩展 • 5G规模推广,带动IT系统升级 • 5G具备大带宽和超低延时…

基于java+springboot+mybatis+vue+mysql的企业客户信息反馈平台

项目介绍 企业客户信息反馈平台能够通过互联网得到广泛的、全面的宣传,让尽可能多的用户了解和熟知企业客户信息反馈平台的便捷高效,不仅为客户提供了服务,而且也推广了自己,让更多的客户了解自己。对于企业客户信息反馈而言&…

小蓝本 第一本 《因式分解技巧》 第六章 二元二次式的分解 笔记(第六天)

小蓝本 第一本 《因式分解技巧》 第六章 二元二次式的分解 笔记(第六天)前言二元二次式的分解研究对象类型普通二元二次式基本形式分解方法总体总结——长十字相乘注意三元齐次式基本形式分解方法总体总结——长十字相乘注意提示习题6题目题解前言 今天…

【数据库】MySQL和Navicate安装和使用

MySQL和Navicate安装使用MySQLNavicate使用数据库MySQL 1、下载 可以考虑在官网下载或者在其它途径获取MySQL https://www.mysql.com/ download-》选择免费版或者其他版本-》选择系统和版本号-》根据需要下载 MySQL的Windows安装版只提供 32 位了 2、运行安装文件 可以选择…

基于51单片机的交通信号灯系统设计

功能: 十字路口交通灯控制程序: 正常时,EW方向计时60s,SN方向计时40s 若按时间加按键(Add_Button)按钮,EW、SN方向各加5s,不可大于99s,79s 若按时间减按键(R…

全网最新的Fiddler(3):fiddler界面工具栏介绍

fiddler界面工具栏介绍 (1)WinConfig:windows 使用了一种叫做“AppContainer”的隔离技术,使得一些流量无法正常捕获,在 fiddler中点击 WinConfig 按钮可以解除这个诅咒,这个与菜单栏 Tools→Win8 Loopback…