JS里函数内部和外部声明的变量重复问题

博客围绕函数输出undefined而非预期值的问题展开,指出这与作用域有关。函数执行时先在自身函数体查变量,无则逐级向上查找。输出undefined是因变量提升,变量可提前声明但赋值不行,还给出函数原型辅助理解。

今天遇到了这么一个问题

var a=10;
   function fun(){
       console.log(a);//undefined
       var a=20;
       console.log(a);//20
   }
   fun();

有人会有这样的疑惑,为什么第一个输出的是undefined而不是10呢
这又要谈到作用域了。
函数在执行时,会先在自己的函数体里查询变量,如果没有,才会一级一级往上查找。函数fun()在执行时,输出第一个变量a是undefined是因为它现在自己的执行环境里查询到变量a已声明,即变量提升(即变量可以提前声明但是赋值是不可以的),此时就输出了undefined。
以上函数的原型实际是这样的:

  function fun(){
       var a;
       console.log(a);//undefined
       a=20;
       console.log(a);//20
   }
   fun();

这样就很容易理解了。

<think>我们正在讨论变量函数外部内部声明的区别。根据引用,特别是引用[2]引用[3],我们可以知道在JavaScript中,变量声明的位置会影响它的作用域提升行为。同时,引用[4]提供了C语言中全局变量局部变量的区别,虽然语言同,但概念有相似之处。下面我将综合这些信息,用中文回答。 首先,变量声明函数外部时,它成为全局变量,作用域是整个程序(或整个文件)。而声明函数内部时,它是局部变量,作用域仅限于该函数内部。 其次,关于变量提升(hoisting):在JavaScript中,无论变量函数内部何处声明(使用var),都会被视为在函数顶部声明(但赋值会提升)。因此,在函数内部,如果在声明之前使用变量,会得到undefined(因为声明提升但未赋值)。而在函数外部声明的全局变量,在整个脚本中都是可访问的。 另外,在函数内部,如果使用与全局变量同名的变量,则在该函数内部,局部变量会覆盖全局变量(引用[4]也提到重名时局部变量覆盖全局变量)。 在C语言中,全局变量局部变量的区别还包括: - 全局变量在程序整个生命周期存在,而局部变量函数调用时创建,函数结束时销毁。 - 全局变量存储在静态存储区,局部变量存储在栈区。 - 全局变量未初始化时默认为0,局部变量未初始化时其值确定。 在JavaScript中,变量声明函数外部时,它是全局变量,属于全局对象(在浏览器中是window)。而函数内部声明变量(使用var)是函数作用域,使用let或const是块级作用域。 现在,根据用户的问题,我们主要讨论JavaScript中的情况(因为引用[2][3]是JS),但也会提及C语言(引用[4])作为对比。 回答结构: 1. 作用域同 2. 生命周期同 3. 变量提升行为 4. 同名变量处理 5. 内存占用访问速度(引用[4]提到全局变量占用更多内存但访问更快) 具体回答: 在编程中,变量函数外部声明函数内部声明的主要区别在于作用域、生命周期以及访问方式等方面。下面以JavaScript为例,同时对比C语言进行说明。 ### 1. 作用域 - **函数外部声明(全局变量)**:变量在整个脚本中都可以访问,包括所有函数内部(除非被局部变量覆盖)。 例如: ```javascript var globalVar = "global"; // 全局变量 function test() { console.log(globalVar); // 可以访问全局变量 } test(); // 输出 "global" ``` - **函数内部声明(局部变量)**:变量只能在声明它的函数内部访问,函数外部无法访问。 ```javascript function test() { var localVar = "local"; // 局部变量 console.log(localVar); // 输出 "local" } test(); console.log(localVar); // 报错:localVar is not defined ``` ### 2. 生命周期 - **全局变量**:在页面加载时创建,页面关闭时销毁(在C语言中,程序开始执行时创建,程序结束时销毁)。 - **局部变量**:在函数调用时创建,函数执行完毕后销毁(在C语言中,函数调用时创建,函数返回时销毁)。 ### 3. 变量提升(JavaScript特有) 在JavaScript中,使用`var`声明变量会提升到其作用域的顶部。但初始化会提升。 - 在函数内部,即使变量声明函数底部,也会被提升到函数顶部,但在赋值之前访问会得到`undefined`。 ```javascript function hoistingExample() { console.log(a); // 输出 undefined,因为变量a声明提升但未赋值 var a = 10; } ``` 而全局变量提升到脚本顶部。 注意:使用`let``const`声明变量也有提升,但存在暂时性死区(在声明前访问会报错),这展开。 ### 4. 同名变量处理 当全局变量局部变量同名时,在函数内部,局部变量会覆盖全局变量(引用[4]也提到这一点)。 ```javascript var a = "global"; function check() { var a = "local"; // 局部变量a覆盖了全局变量a console.log(a); // 输出 "local" } check(); console.log(a); // 输出 "global" ``` ### 5. 内存性能(C语言中提及,JavaScript类似) - 全局变量生命周期长,占用内存时间也长。而局部变量函数执行完后立即释放。 - 全局变量存储在静态存储区(C语言)或全局对象(JavaScript)中,访问速度可能比局部变量(存储在栈上)慢?但引用[4]提到全局变量因内存需再重新分配,因此运行速度能相对提高。实际上,在JavaScript中,访问全局变量局部变量的性能差异很小,但局部变量通常更有利于内存管理,因为可以及时释放。 ### 注意事项 - 在JavaScript中,避免过多使用全局变量,因为容易引起命名冲突,且利于垃圾回收。 - 在C语言中,全局变量使用大写的命名习惯(引用[4]提到),而JavaScript中通常使用小写或驼峰命名。 ### 总结 变量函数外部声明是全局变量,作用域广,生命周期长;在函数内部声明是局部变量,作用域受限,生命周期短。在JavaScript中,两者都有变量提升,但局部变量会覆盖同名的全局变量。在C语言中,全局变量局部变量也有类似区别。 §§相关问题§§ 1. JavaScript中,使用`let``const`在函数内部声明变量与`var`有何同? 2. 在C语言中,如何扩展全局变量的作用域(使用extern)? 3. 为什么建议避免使用全局变量? 4. 在函数内部,如果使用`var`、`let`或`const`关键字直接赋值变量,会怎样?</think>### 变量函数外部内部声明的区别 在编程中,变量声明位置(函数外部 vs 函数内部)会显著影响其作用域、生命周期行为。以下是核心区别: #### 1. **作用域同** - **函数外部声明(全局变量)** 作用域为整个程序(或文件),所有函数均可访问: ```javascript let globalVar = 10; // 全局变量 function show() { console.log(globalVar); // 可访问 → 输出10 } ``` [^2][^4] - **函数内部声明(局部变量)** 作用域仅限于函数内部外部无法访问: ```javascript function test() { let localVar = 20; // 局部变量 console.log(localVar); // 输出20 } console.log(localVar); // 报错:未定义 ``` [^2][^4] #### 2. **生命周期同** - **全局变量** 在程序启动时创建,程序结束时销毁,占用内存时间长。 - **局部变量** 函数调用时创建,函数结束时销毁,内存立即释放。 [^4] #### 3. **变量提升行为(JavaScript特有)** - **函数内部声明** 使用 `var` 时声明会提升至函数顶部,但赋值提升: ```javascript function example() { console.log(a); // 输出 undefined(变量提升) var a = 5; // 赋值在此生效 } ``` [^2][^3] - **函数外部声明** 全局变量同样会提升,但作用域为全局。 #### 4. **同名变量覆盖** - 当局部变量与全局变量同名时,**局部变量优先**: ```javascript let value = 100; function check() { let value = 200; // 覆盖全局变量 console.log(value); // 输出200 } ``` [^4] #### 5. **内存与性能影响** - 全局变量长期占用内存,但访问速度更快(无需重新分配)。 - 局部变量节省内存,但频繁创建/销毁可能增加开销。 [^4] #### 6. **语言差异示例 - **C语言**:全局变量建议首字母大写(如 `Max`),可用 `extern` 扩展作用域。 - **JavaScript**:省略 `var/let/const` 在函数内赋值会意外创建全局变量(严格模式报错)。 [^4] > **关键总结**: > - 全局变量:跨函数共享数据,但增加耦合风险 > - 局部变量:封装数据,避免命名冲突,推荐优先使用 > - 变量提升覆盖规则是常见错误来源,需特别注意 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值