Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[js] 第106天 说说你对作用域链的理解 #1007

Open
haizhilin2013 opened this issue Jul 30, 2019 · 13 comments
Open

[js] 第106天 说说你对作用域链的理解 #1007

haizhilin2013 opened this issue Jul 30, 2019 · 13 comments
Labels
js JavaScript

Comments

@haizhilin2013
Copy link
Collaborator

haizhilin2013 commented Jul 30, 2019

第106天 说说你对作用域链的理解

@haizhilin2013 haizhilin2013 added the js JavaScript label Jul 30, 2019
@EmiyaYang
Copy link

EmiyaYang commented Jul 31, 2019

@haizhilin2013 是"作用域链"而不是“作用链域“

作用域链与函数执行栈相对应。js运行环境分为全局、函数以及eval三类,每当代码执行进入了一个新的运行环境就会将环境的执行上下文入栈,退出环境时将其出栈,从栈顶到栈底形成从内层到外层的嵌套关系。

由执行上下文创建的词法环境持有外层执行上下文的词法环境引用,当JS引擎在当前词法环境中找不到相应的变量时,会逐层向外查找,如此形成的链表即为作用域链。

@haizhilin2013
Copy link
Collaborator Author

@EmiyaYang 多谢指正!已修改!

@haizhilin2013 haizhilin2013 changed the title [js] 第106天 说说你对作用链域的理解 [js] 第106天 说说你对作用域链的理解 Jul 31, 2019
@HuoXiaoYe
Copy link

HuoXiaoYe commented Jul 31, 2019

作用域分为全局作用域和局部作用域,function会产生局部作用域,在全局环境中无法访问局部变量,局部环境内可以访问全局变量。若是函数中嵌套函数,嵌套的函数中还有函数,那么,这样就会形成作用域链。最内部的函数中的变量,会现在自身函数内找是否定义了改变量,若没定义,则向上一级函数中寻找,若上一级函数也没有定义,则继续向上寻找变量,直到全局环境,若还是没有找到,则报错。

@nowherebutup
Copy link

作用域链指的是代码执行时,
查找变量的规则,
先在当前自身的作用域查找,
找不到在往上级作用域查找,
查不到的话直至全局环境,
当然全局环境不能访问局部作用域的变量

@LinStan
Copy link

LinStan commented Jul 31, 2019

JS中每个函数或者变量都有其自身的作用域,作用域可以理解为他们的执行环境。

每次调用函数的时候都会对其生成一个作用域链,这个作用域链可用于在函数执行过程中查找执行涉及的变量和函数。

查找顺序为当前执行函数内部->外部函数->>全局执行环境

如下图例子就为son->test->全局

let a = 1;
    var test = function () {
      let b = 2;
      var son = function () {
        let c = 3;
        console.log('a' + a, 'b' + b, 'c' + c)
      }()
    }()

@liuxiaole
Copy link

引擎初始化时首先会创建一个上下文环境作为初始全局执行上下文(global execution context), top level 的代码将在这个上下文中执行。 执行到函数调用时,引擎会创建新的执行上下文(每次调用都会产生新的执行上下文)。 执行上下文包含一张变量映射表(variable object)、this 指针、激活对象(全局执行上下文没有)和作用域链。 变量表记录着在该上下文执行环境下创建的局部变量和函数,函数调用生成的执行上下文额外包含由函数的参数构成的激活对象 (activation object),this 指针根据函数的调用方式不同而不同,而作用域链由当前作用域,即变量表和激活对象(函数参数),以及父作用域的引用构成。全局执行上下文是初始上下文,因此其作用域中没有父作用域引用,只包含变量表。而对于函数调用产生的执行上下文,函数在创建时(声明时),会记录下当时执行上下文中的作用域( chrome console 中以 [[scopes]] 形式展示),保存其引用,等到函数调用并创建执行上下文构造新的作用域时,便以此作用域作为父作用域。由一级级父作用域构成一个链式引用,此即称之为作用域链。链的顶端即全局作用域。

在上下文中读取变量时,引擎会先在当前作用域中查找,即先查找激活对象,然后查找变量表,如果未找到,则通过作用域链中父作用域的引用,在父域中查找,依此类推,直到查找到全局上下文中的作用域。如果仍未找到则返回 undefined 。

闭包:在某执行上下文中创建了一个函数,函数会引用当前上下文的作用域以备后续调用时创建新的执行上下文使用。一般地,在执行结束后(函数调用结束后),执行上下文会被销毁,其变量表,激活对象和作用域都将被销毁。但如果此次执行结束后,期间创建的函数仍在其他地方存在引用,则意味着该执行上下文中的作用域并不会被销毁,其变量表或激活对象中的变量引用也仍然存在。JS 引擎在处理函数声明对所处上下文作用域的引用时,并不会简单地引用整个作用域链,而会智能分析函数内部用到了当前作用域链上的哪些变量,然后创建一个作用域副本,并把这些变量放入其中。这一步称之为函数捕获了当前作用域中的某些变量,这些变量被关在了这个副本作用域中。直到这个函数的所有引用置空,函数被销毁,这个副本作用域才会被销毁,被捕获的变量才能得以释放。此即闭包。

ES6 的块也会生成新的作用域,进入块时创建新的作用域并压入链顶,退出块时弹出作用域,但不产生新的执行上下文。

@JokerYRF
Copy link

1 如果是函数环境,arguments 对象
2 下一个变量对象来自包含(外部)环境
3 下一个变量对象,来自下一个包含环境
4 ... 延续到全局执行环境(始终是最后一个对象)

@EragonBubble
Copy link

楼上总结的非常好,当然题还是要自己答的。

主要是解决函数体里的变量访问
1.js函数会产生作用域
2.在访问函数体里的变量时,如果在当前函数体里没有找到该变量,则从函数所在的全局作用域中找。
3.函数可以嵌套函数,于是形成了作用域链

@1134617484
Copy link

个人理解 全局包含块级作用域块级(函数体)可链式调用,比如递归,比如函数嵌套,这些都会使块级作用域产生连接作用,一环扣一环,但总体在全局框内,

@seho-dev
Copy link

js有全局作用域,函数作用域,es6之后可以使用let和const表达局部作用域,一个函数或者代码块代表一个域,一个一个域在js代码中分别入栈,读取一个变量的时候,会先从顶层找(即距离本域最近的一个域),直到找到全局作用域还没找到,就返回undefined

@CHWYH
Copy link

CHWYH commented Jun 26, 2020

闭包:在某执行上下文中创建了一个函数,函数会引用当前上下文的作用域以备后续调用时创建新的执行上下文使用。一般地,在执行结束后(函数调用结束后),执行上下文会被销毁,其变量表,激活对象和作用域都将被销毁。但如果此次执行结束后,期间创建的函数仍在其他地方存在引用,则意味着该执行上下文中的作用域并不会被销毁,其变量表或激活对象中的变量引用也仍然存在。JS 引擎在处理函数声明对所处上下文作用域的引用时,并不会简单地引用整个作用域链,而会智能分析函数内部用到了当前作用域链上的哪些变量,然后创建一个作用域副本,并把这些变量放入其中。这一步称之为函数捕获了当前作用域中的某些变量,这些变量被关在了这个副本作用域中。直到这个函数的所有引用置空,函数被销毁,这个副本作用域才会被销毁,被捕获的变量才能得以释放。此即闭包

这段描述很贴切很形象

@lizhesystem
Copy link

function funcA () {
        let a;
	function funcB () {
		let b;
	}
}

参考上面例子:

当进入funcA时,这时候会把变量a压入当前的作用域A中,并且将作用域A入栈,
当进入funcB时,则会把变量b压入当前的作用域B中,并且将作用域B入栈,那么这时候栈中就有了作用域A和作用域B

当在funcB中查找某个变量时,会先从当前的作用域B中查找,如果没有的话,那么就根据栈中的作用域依次往上查找,这就是作用域链。

@xiaoqiangz
Copy link

js分全局作用域、函数作用域,es6新增了块级作用域,作用域链可以这么理解:在函数作用域内,查找某个变量时,首先会查找当前自身作用域的变量,如果没有会去上一层作用域内找,如果没有会找到全局作用域内才会结束,这就是作用域链。
全局作用域不能访问函数作用域内的参数,如果需要访问某函数作用内参数可以使用闭包。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
js JavaScript
Projects
None yet
Development

No branches or pull requests