想彻底搞懂作用域&作用域链?看这里

前言

面试时总是被问到作用域与作用域链, 嘴上说不出来?回答的模棱两可,心里对这些也是模模糊糊?网上的资料说的不够透彻,看了之后依旧模模糊糊?看这里, 让你彻底搞懂作用域与作用域链.

作用域

什么是作用域?

变量的可用范围

为什么要使用作用域?

使变量不被污染(使不同范围内的变量互不干扰)

js包括几级作用域?

2级 ,分别为:

  1. 全局作用域
  2. 函数作用域(局部)
    eg:
//全局作用域
//全局变量
var y=1;
//函数作用域
function fun(){
//局部变量
  var a=6;
}

全局作用域

  • 不属于任何函数的外部范围(任何范围都可以使用)
  • 保存在全局作用域的变量称为全局变量
    全局变量特点
    优点:可反复使用
    缺点:造成全局污染,因此开发禁止使用

函数作用域

  • 一个函数内的范围
  • 保存在函数作用域内的变量称之为局部变量
    局部变量特点
    优点:不会被污染
    缺点:无法反复使用

形成局部变量的方式

  • 函数形参
  • 函数作用域内var声明的变量
    eg:
//这里的参数y就是局部变量
function fun(y){
//这里a也是局部变量
 var a=6;
}

强调:只有函数的{}才能形成作用域

  • 不是所有的{}都能形成作用域
  • 也不是所有的{}里面的数据或者属性都是局部变量
    eg:
  • 对象的{},就不是作用域
  • 对象中的属性也不是局部变量
    var xiaoming={
    name:‘xiaoMing’
    }

作用域链

什么是?

保存的变量的使用顺序的一个链(也就是路线图), 被称为作用域链。
强调:其实每个函数在定义时,就已经规划好了自己专属的一个查找变量的路线图,也就是作用域链
再详细点:

  • 因为,js规定,一个函数既能用自己的作用域上的变量,又可以用外层作用域的变量
  • 所以需要一个 路线图 告诉每个函数,自己都可以去哪里找到想要的变量,就想我们平常旅游时规划旅游景点时的浏览路线一样。

如何找变量?

作用域链上找,先找自己的作用域有没有该变量, 没有向上找最近的父级作用域有没有该变量, 没有继续往上找,直到最顶层,全局,也就是由内向外查找,把自己当成一个js引擎。

本质

js中, 作用域和作用域链都是对象结构

何以见得?往下看->

  1. 新建名为scopes.html的网页:
var a=10;
function fun(){
var a=100;
a++;
console.log(a);
}
fun(); 
console.log(a);
  1. 用浏览器运行,并按F12打开控制台

image.png
3. 控制台里点击Sources,点开scopes.html,并打上断点

image.png
可以看到Scources里各个断点信息,其中作用域Scope里,只有Global(全局作用域)
4. 我们再点开Global,看一下里面的结构以及有哪些数据?

image.png

我们可以看到Global(全局作用域)是个对象结构,也就是个window对象,里面有我们定义的全局变量a和全局fun,有的小伙伴可能会纳闷,这里的a为什么是undefined, 因为程序开始执行时,会先把变量的声明提前,这里的a和fun都会被声明提前,a声明提前,不管有没有值,都会默认赋值undefined; 并且第一行代码赋值的代码还没有执行完,因此这里a的值就是undefined。
小结:全局作用域其实是个名为window的对象,所有的全局变量和全局函数都是window对象的成员。
5. 全局函数fun里面的作用域链Scopes都有什么呢?

image.png
我们看到作用域链Scopes是个对象,里面目前只有只有全局Global属性,因为没有调用fun,所以,目前只有全局的作用域
6. 执行fun,看看发生了什么?

Video_2022-02-23_143834.gif

image.png
执行fun时,多了个Local(本地)局部作用域,这就是fun自身的作用域,可以看到也是一个对象结构,里面有自己的局部变量和this属性,同理变量声明提前,该赋值代码还没有执行完,因此,值默认是undefined;里面的this属性值是全局作用域->window。

image.png
展开this值,里面有全局变量a和全局函数fun,这里全局变量a的值已经有了。
7. 执行完fun发生了什么?fun的local本地作用域消失了

Video_2022-02-23_160435.gif
大家可以看到,在程序一步步执行的时候, Local里面的a属性值从undefined变成了100,再a++后又变成了101,这都是正常执行编程的结果。最后一步,Local消失了?这是因为函数作用域对象其实就是个活动的对象,简称AO,为什么这样说呢?因为,当声明一个小写fun时,其实是做了一次new Function(),就是创建了一个临时函数,调用此临时函数时,创建了一个函数作用域对象,保存了局部变量,按照程序一系列猛操作下来,最后,此临时函数执行完毕,该函数作用域对象和附带自身的局部变量会立即释放消失。一切会恢复如初,后面再声明一个fun, 就会又重新创建一个临时函数,执行完函数作用域对象跟局部变量也会立刻释放
小结:函数作用域对象其实就是个活动的对象,简称AO(Actived Object),所以局部变量不可重用。
以上可证明:
总结作用域(全局作用域和函数局部作用域)和作用域链是个对象结构

调用函数三部曲

想了解调用一个函数这个过程都发生了什么?往下看哦
相当于我们平时做菜,类似做菜三部曲

  1. 备料
  2. 炒菜(按照菜谱步骤做菜)
  3. 清洗锅具,收拾厨房,保证干净整洁
    映射到函数调用上:
  4. 创建临时的函数作用域对象,保存局部变量(备料)
  5. js中引擎按照程序一步步执行(炒菜)
  6. 程序中js引擎调用完函数后,自动释放临时的函数作用域对象和局部变量(清理)
    总结:函数调用过程=做菜三部曲=>备料,做菜,清理
    完结。。。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值