JavaScript之变量作用域与声明提前

本文深入探讨了JavaScript中变量作用域的概念,包括局部变量与全局变量的区别、变量声明提前的现象及原因、作为属性的变量以及作用域链的工作原理。

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

在函数体内部,局部变量优先级别高于同名的全局变量。如果函数外部和内部均有没有使用关键字var声明的同名变量,那么这个变量将被修改为函数内部的那个变量。

a = "Tom";

function curr() {
    a = "Bob";
    return a;
}

var b = curr();//调用函数curr
console.log(a); //Bob
console.log(b); //Bob 


当函数内部的变量未使用var声明时,就相当于声明了一个全局变量,那么这样的话,函数内部的变量a就覆盖了函数外部的变量a,因为最后的结果:变量a的值为“Bob”,变量b的值为“Bob”。


若此时,把代码稍微修改一下:

a = "Tom";

function curr() {
    a = "Bob";
    return a;
}

console.log(a); //Tom

var b = curr();//调用函数curr
console.log(a); //Bob
console.log(b); //Bob 

可以发现,在函数curr没有执行之前,变量a的值还是"Tom",执行之后,a的值为"Bob"。



变量作用域


JavaScript的函数作用域是指:在函数内部声明的变量函数体中是随处可见的。意味着,在函数体中变量未声明之前就可用,这就是JavaScript的特性“声明提前”,这个提前是“这是声明”的提前,而不是“这是赋值”的提前,也就是说,在执行函数体的代码之前,已经将“变量声明”这一步骤提前到了函数体顶部,而并未赋值。

var a = "Tom";
function curr() {
    console.log(a); //undefined
    var a = "Bob";
    console.log(a); //Bob
} 

curr();

在函数体的第一行中,输出的是"undefined",而不是认为的“Tom”,因为此时已经将变量a的声明"var a;"提前在了函数体顶部,但并未赋值,所以输出的是"undefined",此时的a表示的是函数内部的变量a。前面说过:在函数内部,局部变量的优先级别高于全局变量。


以上代码被引擎解析为:

var a = "Tom";
function curr() {
    var a;
    console.log(a); //undefined
    a = "Bob";
    console.log(a); //Bob
} 

curr();

这样,是否好理解一些。


注:从以上可以看出,在以后的编程中,尽量将函数内部中要用到的变量的声明放在函数体的顶部,这样就能更好地反映真实的变量作用域。




作为属性的变量


在JavaScript中,在全局作用域下声明的变量是作为全局对象的属性的。当使用关键字var声明的变量是不可使用delete操作符删除的,而未使用var直接赋值的变量是可以通过delete操作符删除的。


var a = 123; //这是不可删除的变量

b = 234; //这是可以删除的变量

this.a1 = "hello"; //也是可以删除的变量

delete a;
console.log(a); //123

delete b;
console.log(b); //报错 b未声明

delete a1;
console.log(a1); //报错


函数内部声明的局部变量是作为 跟函数调用时相关的对象的 属性,称为“声明上下文对象”,也称“调用对象”。

在JavaScript中,允许this对象引用全局变量,却没有办法引用局部变量。




作用域链

我们知道,全局变量在程序中始终有定义的,局部变量在声明它的函数体中或嵌套在声明它的函数中的函数内始终有定义的。

如果将局部变量看作是自定义实现的对象的 属性 的话,那么更加容易理解变量作用域。JavaScript中的每一段代码(全局代码或函数),都有一个与之相关的“作用域链”,这个作用域链是对象列表或链列表,这组对象定义了这段代码“作用域链”中的变量。JavaScipt需要查找变量x的时候,就会先查找作用域链上的第一个对象是否有这个属性(变量x),如果有则使用这个变量,如果没有,则继续查找下一个对象看是否有这个变量,如果也没有,则继续查找下一个对象,依次类推,逐级向上查找,直至查找到全局作用对象为止。如果最后这个作用域链中的所有对象都没有这个属性(变量x)的话,程序会抛出一个引用错误。


在JavaScript的最顶层代码中(也就是不包含在 任何定义函数的代码,全局环境中),作用域链由一个全局对象组成。而在一个没有嵌套函数的函数体中,它的作用域链上有两个对象:第一个对象定义函数参数和局部变量,第二个对象是全局对象。而在一个嵌套的函数体内,作用域链上至少有三个对象:本身函数的变量对象、外部函数的变量对象、全局变量对象。

当定义一个函数时,它保存着一个作用域链,当调用这个函数时,它将新创建一个对象用来保存局部变量,并将这个对象保存在那个作用域链上,同时新创建一个表示 函数调用作用域的“链”。对于嵌套函数来说,每次调用外部函数时,作用域链也不同,内部函数都会重新定义一遍,因为每次调用外部函数,虽然内部函数的代码一样,但关联这代码的作用域链不同。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值