前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >JavaScript之执行环境与作用域的区别与联系​

JavaScript之执行环境与作用域的区别与联系​

作者头像
达达前端
发布于 2020-02-24 04:37:11
发布于 2020-02-24 04:37:11
8280
举报
文章被收录于专栏:达达前端达达前端

补充内容

什么是块级作用域。js没有块级作用域是啥意思。

如何一对花括号中的语句代码集都属于一个块,在这之中定义的所有变量在代码块外是不可见的,称为块级作用域。作用域控制着变量和参数的可见性与生命周期。

块级作用域概念,任何一对花括号({和})中的语句集都属于一个块,在这之中定义的所有变量在代码块外都是不可见的,我们称之为块级作用域。

在js中作用域区分为全局作用域,函数作用域。没有块级作用域的概念,ECMAScript 6(简称ES6)中新增了块级作用域。块作用域由 { } 包括,if语句和for语句里面的{ }也属于块作用域。

都知道在js中是没有块级作用域的,在ES6中添加了块级作用域,那么块级作用域有什么好处呢?

执行环境

定义变量或函数有权访问的其他数据,决定了它们各自的行为。

执行环境,也称“环境”,Execution context,或执行上下文对象,统一为用执行上下文表示,它定义了变量或函数有权访问的其他数据,决定了他们各自的行为。js代码执行时所在的环境。

每个执行环境都有一个与之关联的变量对象,环境中定义的所以有变量和函数都保存在这个对象中。

执行环境的特点

在JavaScript中分为三种执行环境:

第一种为:全局执行环境,这是最外围的执行环境,一旦代码被载入,引擎最先进入的就是这个环境。在浏览器中,全局环境就是window对象,所以所有全局属性和函数都是作为window对象的属性和方法创建。全局执行环境直到应用程序退出时才会被销毁。

每个函数都有自己的执行环境,当执行流进入一个函数时,函数的环境就会被推入到一个环境栈中,执行完后,栈将其弹出,把控制权交给之前的执行环境。

第二种为:函数执行环境,当执行流执行一个函数时,JavaScript会创建一个新的函数执行环境,函数执行环境中的代码执行完后,该环境被销毁,保存在其中的所有变量和函数定义也随之被销毁。

环境是函数,则将其活动对象作为变量对象。

活动对象在最开始只有一个变量,就是 arguments 对象,这个对象在全局环境中是不存在,只有在函数中。

第三种为:Eval执行环境。

用eval执行的语句应该和普通语句没有区别,其作用域就是当前的作用域。

默认情况下:

1. eval内代码可以读取和使用所在作用域的变量

2. eval中声明的变量也可以在当前作用域中存在

例子:

(function(){window.eval("var x=1;");})();alert(x);// 1

x声明在window中

(function(){eval("var x = 1;"); alert(x);// 1})();alert(x);// x is not defined

y声明在闭包中

(function(){"user strict";eval("var y = 1; alert(y);");// 1alert(y);// y is not defined})();alert(y);// y is not defined

严格模式下的eval的变量仅存在于eval内部,不外泄。

作用域链的前端,一直都是当前执行的代码所在环境的变量对象。

执行顺序

varfoo =function(){console.log('foo1');}foo();// foo1varfoo =function(){console.log('foo2');}foo();// foo2

functionfoo(){console.log('foo1');}foo();// foo2functionfoo(){console.log('foo2');}foo();// foo2

JavaScript引擎不是一行一行地分析和执行程序的,而是一段一段地分析执行的。第一个例子中有变量提升,第二个例子中有函数提升。

JavaScript中的可执行代码的类型有三种,全局代码,函数代码,eval代码。

执行上下文

在JavaScript引擎中创建了执行上下文栈,来管理执行上下文。

functionfun3(){console.log('fun3')}functionfun2(){ fun3();}functionfun1(){ fun2();}fun1();

当执行一个函数的时候,就会创建一个执行上下文,然后把它压入执行上下文栈,当函数执行完毕后,就会将函数的执行上下文从栈中弹出。

作用域

作用域是指在程序中定义变量的区域,作用域规定了如何查找变量,对当前执行代码对变量的访问权限。

关于词法作用域和动态作用域

词法作用域就是静态作用域,而相对于词法作用域就是动态作用域。词法作用域是函数的作用域在函数定义的时候决定的,而动态作用域是在函数调用的时候决定的。

varvalue =1;functionfoo(){console.log(value);}functionbar(){varvalue =2; foo();}bar();

作用域链

作用域链,当代码在一个环境中执行时,会创建变量对象的一个作用域链,这个作用域链确保对执行环境有权访问的所有变量和函数的有序访问。

执行流每进入一个执行环境,都会创建一个作用域链。

作用域链由执行环境的变量对象组成,作用域链的前端都是当前执行环境的变量对象,下个变量对象来自外围环境,再下一个变量对象则来自下一个外围环境,一直延续到全局执行环境的变量对象。

所以全局执行环境的变量对象一直都是作用域链中的最后一个对象。

内部环境可以通过作用域链可以访问所有的外部环境,但是外部环境不能访问内部环境中的任何变量和函数。这些环境之间的连续是线性的,有次序的。

每个环境都是可以向上搜作用域链的,但是任何环境都不能通过向下搜索作用域而进入另一个执行环境。

当我们在某个环境中需要读取而引用一个标识符代表某种特定含义的时候,必须通过搜索来确定该标识符。搜索由近到远,由局部到全局,如果查询到了相应的标识符将停止搜索。

延长作用域链

执行环境类型分两种:一种全局和一种局部。

延长就是可以在作用域链的前端临时增加一个变量对象,该变量对象会在代码执行后被移除,让作用域链加长的方法。

第一种,try-catch语句的catch块。通过增加一个变量对象在作用域前端,在代码执行结束以后销毁。

第二种, with语句。会将指定的对象添加到作用域链上面来延长作用域链。

try{null.name }catch(e) {console.log(e.message); }

延长作用域链的特点:

第一,添加的变量对象是临时的,在语句执行完后将被移除。

第二,添加的变量对象不关联执行环境。

示例,如with语句接收一个参数location对象,那么其变量对象中就包含了location对象的所有属性和方法,这个变量对象被添加到了作用域链的前端。

没有块级作用域

因为没有块级作用域,而添加块级作用域,为什么会添加这个功能呢?就得了解ES5没有块级作用域时出现了哪些问题。

第一,在if或者for循环中声明的变量会泄漏成全局变量,第二,内层变量可能会覆盖外层变量。

了解js的同学知道ES5中是没有块级作用域的概念,只有全局作用域和函数作用域,之前js的是用var定义的变量。如果使用了js内部已经定义好的函数名,就会造成了全局污染。

如果使用了相同名称的变量,就会覆盖掉之前的,或函数内层的变量会覆盖掉外层的变量。从没有块级作用域到有块级作用域。

JavaScript没有块级作用域经常会导致理解上的困惑。为什么说js没有块级作用域

if(true) {vardada ='dada'; }console.log(dada);// dada没在if 块中也可以访问

为什么在if语句执行完毕后没有被销毁呢

在JavaScript中if语句中变量声明会将变量添加到当前的执行环境中。

for(vari =0;i<10; i++){ doSomething(i); }alert(i);//10

在JavaScript中,for语句创建的变量i即使在for循环结束后,也会依然存在于循环外部的执行环境中。

JavaScript没有块级作用域,变量的声明周期和执行环境有关。

使用var声明的变量会自动被添加到最近的环境中,也就是我们所谓的函数局部环境,在with语句中,最接近的环境是函数环境。如果初始化时变量没有使用var声明,该变量为自动被添加到全局环境。

补充内容

块级作用域的出现,es6语法中还有两个定义变量的方法为let和const。

let定义一个变量,允许被改变,只作用在被定义时的作用域下,const也是,但是唯一const为不允许被改变。

执行环境与作用域的区别与联系

作用域链是基于执行环境的变量对象,由所有执行环境的变量对象共同组成。

(function(){ a=5;console.log(window.a);//undefinedvara =1;//会发生变量声明提升console.log(a);//1})();(function(){vara;//a是局部变量a =5;//局部环境中有a,就不会找全局中的console.log(window.a);//undefineda =1;//这里会发生变量声明提升console.log(a);//1})();

Eval:执行字符串内的代码

内建(built-in)函数 eval 让我们能够执行字符串内的代码。

语法如下:letresult =eval(code);比如:letcode ='alert("Hello")';eval(code);// Hello

字符串内的代码在当前词法环境(lexical environment)下执行,因此能访问外部变量:

leta =1;functionf(){leta =2;eval('alert(a)');// 2}f();letx =5;eval("x = 10");alert(x);// 10, 变量的值改变了

总结

全局执行环境是最外围的一个执行环境。

根据所在的宿主环境不同,表示执行环境的对象也不一样。

在web浏览器中,全局执行环境被认为是window对象,所有的全局变量和函数都是作为window对象的属性和方法创建的。

某执行环境的所有代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数定义也随之销毁。

Eval的执行环境和函数调用的执行环境相同。

执行环境可以说分两种的,一种全局执行环境,一种是函数执行环境。全局执行环境是最外围的一个执行环境,每个函数都有自己的执行环境,函数执行环境的变量对象被称为活动对象,它在最开始只包含一个变量,即arguments对象。

标识符解析是沿着作用域链一级一级地搜索标识符的过程,从作用域链的前端开始,向后回溯,直到找到标识符为止,找不到,会导致错误发生。

每次进入到一个新的执行环境中,都会创建一个用于搜索变量和函数的作用域链。

变量的执行环境有助于确定应该何时释放内存。

补充内容

上下文和作用域,每个函数的调用都有与之相关的作用域和上下文,作用域是基于函数,而上下文时基于变量对象。

当调用一个函数,通过new操作符创建一个对象的实例,this指向新创建的实例。

作用域是和每次函数调用时变量的访问有关系,每次调用都是独立的,上下文总是关键字this的值,是调用当前可执行代码的对象的引用。

☆ END ☆

参考文档来源:《JavaScript 高级程序设计》

目前文章内容涉及前端知识点,囊括Vue、JavaScript、数据结构与算法、实战演练、Node全栈一线技术,紧跟业界发展步伐,将 Web前端领域、网络原理等通俗易懂的呈现给小伙伴。更多内容请到达达前端网站进行学习:www.dadaqianduan.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
从 JavaScript 作用域说开去
在电脑程序设计中,作用域(scope,或译作有效范围)是名字(name)与实体(entity)的绑定(binding)保持有效的那部分计算机程序。不同的编程语言可能有不同的作用域和名字解析。而同一语言内也可能存在多种作用域,随实体的类型变化而不同。作用域类别影响变量的绑定方式,根据语言使用静态作用域还是动态作用域变量的取值可能会有不同的结果。
一缕殇流化隐半边冰霜
2018/08/29
8730
从 JavaScript 作用域说开去
理解JavaScript作用域和作用域链
作用域是当前的执行上下文,值和表达式在其中“可见”或可被访问。如果一个变量或表达式不在当前的作用域中,那么它是不可用的。
用户10562852
2023/05/21
4190
理解JavaScript作用域和作用域链
JS进阶:作用域和作用域链
作用域是在运行时代码中的某些特定部分中变量,函数和对象的可访问性。换句话说,作用域决定了代码区块中变量和其他资源的可见性。可能这两句话并不好理解,我们先来看个例子:
4O4
2022/04/25
2.6K0
JS进阶:作用域和作用域链
关于js作用域问题详解
在一段js代码拿过来真正一句一句运行之前,浏览器已经做了一些“准备工作”,其中就包括对变量的声明,而不是赋值。变量赋值是在赋值语句执行的时候进行的。可用下图模拟:第一句报错,a未定义,很正常。第二句、第三句输出都是undefined,说明浏览器在执行console.log(a)时,已经知道了a是undefined,但却不知道a是10(第三句中)。
IT人一直在路上
2019/09/18
1.9K0
关于js作用域问题详解
深入理解作用域和闭包
JavaScript中的变量是松散类型的,没有规则定义它必须包含什么数据类型,它的值和数据类型在执行期间是可以改变的。
神奇的程序员
2022/04/10
5480
深入理解作用域和闭包
JavaScript变量作用域
执行环境是JavaScript中比较重要的概念。执行环境定义了变量或者函数有权访问的其他数据决定了他们各自的行为,每个执行环境都有一个与之关联的变量,环境中定义的所有变量和函数保存在这个对象中。 全局执行环境是最外围的一个执行环境。在web浏览器中,全局执行环境被认为是windows对象,因此所有全局变量和函数都是作为window对象的属性和方法创建的。某个执行环境所有代码执行完毕后,该环境被销毁,保存在其中的变量和函数也一同被销毁。全局执行环境,当应该程序退出或者浏览器关系的时候被销毁。 每个函数都有自己
水击三千
2018/02/27
8440
前端入门17-JavaScript进阶之作用域声明正文-作用域
作为一个前端小白,入门跟着这几个来源学习,感谢作者的分享,在其基础上,通过自己的理解,梳理出的知识点,或许有遗漏,或许有些理解是错误的,如有发现,欢迎指点下。
请叫我大苏
2018/12/24
5450
前端入门17-JavaScript进阶之作用域声明正文-作用域
从零开始讲解JavaScript中作用域链的概念及用途
之前我写过一篇关于JavaScript中的对象的一篇文章,里面也提到了作用域链的概念,相信大家对这个概念还是没有很深的理解,并且这个概念也是面试中经常问到的,因为这个概念实在太重要了,在我们平时写代码时,也可能会因为作用域链的问题,而出现莫名其妙的bug,导致我们花费大量的时间都查找不出原因。所以我就准备单独写一篇关于作用域链的文章,来帮大家更好地理解这个概念。
@零一
2021/01/29
2920
从零开始讲解JavaScript中作用域链的概念及用途
JavaScript——执行环境、变量对象、作用域链
这几天在看《javascript高级程序设计》,看到执行环境和作用域链的时候,就有些模糊了。书中还是讲的不够具体。通过上网查资料,特来总结,以备回顾和修正。
喝茶去
2019/04/16
7890
JS入门难点解析8-作用域,作用域链,执行上下文,执行上下文栈等分析
(注1:如果有问题欢迎留言探讨,一起学习!转载请注明出处,喜欢可以点个赞哦!) (注2:更多内容请查看我的目录。)
love丁酥酥
2018/08/27
6930
手把手教会你JavaScript引擎如何执行JavaScript代码
JavaScript 在运行过程中与其他语言有所不一样,如果不理解 JavaScript 的词法环境、执行上下文等内容,很容易会在开发过程中产生 Bug,比如this指向和预期不一致、某个变量不知道为什么被改了,等等。所以今天我们就来聊一聊 JavaScript 代码的运行过程。
前端皮皮
2022/08/17
4410
手把手教会你JavaScript引擎如何执行JavaScript代码
兄台: 作用域、执行上下文了解一下
变量的词法作用域(简称:作用域)是程序中可以访问变量的区域。通俗地理解,作用域就是变量与函数的可访问范围,即作用域控制着变量和函数的可见性和生命周期。
前端柒八九
2022/08/25
5210
兄台: 作用域、执行上下文了解一下
java作用域-javaScript预编译、作用域,作用域链详解
  ES5中只分为全局作用域和函数作用域java作用域,也就是说for,if,while等语句是不会创建作用域的。ES6(let,const)除外。
宜轩
2022/12/29
1.4K0
深入理解JavaScript作用域
在上一篇文章 深入理解JavaScript 执行上下文 中提到 只有理解了执行上下文,才能更好地理解 JavaScript 语言本身,比如变量提升,作用域,闭包等,本篇文章就来说一下 JavaScript 的作用域。
木子星兮
2020/07/27
7130
深入理解JavaScript作用域
作用域链和原型链的区别_原型链和作用域链
题外话:最近面试一直被问到作用域链的问题,所以还是要深入透彻的学习一下这两个概念。
全栈程序员站长
2022/11/16
4590
作用域链和原型链的区别_原型链和作用域链
作用域及作用域链的解释说明
javascript中作用域是指变量与函数可访问的范围。作用域分为两类,一种是全局作用域,一种是局部作用域。全局变量拥有全局作用域,在JavaScript代码中的任何地方都有定义。局部变量是在函数体内声明而且只作用在函数体内部以及该函数体的子函数的变量。下面我们对全局作用域和局部作用域来做一个深入的理解。
OECOM
2020/07/02
1.2K0
作用域及作用域链的解释说明
浏览器原理学习笔记02—浏览器中的JavaScript执行机制
执行上下文(Execution context)是 JavaScript 执行一段代码时的运行环境,比如调用一个函数,就会进入这个函数的执行上下文,确定该函数在执行期间用到的 this、变量、对象以及函数等。
CS逍遥剑仙
2020/05/02
1.1K1
详解作用域链
在本文中,我们将着重讨论作用域链。首先我们会了解作用域、块级作用域、相关的一些重要概念等前置基础知识,接着我们会通过几个例子来对作用域链进行详细讲解,最后我们还会涉及作用域链延长的问题。在了解完上述知识之后,在本文主要内容的最后,我们还精选了网上几个作用域链相关的题目供小伙伴思考。
石璞东
2020/05/22
5680
作用域、执行环境、作用域链
作用域,之前有介绍过,JavaScript无块级作用域,只有函数作用域,简单点说就是JavaScript的作用域就是函数作用域。因为有函数作用域,所以我们有全局作用域和局部作用域的说法。
wade
2020/04/23
1.5K0
理解JavaScript的作用域
当一个块或函数嵌套在另一个块或函数中时,就发生了作用域的嵌套。作用域嵌套的查询规则:
4O4
2022/04/25
7070
推荐阅读
相关推荐
从 JavaScript 作用域说开去
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文