阅读 153

作用域与作用域链

作用域(Scope)

作用域产生于程序源代码中声明变量的区域,在程序编译阶段就确定了。帮助在程序执行阶段"查询并规定变量的可见性与可访问性。

作用域共两种工作模型:静态作用域动态作用域
Javascript运用的是静态作用域,函数作用域在声明时确定;Bash脚本运用的是动态作用域,函数作用域在调用时确定

案例

let a = 1 function foo() {   console.log(a)   } function bar() {   let a = 2   foo() } bar() 复制代码

静态作用域: 函数作用域在声明时确定,foo函数内部不存在变量a,依据作用域链向上寻找到全局作用域中的变量a,输出结果1
动态作用域: 函数作用域在调用时确定,foo函数内部不存在变量a,因foobar中调用寻找bar作用域内的变量a,输出结果2

Javascript中可分为三种作用域:全局作用域函数作用域块级作用域

全局作用域

程序中任何地方都有权访问全局作用域下的声明的变量。
注意: 多人协作下,定义在全局的变量容易引发命名冲突、污染全局的问题。为了避免污染有以下两种方式。

  1. 创建私有的命名空间,可一定程度的降低被污染的风险。

let object = {     name: '瑾行',     getName: function() {} } 复制代码

  1. 创建立即调用函数表达式(IIFE),Jquery就是这么干的...????,利用函数作用域私有化变量起到隔离变量的作用。

(function(obj) {     var name = '瑾行'     var getName = function() {} })(window) console.log(name) //输出为空  console.log(getName) //输出为空 复制代码

函数作用域

函数内部定义的变量,外层作用域无权进行访问。当然,耍些手段可达到目的:闭包
例子:

function closure() {     let name = '瑾行',     return hello() {         console.log('hello,' + name)     } } let func = closure() func() // hello,瑾行 复制代码

块级作用域

ES6 新增letconst命令,使声明的变量仅在当前函数内部或代码块中访问。
块级作用域有如下特点:

  1. var相比,不存在变量提升。

  2. 不允许重复定义

  3. 全局定义不绑定在window上

来看下,利用块级作用域解决的经典面试题

for(var i = 0; i < 5; i++) {     setTimeout(() => {         console.log(i) // 5个5     }) } // 将i绑定到for循环的块作用域 for(let i = 0; i < 5; i++) {     setTimeout(() => {         console.log(i) // 0,1,2,3,4                                                            }) } 复制代码

作用域链

上文提到作用域是在定义时就确定了。原因是函数有个内部属性[[scopes]],当函数创建时,会保存所有的父变量对象;当函数被调用时,关联当前函数的活动对象(初始化arguments)与定义时的所有父变量对象确定完整的作用域链。[[scopes]]如图所示。

image.png

作用域链的最前端是当前环境的变量对象,末端是全局window环境的变量对象

例子

let msg = 'hello,' function say() {     let name = '瑾行'     return function hello() {       console.log(msg + name)      } }  let hello = say() hello() // hello, 瑾行 复制代码

image.png

name 在Closure变量对象中,msg在 顶层Script变量对象中(因let 声明,未绑定在window的变量对象)。

作用域与执行上下文

作用域与执行上下文的概念经常被混为一谈。
作用域上文提到在程序编译阶段确定,但执行上下文是在代码执行阶段确定,是执行代码时所在环境的抽象概念,主要通过引擎创建执行上下文栈来管理执行上下文  。

执行上下文生命周期:创建阶段执行阶段回收阶段

  1. 创建执行上下文,包含三个属性:变量对象、作用域链、this指向。

  2. 执行变量赋值、函数引用,执行其余代码。

  3. 垃圾回收。

执行上下文类型:全局执行上下文函数执行上下文Eval函数执行上下文
全局上下文:当开始执行程序时,就会创建全局上下文压入栈中,结束程序,从栈中弹出。
函数执行上下文:当每个函数被调用时,都会创建一个对应的执行上下文,函数调用结束,从栈中弹出
Eval函数执行上下文:执行eval函数时创建。

举个????。

let a = 1 function foo() {   console.log(a)   } function bar() {   let a = 2   foo() } bar() 复制代码

未命名文件.png


作者:花哨
链接:https://juejin.cn/post/6993628835543515172


文章分类
后端
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐