当前位置: 首页 > wzjs >正文

秦皇岛网站制作定制网络运营者应当制定网络安全事件

秦皇岛网站制作定制,网络运营者应当制定网络安全事件,子凡wordpress,如何修改wordpress权限设置你将知道: 什么是闭包什么是词汇环境Chrome 中的 [[Scopes]] 属性保留函数的本地环境闭包的实际应用 什么是闭包? closures 函数及其词法环境统称为闭包。 什么是词汇环境? 考虑下面的代码: var a static;function f1() {co…

你将知道:

  • 什么是闭包
  • 什么是词汇环境
  • Chrome 中的 [[Scopes]] 属性
  • 保留函数的本地环境
  • 闭包的实际应用

什么是闭包? closures

函数及其词法环境统称为闭包。

什么是词汇环境?

考虑下面的代码:

var a = 'static';function f1() {console.log(a);
}function f2() {var a = 'dynamic';f1();
}f2();

是时候揭晓答案了:它是 ‘静态的’

在这个作用域系统中,为了解析函数内部的名称,首先在函数的局部环境中搜索,然后在其词法环境中搜索。

函数 f 的词法环境只是指源代码中包围该函数定义的环境。

换句话说,给定函数的词法环境基于程序的源代码——函数的定义位置。这就是为什么我们称之为 “词法” 环境,即基于源代码的环境。

那么,根据源代码,它究竟是如何运作的呢?这到底是什么意思呢?

嗯,JavaScript 编译器在编译程序时会读取程序的源代码,并根据其定义确定给定函数可访问的环境。

例如,如果函数 f 在全局范围内定义,则其词法环境(编译函数时确定)就是全局环境。

包围一个函数的所有环境集合统称为该函数的词法环境。

Note: 一个函数的词法环境可以包含多个环境。

词法环境一旦确定,便会在整个程序运行过程中保持不变。这就是为什么 JavaScript 被称为静态作用域语言的原因——程序中可访问给定名称(变量和函数)的位置是静态的(即不会改变),并且由源代码控制。

让我们重新考虑一下上面显示的代码片段:

var a = 'static';function f1() {console.log(a);
}function f2() {var a = 'dynamic';f1();
}f2();

这里,函数 f1 定义在全局作用域中,同样,它的词法环境也是整个全局环境。函数 f2() 也是如此。

现在,当在第 12 行调用 f2() 时,首先创建一个局部变量 a 并将其初始化为 'dynamic' ,然后调用 f1() 。在 f1() 内部,会遇到语句 console.log(a) 。此时,必须解析名称 a

  1. 首先在 f1 的局部作用域中搜索名称 a 。显然,由于该局部环境为空,因此未找到该名称。因此,搜索将移至 f1 的词法环境。
  2. 在词法环境中的搜索也是有序的。也就是说,首先搜索函数的第一个封闭环境,然后是更外层的封闭作用域,依此类推,直到最终到达全局环境,此时不再有进一步的封闭环境。
  3. f1 的封闭词法环境就是全局作用域,因此这里搜索的是名称 a 。由于找到了匹配项,并且绑定到了值 20console.log(a) 中的名称 a 被解析为值 20

词法意味着与源代码相关,或者仅仅基于源代码。函数的词法环境仅仅指包含函数定义的环境。之所以称为词法,是因为它基于源代码,并且在整个程序执行过程中保持不变。当函数 f 中引用名称 x 时,首先在 f 的局部环境中搜索,然后在其词法环境中搜索。

Chrome 中的 [[Scopes]] 属性

根据 ECMAScript 规范,每个函数都包含一个内部属性 [[Environment]] ,它仅包含该函数的词法环境。最棒的是,这个属性是 Chrome 控制台公开的属性之一。然而,在撰写本文时,它的命名略有不同——它被称为 [[Scopes]] 。这意味着我们实际上可以通过检查其 [[Scopes]] 属性来检查 Chrome 中任何给定函数 f 的词法环境。考虑上面定义的相同代码。注意,我们暂时不调用 f2() ,同样,最后一条语句也被注释掉了。我们稍后完成一些基本检查后再调用它,让我们在代码中添加 console.dir() 语句来检查 f1 ::

var a = 'static';function f1() {console.log(a);
}function f2() {var a = 'dynamic';f1();
}// f2();
console.dir(f1);

首先,展开函数 f1 以查看其属性和内部属性。在这里,展开 [[Scopes]] 属性以查看 f1 的词法环境。

在这种情况下,它是一个仅包含一个指向全局环境的对象的数组。最后,我们展开 [[Scopes]] 的这个元素。接下来是一长串属性,其中我们只能显示前五个。

看到这里的 a 了吗? 这是全局变量 a 。在上面的代码中,当 f2 内部调用 f1 时,它被用来解析 f1 中的名称 a

我们来回顾一下在上面的函数 f1 中遇到 a 时会发生什么。

  1. f1 的局部环境中搜索名称 a 。这里没有找到任何内容,同样搜索转移到 f1 的词法环境。
  2. [[Scopes]] 表示的词法环境中,名称 a 在包含 f1 的第一个环境中被搜索。在本例中,该环境就是全局环境。
  3. 同样,在全局环境中搜索 a 。找到一个匹配项,该匹配项绑定到值 'static' ,因此 f1 中的 a 被解析为 'static'
     
同一作用域内的函数具有相同的词法环境 。需要记住的一点是,同一作用域内的所有函数都指向完全相同的词法环境。这是一个无关紧要的细节,无论如何都应该满足。

这意味着在上面的代码中, f2[[Scopes]] 将与 f1[[Scopes]] 相同,因为它们都位于全局作用域内。它们将引用存储在内存中的同一个内部环境对象。

好了,接下来,我们对上面的代码做一个简单的修改,然后重新思考一下。我们将把所有代码封装在一个 IIFE 函数中:

(function() {var a = 'static';function f1() {console.log(a);}function f2() {var a = 'dynamic';f1();}// f2();console.dir(f1);
})();

f1 (和 f2 )的 [[Scopes]] 属性包含两个条目。

第一个是包含 f1 定义的第一个环境,即 IIFE 的局部环境;

第二个是包含 f1 第二个环境,即全局环境。

为什么没有 f2

你可能会想: 为什么上面 [[Scopes]] 的第一个条目中没有 f2 呢? f2 是因为 V8 引擎(Chrome 的 JavaScript 编译器)做了优化。在这种情况下,引擎认为 IIFE 中的任何函数( f1f2 )都不需要 f2 ,同样,它也没有存储在这些函数的词法环境中。

和以前一样,让我们看看当在函数 f1 中遇到名称 a 时,即调用该函数时会发生什么:

  1. f1 的局部环境中搜索名称 a 。这里没有找到任何内容,同样搜索转移到 f1 的词法环境。
  2. 在通过 [[Scopes]] 表示的词法环境中,在包含 f1 第一个环境(即 IIFE 的局部环境)中搜索名称 a
  3. 在这里,确实发现了值为 'static'a ,同样, f1 中的 a 也被解析为 'static'

更多示例

让我们考虑一个非常简单的例子来扩展我们之前的代码片段:

var a = 'easy';(function() {var b = 'easy';function f1() {console.log(a, b);}function f2() {var a = 'difficult';var b = 'difficult';f1();}f2();
})();

好吧,让我们看看上面的代码是如何执行的。

  1. 创建一个全局变量 a 并赋予其值 'easy' ,然后创建并调用一个 IIFE。
  2. 为这个 IIFE 创建了一个局部环境。这里创建了一个局部变量 b ,并将其初始化为值 'easy' 。接下来,创建了两个函数 f1f2
  3. 将函数的词法环境保存在函数的 [[Environment]] 内部属性中
  4. 完成所有这些后,执行转到第 16 行,在此调用 f2()
  5. f2 创建了一个局部环境。这里定义了两个局部变量 ab ,它们的值均为 'difficult'
  6. 接下来,调用 f1()
  7. f1 创建了一个局部环境。执行移至第 7 行的语句 console.log(a, b) 现在,在处理此语句之前,必须先解析名称 ab
  8. 让我们首先解决 a :
    1. f1 的局部环境中搜索 a 。未找到匹配项,因此搜索移至词汇环境.
    2. 在词法环境中,在 f1 的第一个封闭环境(即 IIFE 的局部环境)中搜索 b
    3. 即使在这里也找不到任何东西,同样搜索移动到第二个封闭环境(在 f1 的词汇环境内),即全局环境。
    4. 由于在这里找到了匹配 a = 'easy'console.log( a , b) 中的名称 a 被解析为值 'easy'
  1. 现在让我们解决 b
    1. f1 的局部环境中搜索 b 。未找到匹配项,因此搜索转移到词汇环境。
    2. 在词法环境中,在 f1 的第一个封闭环境(即 IIFE 的局部环境)中搜索 b
    3. 由于在这里找到匹配项 b = 'easy'console.log(a, b ) 中的名称 b 被解析为值 'easy'
  1. 此时名称 ab 都已解析,因此语句 console.log(a, b) 执行,完成 f1 的执行、 f2 的执行,最终完成整个程序的执行。

保留函数的本地环境

“JavaScript 为什么能够在函数退出后保留其本地环境”

看一下下面的代码:

function f1() {var a = 'difficult';return function() {console.log(a);};
}var a = 'easy';
var f2 = f1();f2();

当执行上述代码时,会发生以下情况:

  1. 创建一个函数 f1 ,然后将全局变量 a 赋值为 'easy'
  2. 接下来,调用函数 f1()
  3. 为函数 f1 创建一个局部环境。在这里,定义一个变量 a ,其值为 'difficult' 。然后创建一个匿名函数,其词法环境包含这个( f1 的)局部环境,最后返回这个函数。
  4. 此时,由于函数 f1 返回了一个值,表示该函数已执行完毕,JavaScript 引擎必须删除其本地环境。在删除之前,会进行快速搜索,查找是否存在对该环境的引用。由于在函数 f1 的本地作用域之外,确实存在一个引用——在返回函数的 [[Environment]] 属性中——因此该环境会保留在内存中 。但是,其他必要的步骤仍会照常执行,例如清除 f1 的调用堆栈框架。
  5. 调用 f1() 完成,其返回值(一个匿名函数)被赋值给全局变量 f2 。然后调用 f2()
  6. f2 创建了一个局部环境。执行到第 5 行,此时 console.log(a) 中的名称 a 应该被解析。
  7. 解决方法如下:
    1. f1 的局部环境中搜索名称 a 。这里没有找到任何内容,同样,搜索转移到词汇环境。
    2. 在词法环境中,检查 f1 的第一个封闭环境(即函数 f2 的局部环境)是否存在 a
    3. 这里由于找到了匹配 a = 'difficult' ,所以 console.log(a) 中的名称 a 被解析为值 'difficult'

这里最有趣的一点是,即使 f1 退出(通过 return 关键字), f1 的局部环境也不会被删除。这是因为返回的匿名函数中存在对其局部环境的引用。

引擎会检查函数退出时,函数外部是否至少存在一个对该函数局部环境的引用 。如果存在,则该局部环境不会被垃圾回收 。


文章转载自:

http://bzV1Q3ui.jbztm.cn
http://ez9kAC7b.jbztm.cn
http://P3ChC1LT.jbztm.cn
http://glwmu1rZ.jbztm.cn
http://kRngIknn.jbztm.cn
http://fErZOgNY.jbztm.cn
http://bCrzNxY5.jbztm.cn
http://jN5MyHNE.jbztm.cn
http://n1kg7fps.jbztm.cn
http://xcjhy0ST.jbztm.cn
http://PFbBFTPD.jbztm.cn
http://tyrc5WEw.jbztm.cn
http://v80cqdZd.jbztm.cn
http://HyPoLhh3.jbztm.cn
http://8rQrQEPQ.jbztm.cn
http://n9M6ajmO.jbztm.cn
http://MHmmA6bC.jbztm.cn
http://MKMmsXbZ.jbztm.cn
http://W8NQ0zSr.jbztm.cn
http://b3zzYOjz.jbztm.cn
http://tblT3PrW.jbztm.cn
http://F70tYZZH.jbztm.cn
http://tCq1DmZM.jbztm.cn
http://IF3sSq6U.jbztm.cn
http://dpy6TNXc.jbztm.cn
http://i5eMaTGC.jbztm.cn
http://YZafL3V4.jbztm.cn
http://gf6uk1IJ.jbztm.cn
http://HahDFbMp.jbztm.cn
http://fTDM7wgg.jbztm.cn
http://www.dtcms.com/wzjs/636462.html

相关文章:

  • 网站内页做友链网站设计制作合同
  • 甘肃交通工程建设监理公司网站网页设计师考试报名
  • vs做网站mvc商业网站建设设计
  • 招标网官方网站网站播放图片多大合适
  • 网络营销网站建设ppt做外贸网站的好处
  • 学网站开发跟那个专业最相近知名的深圳小程序开发公司
  • 网站开发 软件垦利区建设局网站
  • 如何搭建网站服务器html5网站提示
  • 做网站得叫什么软件seo竞争对手分析
  • 山西网站设计门户网站功能模块
  • 优惠购网站怎么做的辽宁关键词优化排名外包
  • 健身网站开发可行性分析泉州网站关键词推广
  • 自己做h5制作开发搜索引擎关键词排名优化
  • 怎么在百度建立自己的网站yole市场调研公司
  • 做网站的软件电子360做网站和推广怎么样
  • 网站做下cdn8小8x人成免费观看网页
  • 统计 网站关键字 布局手机表格制作软件
  • 凯发网站兰州建网站
  • 宝安专业网站设计多少钱seo教程有什么
  • 注册网站给谁交钱友情链接交换统计表
  • 四川省住房与城乡建设厅网站官网网站开发 python 工具
  • 张家港建网站价格广州市天河区
  • 网站的收录率使用wordpress需要懂什么语言
  • 微网站建站平台怎么查找网站备案主体
  • 淘宝接单做网站商标制作logo在线制作
  • 国内网站开发中国万网注册网站
  • 广安市网站建设公司汕头免费网站制作
  • 网站布局设计网站搭建工具的种类
  • 做网站的背景图片要多大个人简历网页设计
  • 网站哪里买外链html5网站建设源码