当前位置: 首页 > news >正文

【js】JavaScript的变量提升、函数声明提升

一、变量提升

变量提升(Hoisting)是 JavaScript 中的一个特性,它指的是:

在代码执行前,变量的声明(不是赋值)会被“提升”到当前作用域的顶部。


🌟 举个例子:

console.log(x); // 输出:undefined
var x = 10;

你可能觉得这段代码会报错,但实际上它不会。

这是因为 JavaScript 在“执行前”会自动把 var x 提到代码的最上面,相当于这样:

var x;          // 声明被提升了
console.log(x); // 这里访问的是 x,但还没赋值,结果是 undefined
x = 10;         // 赋值发生在这一行

❗注意几点:

  1. 只有声明被提升,赋值不会提升!

    console.log(a); // undefined,而不是 5
    var a = 5;
    
  2. 函数声明也会被提升,但函数表达式不会

    greet(); // OK,输出 Hello
    function greet() {console.log("Hello");
    }greet2(); // ❌ 报错:greet2 is not a function
    var greet2 = function () {console.log("Hi");
    };
    
  3. letconst 也会被“提升”,但不会初始化,访问会报错(TDZ)

    console.log(b); // ❌ ReferenceError: Cannot access 'b' before initialization
    let b = 20;
    

    这叫做“暂时性死区(TDZ,Temporal Dead Zone)”。


✅ 建议写法:

  • 避免使用 var,使用 letconst

  • 把变量声明放在使用之前,代码更清晰,逻辑更直观。

这是一个非常好的问题,触及了 JavaScript 的历史、兼容性以及开发习惯演变。我们来深入、清晰地解答这个问题:


🌍 为什么 var 仍然存在?

1. 历史兼容性(向后兼容)

  • varJavaScript 最初就有的变量声明方式,存在于 ES5(2009年)及更早的版本。

  • letconstES6(2015年) 才引入的新特性。

  • 如果完全废弃 var,会导致 大量旧代码无法运行,这对于浏览器厂商和开发者都是灾难性的。

➡️ 所以 var 仍被支持,是为兼容旧代码。


📌 使用 var 有哪些坑?

特性varlet / const
作用域函数作用域块级作用域
变量提升有(声明提升 + 初始化为 undefined)有声明提升但存在 TDZ(初始化前不能访问)
允许重复声明✅ 是❌ 不允许
推荐程度🚫 不推荐✅ 推荐

示例:

if (true) {var x = 10;
}
console.log(x); // ✅ 输出 10,x 逃出了 if 块if (true) {let y = 20;
}
console.log(y); // ❌ ReferenceError

✅ 总结:你该怎么做?

  • 新项目中,强烈推荐只用 letconst

    • 默认用 const,只有需要修改变量值时再用 let

  • 除非你明确在维护旧代码,或有特殊兼容性需求,否则应该避免使用 var

  • 在团队开发中可使用 ESLint 等工具强制禁止使用 var

 


二、函数声明提升

“函数声明提升(function hoisting)”是 JavaScript 的特有行为,它并不普遍存在于其他大多数编程语言中,尤其是静态类型语言(如 Java、C++、Python)中。


✅ 回顾一下 JavaScript 中的函数提升:

在 JavaScript 中,如果使用 函数声明function 关键字直接定义),整个函数(包括函数体)都会被提升到作用域顶部,你可以在声明之前调用它:

sayHi(); // ✅ 输出 "Hi"function sayHi() {console.log("Hi");
}

但如果使用 函数表达式,即把函数赋值给变量,那么只有变量声明被提升,函数体不会被提升

sayHello(); // ❌ 报错:sayHello is not a functionvar sayHello = function() {console.log("Hello");
};

❓其它语言是否有函数提升?

🔸 Python:

没有函数提升,函数必须在使用之前定义:

say_hello()  # ❌ NameError: name 'say_hello' is not defineddef say_hello():print("Hello")

🔸 C / C++:

函数定义前必须有 函数声明(prototype),否则编译不通过:

int add(int, int); // 函数声明int main() {int result = add(2, 3); // OK
}int add(int a, int b) { // 函数定义return a + b;
}

🔸 Java:

类方法要写在类中,没有提升,编译器需要先知道方法的签名。


💡 为什么 JavaScript 这么设计?

JavaScript 是一种解释型语言,设计之初为了方便开发者快速书写脚本,提供了“先用后声明”的容忍机制。解释器在执行之前会做一个“预扫描”(预处理阶段),把变量和函数的声明提取出来,这就造成了所谓的“提升”现象。


🔚 总结:

特性JavaScriptPythonC/C++Java
变量提升var 有,let/const 没有
函数提升✅ 函数声明提升❌(需声明)

http://www.dtcms.com/a/192561.html

相关文章:

  • 知识图谱系列(2):知识图谱的技术架构与组成要素
  • 【补充笔记】修复“NameError: name ‘ZhNormalizer‘ is not defined”的直接方法
  • Kafka如何实现高性能
  • Unity碰撞检测:射线与胶囊体投射/Layer(层)、LayerMask(遮罩层)
  • Unity3D开发AI桌面精灵/宠物系列 【六】 人物模型 语音口型同步 LipSync 、梅尔频谱MFCC技术、支持中英文自定义编辑- 基于 C# 语言开发
  • Linux云计算训练营笔记day08(MySQL数据库)
  • 【上位机——WPF】Window标签常用属性
  • 【学习心得】2025年Docker Desktop安装记录
  • 阿里云ECS部署Dify
  • 阿里云CMH镜像迁移与SMC整机迁移对比及功能详解(同地域跨主体账号场景)
  • 配置VScodePython环境Python was not found;
  • 「Java EE开发指南」如何使用MyEclipse的可视化JSF编辑器设计JSP?(二)
  • PC:使用WinSCP密钥文件连接sftp服务器
  • ANTsPy:医学影像处理python库
  • Java集合详解:LinkedBlockingQueue
  • 26考研 | 王道 | 计算机组成原理 | 一、计算机系统概述
  • Window下Jmeter多机压测方法
  • 128.在 Vue 3 中使用 OpenLayers 实现绘制矩形截图并保存地图区域
  • OpenShift AI - 用 ModelCar 构建容器化模型,提升模型弹性扩展速度
  • IP地址、端口、TCP介绍、socket介绍、程序中socket管理
  • Golang 设计哲学
  • 用Python代码绘制动态3D爱心效果
  • AI日报 · 2025年5月15日|GPT-4.1 登陆 ChatGPT
  • 实验-时序电路设计2-存储器阵列(数字逻辑)
  • 光谱相机的图像预处理技术
  • MYSQL基本命令
  • 70、微服务保姆教程(十三)Docker容器详细讲义
  • 人体肢体渲染-一步几个脚印从头设计数字生命——仙盟创梦IDE
  • 工业操作系统核心技术揭秘
  • Web GIS可视化地图框架Leaflet、OpenLayers、Mapbox、Cesium、ArcGis for JavaScript