加深理解Javascript的作用域和作用域链

本文深入解析JavaScript中的作用域与作用域链概念,包括预解析、函数作用域、全局作用域、局部作用域及作用域链的规则,帮助初学者理解变量在不同作用域中的行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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 ’

以上就是我对Javascript的 作用域 和 作用域链 的理解,如有不同的见解或者不对的地方,可以一起交流!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值