Repository navigation
JavaScript深入之作用域链 #6
Description
Activity
大神你好,问你一个问题,checkscope函数被创建时,保存到[[scope]]的作用域链和checkscope执行前的准备工作中,复制函数[[scope]]属性创建的作用域链有什么不同么?为什么会有两个作用域链?
Reacted by zhdxcz, 杨腿, LwbK and baichencheckscope函数创建的时候,保存的是根据词法所生成的作用域链,checkscope执行的时候,会复制这个作用域链,作为自己作用域链的初始化,然后根据环境生成变量对象,然后将这个变量对象,添加到这个复制的作用域链,这才完整的构建了自己的作用域链。至于为什么会有两个作用域链,是因为在函数创建的时候并不能确定最终的作用域的样子,为什么会采用复制的方式而不是直接修改呢?应该是因为函数会被调用很多次吧。
Reacted by menglingfei, zhangzw, MattZeng, 涛儿, 钠铬谁, liuliang, 明昌, Howard Tang, Shangbin Yang, sandGuard and 210 moreReacted by 微醺岁月, stickmy, Open-FE, weiai, 砖家, Ocean Liang, jingke, zhao chong, andy, mandom and 21 moreReacted by 微醺岁月, chuck, Benny Eu, stickmy, weiai, 砖家, jingke, andy, Howard, baiyuze and 16 moreReacted by harifakingReacted by 微醺岁月, imgwho, Benny Eu, stickmy, mumiao, weiai, whatwg6, 砖家, jingke, Howard and 17 moreReacted by Howard, baiyuze, 墨夜, xufeimac, chiic, Anoninz, xixi, Xiaoxi, fly-cool, guanxc9876 and 17 moreReacted by 墨夜, ROKIVABLE, Anoninz, smallant, xixi, zdc1111, fly-cool, guanxc9876, Wling, HuaiNian1994 and 12 more@menglingfei 在js中复制有分两种,比如说基本类型的复制,就是直接的赋值,两个变量以后互不影响。而引用类型的复制,是指两个变量同时指向一个对象。我觉得这里应该说的是后者吧。
Reacted by Setsuna, sclchic, 沐橙, beexpectedone and Beixiaomi函数有一个内部属性 [[scope]],当函数创建的时候,就会保存所有父变量对象到其中,想问一下变量对象是创建上下文的时候才有的吧
function foo() {
function bar() {
...
}
}
要是foo没有创建上下文,那bar怎么保存foo的变量对象啊Reacted by fly-cool@yh284914425 以你举的例子为例的话,当 foo 函数的执行上下文初始化的时候,才会创建 bar 函数。
Reacted by jingke, Ezio, Jesse, 刘文, 陈程城, szmintel, Jay Yoon, slowlydd, mjj625865426, bigtomissyue and 2 moreReacted by sky blue@mqyqingfeng 好吧,当函数创建的时候,就会保存所有父变量对象到其中这个过程感觉不是很明白,能说的清楚一些吗,以我举的例子为例的话,当 foo 函数的执行上下文初始化的时候,才会创建 bar 函数,bar函数保存foo的变量对象,那更外层的变量对象呢
Reacted by Li Chunbo, 哦哈哈, PrimeLeon and Jamartin@yh284914425 更外层就是全局对象呐~ 所以bar 的 [[scope]] 属性值就是 [ fooContext.AO, globalContext.VO];
@mqyqingfeng 我知道呀,就是想问一下,[[scope]] 属性值是怎么把globalContext.VO保存进去的,有点转牛角尖,嘿嘿
@yh284914425 根据词法作用域的规则找出最外层的就是 globalContext ,然后……然后就保存呐……具体是怎么保存进去的,这个应该是实现层面上的吧
听君一席话 胜读十本书
Reacted by ljscode and 螃蟹Reacted by Shawn Leo@sandGuard 感谢,这真是对我莫大的肯定~
《JS高程》讲到,每一个函数都有自己的执行环境。好像这里没有讲到额
128 remaining items
各位大佬我想问下为什么 [[Scopes]] l里面的Closure (outerFunction) {hidden: 4}。会为4 的按照我的 理解 inc 函数会 查找当前活动对象 在查找outerFunction 变脸对象在查找 Global 变量对象 自身活动对象没 有hidden 变量然后查找outerFunction 但是 打印的话他的值是4 为什么 myClosure.inc() 的返回结果是正确的呢。对不上了呀
因为你 return 3 之后执行了 hidden++
- 我是曾满英,您的邮件我已收到!
@mqyqingfeng 捋一捋里面的第一步是不是应该是 globalContext.AO?
checkscope.[[scope]] = [
globalContext.VO // 这里是不是应该是 AO ?
];先return 后执行++, 改为return ++hidden就对上了
- 我是曾满英,您的邮件我已收到!
- 这是来自QQ邮箱的假期自动回复邮件。 您好,我最近正在休假中,无法亲自回复您的邮件。我将在假期结束后,尽快给您回复。
在《javascript忍者秘籍》里说到的词法环境[[Environment]]与这里的[[Scope]]和作用域链有什么关系?感觉书里讲的[[Environment]]很像作用域链
- 我是曾满英,您的邮件我已收到!
大佬 可以举例说明下 什么情况下会遇到函数预解析时的:《 第二次复制函数[[scope]]属性创建作用域链》的逻辑吗 这块还是没有理解透彻
- 我是曾满英,您的邮件我已收到!
函数执行上下文中的对象是不是就等于这个函数的作用域
也就是说,每个可执行代码块的执行上下文 = 代码块作用域 + 作用域链 + this- 我是曾满英,您的邮件我已收到!
checkscope函数创建的时候,保存的是根据词法所生成的作用域链,checkscope执行的时候,会复制这个作用域链,作为自己作用域链的初始化,然后根据环境生成变量对象,然后将这个变量对象,添加到这个复制的作用域链,这才完整的构建了自己的作用域链。至于为什么会有两个作用域链,是因为在函数创建的时候并不能确定最终的作用域的样子,为什么会采用复制的方式而不是直接修改呢?应该是因为函数会被调用很多次吧。
这里应该想说的是完整的构建了自己的执行上下文吧?而不是作用域链
- 我是曾满英,您的邮件我已收到!
- 这是来自QQ邮箱的假期自动回复邮件。你好,你的邮件我收到,谢谢。
前言
在《JavaScript深入之执行上下文栈》中讲到,当JavaScript代码执行一段可执行代码(executable code)时,会创建对应的执行上下文(execution context)。
对于每个执行上下文,都有三个重要属性:
今天重点讲讲作用域链。
作用域链
在《JavaScript深入之变量对象》中讲到,当查找变量的时候,会先从当前上下文的变量对象中查找,如果没有找到,就会从父级(词法层面上的父级)执行上下文的变量对象中查找,一直找到全局上下文的变量对象,也就是全局对象。这样由多个执行上下文的变量对象构成的链表就叫做作用域链。
下面,让我们以一个函数的创建和激活两个时期来讲解作用域链是如何创建和变化的。
函数创建
在《JavaScript深入之词法作用域和动态作用域》中讲到,函数的作用域在函数定义的时候就决定了。
这是因为函数有一个内部属性 [[scope]],当函数创建的时候,就会保存所有父变量对象到其中,你可以理解 [[scope]] 就是所有父变量对象的层级链,但是注意:[[scope]] 并不代表完整的作用域链!
举个例子:
函数创建时,各自的[[scope]]为:
函数激活
当函数激活时,进入函数上下文,创建 VO/AO 后,就会将活动对象添加到作用链的前端。
这时候执行上下文的作用域链,我们命名为 Scope:
至此,作用域链创建完毕。
捋一捋
以下面的例子为例,结合着之前讲的变量对象和执行上下文栈,我们来总结一下函数执行上下文中作用域链和变量对象的创建过程:
执行过程如下:
1.checkscope 函数被创建,保存作用域链到 内部属性[[scope]]
2.执行 checkscope 函数,创建 checkscope 函数执行上下文,checkscope 函数执行上下文被压入执行上下文栈
3.checkscope 函数并不立刻执行,开始做准备工作,第一步:复制函数[[scope]]属性创建作用域链
4.第二步:用 arguments 创建活动对象,随后初始化活动对象,加入形参、函数声明、变量声明
5.第三步:将活动对象压入 checkscope 作用域链顶端
6.准备工作做完,开始执行函数,随着函数的执行,修改 AO 的属性值
7.查找到 scope2 的值,返回后函数执行完毕,函数上下文从执行上下文栈中弹出
下一篇文章
《JavaScript深入之从ECMAScript规范解读this》
本文相关链接
《JavaScript深入之词法作用域和动态作用域》
《JavaScript深入之执行上下文栈》
《JavaScript深入之变量对象》
深入系列
JavaScript深入系列目录地址:https://github.com/mqyqingfeng/Blog。
JavaScript深入系列预计写十五篇左右,旨在帮大家捋顺JavaScript底层知识,重点讲解如原型、作用域、执行上下文、变量对象、this、闭包、按值传递、call、apply、bind、new、继承等难点概念。
如果有错误或者不严谨的地方,请务必给予指正,十分感谢。如果喜欢或者有所启发,欢迎star,对作者也是一种鼓励。