前言
面试时总是被问到作用域与作用域链, 嘴上说不出来?回答的模棱两可,心里对这些也是模模糊糊?网上的资料说的不够透彻,看了之后依旧模模糊糊?看这里, 让你彻底搞懂作用域与作用域链.
作用域
什么是作用域?
变量的可用范围
为什么要使用作用域?
使变量不被污染(使不同范围内的变量互不干扰)
js包括几级作用域?
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中, 作用域和作用域链都是对象结构
何以见得?往下看->
- 新建名为scopes.html的网页:
var a=10;
function fun(){
var a=100;
a++;
console.log(a);
}
fun();
console.log(a);
- 用浏览器运行,并按F12打开控制台
3. 控制台里点击Sources,点开scopes.html,并打上断点
可以看到Scources里各个断点信息,其中作用域Scope里,只有Global(全局作用域)
4. 我们再点开Global,看一下里面的结构以及有哪些数据?
我们可以看到Global(全局作用域)是个对象结构,也就是个window对象,里面有我们定义的全局变量a和全局fun,有的小伙伴可能会纳闷,这里的a为什么是undefined, 因为程序开始执行时,会先把变量的声明提前,这里的a和fun都会被声明提前,a声明提前,不管有没有值,都会默认赋值undefined; 并且第一行代码赋值的代码还没有执行完,因此这里a的值就是undefined。
小结:全局作用域其实是个名为window的对象,所有的全局变量和全局函数都是window对象的成员。
5. 全局函数fun里面的作用域链Scopes都有什么呢?
我们看到作用域链Scopes是个对象,里面目前只有只有全局Global属性,因为没有调用fun,所以,目前只有全局的作用域
6. 执行fun,看看发生了什么?
执行fun时,多了个Local(本地)局部作用域,这就是fun自身的作用域,可以看到也是一个对象结构,里面有自己的局部变量和this属性,同理变量声明提前,该赋值代码还没有执行完,因此,值默认是undefined;里面的this属性值是全局作用域->window。
展开this值,里面有全局变量a和全局函数fun,这里全局变量a的值已经有了。
7. 执行完fun发生了什么?fun的local本地作用域消失了
大家可以看到,在程序一步步执行的时候, Local里面的a属性值从undefined变成了100,再a++后又变成了101,这都是正常执行编程的结果。最后一步,Local消失了?这是因为函数作用域对象其实就是个活动的对象,简称AO,为什么这样说呢?因为,当声明一个小写fun时,其实是做了一次new Function(),就是创建了一个临时函数,调用此临时函数时,创建了一个函数作用域对象,保存了局部变量,按照程序一系列猛操作下来,最后,此临时函数执行完毕,该函数作用域对象和附带自身的局部变量会立即释放消失。一切会恢复如初,后面再声明一个fun, 就会又重新创建一个临时函数,执行完函数作用域对象跟局部变量也会立刻释放
小结:函数作用域对象其实就是个活动的对象,简称AO(Actived Object),所以局部变量不可重用。
以上可证明:
总结:作用域(全局作用域和函数局部作用域)和作用域链是个对象结构
调用函数三部曲
想了解调用一个函数这个过程都发生了什么?往下看哦
相当于我们平时做菜,类似做菜三部曲
- 备料
- 炒菜(按照菜谱步骤做菜)
- 清洗锅具,收拾厨房,保证干净整洁
映射到函数调用上: - 创建临时的函数作用域对象,保存局部变量(备料)
- js中引擎按照程序一步步执行(炒菜)
- 程序中js引擎调用完函数后,自动释放临时的函数作用域对象和局部变量(清理)
总结:函数调用过程=做菜三部曲=>备料,做菜,清理
完结。。。