重温js——作用域和作用域链

简介: js代码执行,会在call stack创建对应的作用域(执行上下文),然后每一个上下文中会有一个VO来保存当前作用域的变量. 但是VO中如果会创建函数,那么函数中有一个额外的属[[scoped]]会指向栈中最顶层的VO(AO);

作用域


看过上一篇重温js——执行上下文,里面提到了一个概念叫做执行环境,在里面说到了 全局环境,函数环境和eval的环境。那里面所说的环境,其实就是作用域,所以这里在稍微唠叨一下,作用域有以下:


  • 全局作用域(Global scope):和前文的GO对象一样
  • 函数作用域(Function scope):处于每一次执行的VO对象
  • 块级作用域(es6以后补充的):es6以后定义变量的关键字变成let和const, let 和 const有自己的规则,详情查看.


既然变量有作用域,函数也有作用域,那么他们是怎么连接起来形成作用域链呢?


作用域链


js代码执行,会在call stack创建对应的作用域(执行上下文),然后每一个上下文中会有一个VO来保存当前作用域的变量. 但是VO中如果会创建函数,那么函数中有一个额外的属[[scoped]]会指向栈中最顶层的VO(AO);


上面的那一段话有点不好理解,咋们来举个例子,画个图来看看就明白了。


// 这一道题目输出的a是多少
var a = 1;
function A(){
  console.log(a)
}
function B(){
 var a = 123;
 var C = A;
 C();
}
B();


需要理解这个例子,咋们来画画图。


7c995673a5d9434aa9019ae767b1fa12.gif


上面图中的每一帧可以理解为代码在运行过程中所作的事情。


咋们先那函数C 来分析,函数C 指向的是函数A的地址,然而函数A又是在全局的作用域中创建的,所以函数A的[[scoped]] 是指向GO对象的. 如下图红色线条:


eba859f29b0240fa882fd15e961f1076.png


C 中的变量查找方式C ---> A ---> GO, 形如: C ---> A ---> GO这样作用域指向的形式,我们称之为作用域链。查找对象也是严格按照作用域链来查找的。


结果:


5a5cabba00f64586ad900dfb583be757.png


闭包


在上面的那个例子中,我们的函数A相当于保存到了函数B的内部(B内部使用的是引用地址),实际上函数A所处的作用域还是全局作用域。


  • 从广义上来说,函数内部使用函数,并且里面函数用到了外面的作用的变量。上面例子中的函数B就形成了闭包。


  • 从狭义上来讲:函数内部使用了外部的变量,并且函数在其他作用域调用就形成闭包。


// 这一道题目输出的a是多少
var a = 1;
function A(){
  console.log(a)
}
function B(){
 var a = 123;
 var C = A;
 C();
}
B();


其实闭包在我们的开发中是非常常见的。其实还有一个问题,就是说闭包带来的问题:

内存泄漏, 这个观点是不对的。内存泄漏是指内存中的变量不能够访问并且不能被垃圾回收给清理掉。上面的那个例子中变量a可以找到吧。我们找到他的方式有很多种。


这里有的人可能需要说,我们看到的闭包是下面的这种形式?


function A(){
 var a = 1223;
 return function(){
    console.log(a)
  }
}
var afunc = A();
afunc();


上面的代码,先创建函数A,然后执行函数A,然后函数A返回一个函数。只要函数执行了,call stack 中会清空哇,哪里会有内存占用不释放呢?

相关文章
|
13天前
|
JavaScript 前端开发
js变量的作用域、作用域链、数据类型和转换应用案例
【4月更文挑战第27天】JavaScript 中变量有全局和局部作用域,全局变量在所有地方可访问,局部变量只限其定义的代码块。作用域链允许变量在当前块未定义时向上搜索父级作用域。语言支持多种数据类型,如字符串、数字、布尔值,可通过 `typeof` 检查类型。转换数据类型用 `parseInt` 或 `parseFloat`,将字符串转为数值。
18 1
|
1月前
|
存储 JavaScript 前端开发
解释 JavaScript 中的作用域和作用域链的概念。
【4月更文挑战第4天】JavaScript作用域定义了变量和函数的可见范围,静态决定于编码时。每个函数作为对象拥有`scope`属性,关联运行期上下文集合。执行上下文在函数执行时创建,定义执行环境,每次调用函数都会生成独特上下文。作用域链是按层级组织的作用域集合,自内向外查找变量。变量查找遵循从当前执行上下文到全局上下文的顺序,若找不到则抛出异常。
21 6
|
1月前
|
JavaScript
作用域和作用域链(js的问题)
作用域和作用域链(js的问题)
|
2月前
|
自然语言处理 JavaScript 前端开发
深入理解JS的执行上下文、词法作用域和闭包(中)
深入理解JS的执行上下文、词法作用域和闭包(中)
|
2月前
|
存储 自然语言处理 JavaScript
深入理解JS的执行上下文、词法作用域和闭包(上)
深入理解JS的执行上下文、词法作用域和闭包(上)
|
2月前
|
JavaScript 前端开发
js开发:请解释什么是作用域(scope),并说明全局作用域、局部作用域和块级作用域的区别。
JavaScript中的作用域规定了变量和函数的可见性与生命周期。全局作用域适用于整个脚本,变量可通过全局对象访问,可能导致命名冲突和内存占用。局部作用域限于函数内部,每次调用创建新作用域,执行完毕后销毁。ES6引入的块级作用域通过`let`和`const`实现,变量仅在其代码块内有效,并有暂时性死区。作用域机制有助于代码组织和变量管理。
23 1
|
2月前
|
自然语言处理 前端开发 JavaScript
深入理解JavaScript中的闭包与作用域链
在JavaScript编程中,闭包和作用域链是两个非常重要的概念,它们对于理解代码的执行过程和解决一些特定问题至关重要。本文将深入探讨JavaScript中闭包和作用域链的原理和应用,帮助读者更好地理解这些概念并能够在实际项目中灵活运用。
|
2月前
|
JavaScript 前端开发
JS作用域与作用域链
JS作用域与作用域链
|
2月前
|
自然语言处理 JavaScript 前端开发
深入探索 JS 的提升机制、函数与块作用域以及函数表达式和声明(下)
深入探索 JS 的提升机制、函数与块作用域以及函数表达式和声明(下)
|
2月前
|
JavaScript 前端开发
深入探索 JS 的提升机制、函数与块作用域以及函数表达式和声明(上)
深入探索 JS 的提升机制、函数与块作用域以及函数表达式和声明(上)