位置: 编程技术 - 正文

javascript作用域链(Scope Chain)用法实例解析(javascript作用域链)

编辑:rootadmin

推荐整理分享javascript作用域链(Scope Chain)用法实例解析(javascript作用域链),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:js有哪些作用域,分别是什么意思,js作用域和执行环境,javascript 作用域,javascript作用域有几种,javascript作用域链,javascript作用域有几种,javascript作用域和闭包,javascript作用域有几种,内容如对您有帮助,希望把文章链接给更多的朋友!

本文实例分析了javascript作用域链(Scope Chain)用法。分享给大家供大家参考,具体如下:

关于js的作用域链,早有耳闻,也曾看过几篇介绍性的博文,但一直都理解的模棱两可。近日又精心翻看了一下《悟透Javascript》这本书,觉得写得太深刻,在“代码的时空”一节里有一段介绍作用域链的地方寥寥数语,回味无穷(其实还是理解的模棱两可^_^)。现在整理下自己的读书笔记,顺便借鉴网上资源,写下来。

一、从一个简单的问题说起

下面的js代码在页面中运行显示什么结果:

您的答案是什么?没错,就是弹出。我的理解是这样的,funTest函数有一个形参arg,funTest函数传入实参,alert方法把弹出就是了,?濉?br />好,问题又来了:

答案是什么?如果是5年前的我,肯定不会再往下想了,还是!这么简单的问题还用想什么呀?我的理解是这样的:funTest函数是一个无参数的函数,函数内部通过alert方法,调用外部(全局)的变量arg,在函数执行前,arg赋值为,弹出arg值后改变arg值为2,所以弹出值为。

真的是吗?是还是不是?

测试的结果:弹出“undefined”,瀑布汗.

二、理解作用域链,从javascript运行机制说起

1、js的运行顺序

如果一个文档流中包含多个script代码段(用script标签分隔的js代码或引入的js文件),它们的运行顺序是:

步骤1. 读入第一个代码段(js执行引擎并非一行一行地执行程序,而是一段一段地分析执行的)步骤2. 做语法分析,有错则报语法错误(比如括号不匹配等),并跳转到步骤5步骤3. 对var变量和function定义做“预解析”(永远不会报错的,因为只解析正确的声明)步骤4. 执行代码段,有错则报错(比如变量未定义)步骤5. 如果还有下一个代码段,则读入下一个代码段,重复步骤2步骤6. 结束

上面的分析已经足够清楚,步骤二、三和步骤四里的红色字体可能是我们新手理解上的一个盲点,尤其是步骤三的“预解析”,如果不清楚什么叫预解析,总觉得不踏实。而步骤四的“有错则报错”也是经常碰到的。举例来说:

上面这段代码执行时,弹出“undefined”,也就是说arg没有定义,js的变量不是不用定义也可以吗?

2、语法分析和“预解析”

(1)、从解释型语言的编译过程说起

众所周知,javascript是解释型语言,它不同于c#和java等编译型语言。对于传统编译型语言来说,编译步骤分为:词法分析、语法分析、语义检查、代码优化和字节生成;但对于解释型语言来说,通过词法分析和语法分析得到语法树后,就可以开始解释执行了。

a、词法分析

简单地说,词法分析是将字符流(char stream)转换为记号流(token stream)。但是这个转换过程并不是可以用一句话就可以概括的那么简单,我们可以试着用伪代码理解一段简单的程序:

代码var result=x-y;的转换大致可以表示如下:

NAME "result"EQUALSNAME "x"MINUSNAME "y"SEMICOLON

b、语法分析

javascript作用域链(Scope Chain)用法实例解析(javascript作用域链)

简单地说,语法分析就是为了构造合法的语法分析树,而语法分析树可以直观地表示出推导的过程。

那么什么是语法分析树?简单地说,就是程序推导过程的描述。但是到底什么是语法树,请参考专业文章,本篇略过。

c、其他

通过语法分析,构造出语法分析树后,接下来还可能需要进一步的语义检查。对于传统强类型语言来说,语义检查的主要部分是类型检查,比如函数的实参和形参类型是否匹配等等。结论:通过上面的分析可以看出,对于javascript引擎来说,肯定有词法分析和语法分析,之后可能还有语义检查、代码优化等步骤,等这些编译步骤完成之后(任何语言都有编译过程,只是解释型语言没有编译成二进制代码),才会开始执行代码。

(2)、执行过程

a、javascript的作用域机制

通过编译,javascript代码已经翻译成了语法树,然后会立刻按照语法树执行。

进一步的执行过程,需要理解javascript的作用域机制:词法作用域(lexcical scope)。通俗地讲,就是javascript变量的作用域是在定义时决定而不是执行时决定,也就是说词法作用域取决于源码,编译器通过静态分析就能确定,因此词法作用域也叫做静态作用域(static scope)。但需要注意,with和eval的语义无法仅通过静态技术实现,所以只能说javascript的作用域机制非常接近词法作用域(lexical scope).

javascript引擎在执行每个函数实例时,都会创建一个执行环境(execution context)。执行环境中包含一个调用对象(call object), 调用对象是一个scriptObject结构(scriptObject是与函数相关的一套静态系统,与函数实例的生命周期保持一致),用来保存内部变量表varDecls、内嵌函数表funDecls、父级引用列表upvalue等语法分析结构(注意varDecls和funDecls等信息是在语法分析阶段就已经得到,并保存在语法树中。函数实例执行时,会将这些信息从语法树复制到scriptObject上)。

b、javascript作用域机制的实现方法

词法作用域(lexical scope)是javascript的作用域机制,还需要理解它的实现方法,就是作用域链(scope chain)。作用域链是一个name lookup机制,首先在当前执行环境的scriptObject中寻找,没找到,则顺着upvalue到父scriptObject中寻找,一直lookup到全局调用对象(global object)。

现在回过头来分析第二个问题:

在执行funcTest函数时,也即进入了funcTest对应的作用域,js引擎在执行时,当遇到对变量名或者函数名的使用时,会首先在当前作用域(也即funcTest对应的作用域)查找变量或者函数(显然,arg变量在funcTest对应的作用域里被定义为var arg=2 所以alert方法的参数采用的是当前作用域的arg,但是因为arg被定义在alert方法后,所以arg变量默认值为undefined)。当然,如果没有找到就到上层作用域查找,依此类推(作用域范围可以持续到javascript运行环境的根:window对象)。

最后,让你看的更清楚,上面的代码其实可以等价于:

c、闭包(closure)

当一个函数实例执行时,会创建或关联到一个闭包。 (关于闭包,打算另写一篇学习笔记)

scriptObject用来静态保存与函数相关的变量表,闭包则在执行期动态保存这些变量表及其运行值;

闭包的生命周期有可能比函数实例长。函数实例在活动引用为空后会自动销毁;

闭包则要等要数据引用为空后,由javascript引擎回收(有些情况下不会自动回收,就导致了内存泄漏)。

ps:关于“执行过程”这一段比较拗口,名词很多,不过别被它们吓住,一旦理解了执行环境(execution context)、调用对象(call object)、词法作用域(lexical scope)、作用域链(scope chain)、闭包(closure)等这些概念,javascript的很多现象都能迎刃而解。

三、结语

通过第二段的分析,对照第一段笔者曾经做出的判断(你是不是也觉得笔者曾经的分析和结论很幼稚(哪怕有时结果碰巧也对!)?!不是一般的肤浅啊,^_^),你会发现原来javascript还有这么多“玄机”,而要真正理解精通又谈何容易?先“悟透”再说吧。

希望本文所述对大家JavaScript程序设计有所帮助。

全面解析Bootstrap排版使用方法(标题) Bootstrap和普通的HTML页面一样,定义标题都是使用标签h1到h6,只不过Bootstrap覆盖了其默认的样式,使用其在所有浏览器下显示的效果一样,具体定义的规

JavaScript基础篇(3)之Object、Function等引用类型 阅读目录Object类型1、通过构造函数来创建2、通过字面量表示法来创建对象Array类型同样Array也有两种创建方式:如果我们想要打印数组中所有的值,直接

javascript中eval和with用法实例总结 本文实例讲述了javascript中eval和with用法。分享给大家供大家参考,具体如下:我们都知道javascript的作用域机制,但是with和eval有时会破坏我们对于作用

标签: javascript作用域链

本文链接地址:https://www.jiuchutong.com/biancheng/386337.html 转载请保留说明!

上一篇:Bootstrap每天必学之js插件(bootstrap需要学多久)

下一篇:全面解析Bootstrap排版使用方法(标题)(全面解析朝鲜战争)

  • 个人所得税个人信息怎么填写
  • 电子商务税收的特征有哪些?
  • 研发设备定义
  • 设备转产需要停止折旧吗
  • 2021年销售农机免增值税吗
  • 基本户和一般户的用途
  • 一般纳税人的进项税额计入成本吗
  • 按季度申报,利润表中所得税费用怎么算出来的
  • 生产研发设备
  • 开票资料都包括什么内容
  • 2021留美学生签证
  • 应付职工薪酬的计税基础
  • 成本跨年如何处理
  • 金税盘发票号码确认显示不全
  • 出口退税征税
  • 个人所得税必须得交吗
  • 房地产开发企业应交税费科目
  • 合作社能否开具专用发票
  • 提供物业管理服务税率
  • 旧房转让如何缴纳土地增值税
  • 其他应付款可以用其他应收款代替吗
  • 公司注销无法支付的款项如何处理
  • 增值税普通发票有什么用
  • 资产处置收益的项目有哪些
  • win 7系统如何备份
  • 私款转入公司账户怎么办
  • window清除临时存储文件夹
  • mac底部菜单栏不见了快捷键
  • 以合同条款无法达成一致要求返还定金
  • 公司收到财政拨付办公经费
  • 内部退养如何缴纳个人所得税
  • 什么是跨域以及跨境电商
  • CSDN接入AIGC辅助创作,对此你怎么看?
  • 增值税专用发票和普通发票的区别
  • 个税申报表收入额怎么填
  • mysql select语法的使用
  • 运输行业一般纳税人开普票税率是多少
  • 企业股东分红可抵税吗
  • 又是客户又是供应商的舞弊行为
  • 借款人和还款人不一致,收据打给谁
  • 纳税人缴纳的税款叫做什么
  • 公司借个人款利息产生个人所得税公司可以承担吗
  • 房屋出租后转租缴纳房产税吗
  • 个体户记账报税
  • 个人挂靠公司承接工程如何做会计处理?
  • 购入房屋建筑物进项税额抵扣
  • 小公司用什么财务软件做账
  • sql数据库压缩能提高性能吗
  • 双启动子存在的意义
  • cmos设置密码开机密码
  • win7系统怎么连接
  • linux中使用最多的命令
  • centosfind命令
  • Mac怎么连接扫描仪
  • 怎样把系统及软件迁移到固态
  • opera installer
  • win7自带桌面时钟吗
  • win7系统无法更改主题
  • Unity3d Asset Serialization 设置错误导致SVN文件不能同步
  • 快速掌握知识的方法
  • gridview用法
  • 安卓开发过程中的问题
  • 使用scp获取远程linux服务器上的文件 linux远程拷贝文件
  • python如何判断一个变量的类型
  • unity3d音效
  • unity5.x游戏开发指南
  • JavaScript获取元素
  • js中不同的height, top的区别对比
  • uleb128、sleb128和uleb128p1编码格式介绍
  • activity与fragment的通信
  • 夜间模式图
  • 用python编写简单程序
  • 我置顶你也只顶你
  • javascript面向对象精要pdf
  • Cannot run program "/home/mohemi/Program/adt-bundle-linux-x86_64-20130729/sdk//tools/emulator": erro
  • 以下关于android应用程序的目录结构描述中,不正确的是
  • 2023河南新农合截止日期新规
  • 信息报送条例
  • 富士康走了,京东去哪了
  • 本科毕业去上海找什么工作好
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设