JS中的作用域和作用域链对新手来说一直都是一个难点,为了增加大家对作用域和作用域链的认知,我在这儿讲解一下我对作用域的理解。
在我们了解函数作用域之前,先让我们来看一段代码吧!
var num = 10
function fn() {
console.log(num)
}
fn()
肯定会有不少小伙伴以为console.log(num)输出的结果是 10,但这是错的,正确的结果是 undefined
那为什么会这样呢?
道理很简单,这关系到预解析,让我们先来了解一下什么叫预解析
一、预解析
预解析就是 在当前作用域中,JavaScript代码执行之前,浏览器首先会默认的把所有带var和function声明的变量进行提前的声明或者定义。
简单来说,就是在JS代码执行之前,把所有带有var和function开头的先拿出来一一进行声明,但需要我们注意的是:
(1) 在预解析时,var只是声明变量名,不赋值
(2) 而function函数则是在声明函数名之后,给函数名赋值函数
现在让我们一起来看看上面那个案例:
var num = 10 //预解析,对var num变量进行声明,但不赋值
function fn() { //预解析,对function fn(){console.log(num)}函数变量名声明,并赋值函数
console.log(num)
}
fn()//执行函数,因为变量num只声明,未赋值,所以获取结果是undefined
现在看来,这题目是不是就变得很简单了呢?
那么接下来,就来到了我们的重点,函数作用域
二、函数作用域
作用域
作用,就是生效,能够使用的; 域,指的就是范围。 顾名思义,作用域就是指在范围内能够使用或者生效的东西
那么会是什么在范围内生效的呢?答案就是:变量
函数作用域其实指的就是一个变量可以生效的范围,而函数作用域又分为两种,分别是全局作用域和局部作用域
1、全局作用域
全局作用域比较好掌握,主要就是在 最外层函数 和 最外层函数外面定义的变量拥有全局作用域
var str1 = '我是最外层变量'
function fn() { //我是最外层函数
var str2 = '我是内层函数'
}
fn()
2、局部作用域
局部作用域就是在函数里面的,局部作用域只能产生在函数里面,每一个函数有且只有一个局部作用域
function internal() {
//这是一个局部作用域的空间,以下内容都属于局部作用域里面的内容
var str = '123'
var num = 123
var bol = true
}
internal()
三、作用域链
讲作用域链前先让我们看段代码
var c = 1
function fn() {
var b = 2
var c = 3
console.log(c)//自由变量
}
fn()
在案例中,函数内部打印 c 的变量在函数并没有定义,这就是函数的自由变量。
那么变量 c 的值怎么得到呢?答案就是向上一级一级的作用域里面查找
作用域链
通过一级一级的向上面的作用域查找,如果父级的作用域里面没有,那就继续向父级的父级的作用域查找,直到查找到全局的作用域。这整
一个过程,就叫做作用域链
而作用域链主要表现在三个规则,大家只要记住这三个规则,就能更好的掌握作用域链
1、函数的变量定义
var a = 100
function fn() {
var b = 200 //fn 局部作用域里面的变量
console.log(a) //自己函数内部没有定义,向父级作用域查找变量,所以得到结果是 100
function fun() {
var c = 300 //fun 局部作用里面的变量
console.log(b) //自己函数内部没有定义,向父级作用域查找变量,所以得到结果是 200
}
fun()
}
fn()
console.log(b) //不能够向下的作用域查找变量,所以结果是 报错
从上个案例中我们能够得知,当你在定义一个变量的时候,只有定义变量的该作用域以及后代作用域才可以使用这个变量,向上的父级或者是祖先级都不能够使用这个变量
2、函数的变量赋值
var a = 100 // 全局 a 变量
function fn() {
a = '后来赋值操作' //局部作用域没有定义变量 a , 则向上查找,直到全局作用域
console.log(a) // 结果 后来赋值操作
}
fn() // 因为 fn 函数的执行, 给全局变量 a 从新进行了赋值操作
console.log(a)// 结果 后来赋值操作
从上个案例我们不难看出,当你要给一个变量赋值的时候,先要在自己作用域内部查找,如果有,就给自己作用域内部的值赋值,如果没有,就向上一级一级的查找,直到全局作用域,如果全局作用域有这个变量,那就直接赋值;如果没有,那就先让这个变量称为全局变量,再进行赋值。
3、函数的变量使用
var a = 100
function fn() {
var a = 'fn 里面的'
var d = 200
function fun() {
var a = 'fun 里面的 a 变量'
var b = 'fun 里面的'
var c = 300
console.log(d) // 得到的是 fn 作用域里面的 b 变量的值
}
fun()
}
fn()
函数的变量使用和函数的变量定义类似,如果在自己的作用域里面有,那就拿自己作用域里面的值,如果没有,那就一级一级的向上走,哪个作用域里面有,那就从哪个作用域里面拿这个值,如果知道全局作用域都没有这个值,那就报错,返回 ’ 变量 is not defined ’