作用域和作用域链的简单理解
作用域和作用域链
作用域
javascript采用的静态作用域,也可以称为词法作用域,意思是说作用域是在定义的时候就创建了, 而不是运行的时候。此话对于初学者很不好理解,看看下面这个例子:
let a=1
function aa(){
console.log(a) //输出1
}
function bb(){
let a=2
aa()
}
是不是非常违背常理啊,你看嘛,aa在bb里面调用的,aa函数里面没有a变量,那么就应该去调用它的作 用域里找,刚好找到a等于2。思路是完美的,可是js的作者采用的静态作用域,不管你们怎么运行,你们 定义的时候作用域已经生成了。 那么什么是作用域? 变量和函数能被有效访问的区域或者集合。作用域决定了代码块之间的资源可访问性。 作用域也就是一个独立的空间,用于保护变量防止泄露,也起到隔离作用。每个作用域里的变量可以相同命名,互不干涉。就像一栋房子一样,每家每户都是独立的,就是作用域。 作用域又分为全局作用域和函数作用域,块级作用域。 全局作用域任何地方都可以访问到,如window,Math等全局对象。 函数作用域就是函数内部的变量和方法,函数外部是无法访问到的。 块级作用域指变量声明的代码段外是不可访问的,如let,const.
作用域链
知道作用域后,我们来说说什么是作用域链? 表示一个作用域可以访问到变量的一个集合。函数作为一个对象有一个[[scope]]属性,就是表示这个集合的。再来理解几个概念词: AO:活动变量(Active object,VO) VO:变量对象(Variable object,VO) 执行上下文:代码运行的环境,分为全局上下文和函数上下文。
举例子来说明一下:(借用的例子)
// 作者:jianyangdu洋仔
function a() {
function b() {
var b = 234;
}
var a = 123;
b();
}
var gloab = 100;
a();
第一步: a 函数定义
我们可以从上图中看到,a 函数在被定义时,a函数对象的属性[[scope]]作用域指向他的作用域链scope chain,此时它的作用域链的第一项指向了GO(Global Object)全局对象,我们看到全局对象上此时有5个属性,分别是this、window、document、a、glob
第二步: a 函数执行
当a函数被执行时,此时a函数对象的作用域[[scope]]的作用域链scope chain的第一项指向了AO(Activation Object)活动对象,AO对象里有4个属性,分别是this、arguments、a、b。第二项指向了GO(Global Object),GO对象里依然有5个属性,分别是this、window、document、a、golb。
第三步: b 函数定义
! 当b函数被定义时,此时b函数对象的作用域[[scope]]的作用域链scope chain的第一项指向了AO(Activation Object)活动对象,AO对象里有4个属性,分别是this、arguments、a、b。第二项指向了GO(Global Object),GO对象里依然有5个属性,分别是this、window、document、a、golb。
第四步: b 函数执行
当b函数被执行时,此时b函数对象的作用域[[scope]]的作用域链scope chain的第一项指向了AO(Activation Object)活动对象,AO对象里有3个属性,分别是this、arguments、b。第一项指向了AO(Activation Object)活动对象,AO对象里有4个属性,分别是this、arguments、a、b。第二项指向了GO(Global Object),GO对象里依然有5个属性,分别是this、window、document、a、golb。 以上就是上面代码执行完之后的结果。
- 是时候开始用C#快速开发移动应用了
- Open ID Connect(OIDC)在 ASP.NET Core中的应用
- Jetty入门
- java序列化反序列化深入探究
- 前后端分离开发模式下后端质量的保证 —— 单元测试
- java如何获取一个对象的大小
- JDK1.7新特性(3):java语言动态性之脚本语言API
- JDK1.7新特性(4):java语言动态性之反射API
- ASP.NET Core集成现有系统认证
- Redis(2):常用命令详解
- C#移动跨平台开发(2)Xamarin移动跨平台解决方案是如何工作的?
- Ruby(3):基本语法中
- Python(3):文件读写与异常
- 向ASP.NET Core迁移
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 面试题系列第2篇:new String()创建几个对象?有你不知道的
- spring之整合struts2
- django-URL之include函数(五)
- springmvc之使用ModelAttribute避免不允许被修改的值更新时为空
- 【colab pytorch】使用tensorboard可视化
- django-URL别名的作用(六)
- springmvc之如何确定目标方法Pojo类型的参数?
- 【colab pytorch】使用tensorboardcolab可视化
- 实用,完整的HTTP cookie指南
- django-URL之从URL中获取关键字(七)
- springmvc之使用POJO作为参数
- 【猫狗数据集】利用tensorboard可视化训练和测试过程
- springmvc之视图解析流程
- 【猫狗数据集】从命令行接收参数
- django-URL重定向(八)