这是我参与更文挑战的第9天,活动详情查看: 更文挑战
前言
作用域和作用域链在前端里是比较简单的概念,但往往因为简单而被人忽视,涉及到作用域链产生的bug很容易让人摸不着头脑。其实再简单的知识点也有复杂的地方,就像再复杂的概念也有易于理解的点一样。今天大冰块从 作用域 , 变量范围 , 作用域链 这三个方面好好谈一谈JavaScript的作用域及作用域链,希望各位同学看完之后能有所收获。
作用域
概念:变量声明后,能够在哪个范围内起作用。
块级作用域
块级作用域: 由花括号组成代码结构的范围 {}
,在花括号里面声明的变量在外部无法访问。
其实JavaScript是不支持块级作用域的,那么为什么大冰块还要说一下这个呢?多了解一点总是没坏处的,比如面试的时候,别人没说这个,但是你把这个点一提,是不是水平立马就提升了?(手动滑稽)
if(true){
var num = 100
}
console.log(num) // 100 js可以获取到{}内声明的变量
for(var i = 0; i < 10; i++){
var str = "能访问到我吗"
}
console.log(str) // 能访问到我吗 js可以获取到{}内声明的变量
词法作用域
词法作用域: 也叫函数作用域,因为在js里面,只有函数才能形成作用域。也叫静态作用域,因为它的作用域是指在词法分析阶段就确定了,不会改变。动态作用域是在运行时根据程序的流程信息来动态确定的,而不是在写代码时进行静态确定的。而词法作用域是在写代码或者定义时确定的,而动态作用域是在运行时确定的(this也是!)。词法作用域关注函数在何处声明,而动态作用域关注函数从何处调用。
function fn(){
var num = 100
}
console.log(num) // num is not defined
变量范围
根据作用域把变量分为3类
全局变量
在函数外部声明的变量就是全局变量,在任意位置都能够访问到
var num = 100
function fn(){
console.log(num) // 100
}
console.log(num) // 100
局部变量
在函数内部声明的变量就是局部变量,只能在函数内部使用。
function fn(){
var num = 100
}
console.log(num) // num is not defined
自由变量
对于一个函数来说,如果这个变量不是在这个函数内部声明的,但是却使用了这个变量,对于这个函数来说,这个变量就是自由变量
var a = 100
function fn(){
var b = 200
console.log(a) // 100,对fn函数来说,a是自由变量
console.log(b) // 200
}
fn()
作用域和变量的关系
函数的作用域在函数定义的时候就已经确定下来了,函数定义的时候就已经确定下来了,函数定义的时候就已经确定下来了,重要事情说三遍。也就是说,函数作用域和函数在哪调用是没有关系的,以及函数如何被调用都是没有关系的。和this不同,this是在函数被调用的时候才确定,函数是如何被调用的。 函数作用域的查找是如何查找到呢?
1. 如果变量是在函数内部声明的,直接在当前作用域内就查找到了
2. 如果变量是自由变量,去创建这个函数的作用域中去查找
好了,说了这么多,出一道题考考你,请看下面的题目:
var num = 123
function f1() {
console.log(num)
}
function f2(){
var num = 456
f1()
}
f2() // 这里会打印啥?
各位同学,请把你的答案贴在评论区。
作用域链
作用域链:函数能够形成作用域,如果函数被嵌套在另一个函数中,嵌套的函数也有自己的作用域,从这个函数的作用域往外形成的一条链, 这个链叫做作用域链。例如:
function outer(){
function inner(){
function fn(){
}
}
}
上面代码中: 函数outer的作用域链: outer作用域 ==> 全局作用域 函数inner的作用域链: inner作用域 ==> outer作用域 ==> 全局作用域 fn的作用域链: fn作用域 ==> inner作用域 ==> outer作用域 ==> 全局作用域
作用域链: 变量搜索规则:
1. 首先在当前作用域内查找是否有声明该变量,如果有,直接返回。
2. 如果没有,向上一级作用域查找,,如果有,直接返回。
3. 如果没有,沿着作用域链进行查找,直到全局作用域,如果有,直接返回。
4. 如果一直找到最后还是没有,就会报错not defined
5. 在哪一层找到了该变量的声明,直接返回结果,就不继续查找。
好了,下面再出一道题考考大家:
var num = 1000
function outer(){
var num = 999
function inner(){
var num = 888
function fn(){
var num = 777
console.log(num)
}
fn()
}
inner()
}
outer()
各位同学,请把再次把你的答案贴在评论区。
后记
在平时写代码的过程中,如果作用域和作用域链如果理解的不透彻,很容易产生bug。相信通过大冰块从作用域,变量范围,作用域链这几个方面的详细解读,你一定对作用域和作用域链有了更透彻的理解。如果本篇文章由帮助到你,希望能点赞支持一下,不枉我熬夜淦完这篇文章。如果有错误也欢迎指出交流。感谢阅读~
PS: 今天是参加掘金更文挑战的第9天啦,没有存稿的我,今天也是拼着熬夜更了这篇文章,一起加油吧~
更文挑战的文章目录如下:
- 2021.06.01 《多图预警!详细谈谈Flex布局的容器元素和项目元素的属性~》
- 2021.06.02 《如何把css渐变背景玩出花样来》
- 2021.06.03 《如何使用SVG制作沿任意路径排布的文字效果》
- 2021.06.04 《3大类15小类前端代码规范,让团队代码统一规范起来!》
- 2021.06.05 《团队管理之git提交规范:大家竟然都不会写commit记录?| 周末学习》
- 2021.06.06 《如何控制css鼠标样式以及扩大鼠标点击区域 | 周末学习》
- 2021.06.07 《 纯css实现:仿掘金账户密码登录时,小熊猫捂眼动作切换的小彩蛋》
- 2021.06.08 《 从11个方面详细谈谈原型和原型链》