news 2026/5/26 6:56:02

一篇文章了解 JavaScript 开发中函数与变量的优先级

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
一篇文章了解 JavaScript 开发中函数与变量的优先级

函数与变量的优先级:搞懂这3个核心场景,再也不踩坑

在 JavaScript 开发中,我们经常会遇到这样的困惑:当函数和变量同名时,到底谁会被优先访问?为什么有时候打印的是函数,有时候却是变量值?其实这背后藏着 JS 引擎的执行机制——变量提升与函数提升的优先级规则。

今天这篇文章,就从「提升机制的本质」出发,通过 3 个核心场景的代码案例,帮你彻底搞懂函数与变量的优先级逻辑,从此避开这类基础却致命的 bugs。

一、先理清:变量提升 vs 函数提升

在聊优先级之前,我们必须先明确两个基础概念:变量提升(Hoisting)和函数提升。这是 JS 引擎在执行代码前的「预编译」阶段会做的核心操作。

简单来说:

  • 变量提升:var 声明的变量会被提升到当前作用域顶部,但仅提升声明,不提升赋值(值为 undefined);let/const 声明的变量也会提升,但存在「暂时性死区」,不能在声明前访问。
  • 函数提升:函数声明(function 关键字声明)会被完整提升到当前作用域顶部,包括函数体;而函数表达式(如 var fn = function(){})不会提升函数体,仅提升变量声明(同 var 变量)。

而函数与变量的优先级,核心就体现在「提升阶段的竞争」——谁在提升后更“靠前”,谁就会被优先访问。

二、3 个核心场景,吃透优先级规则

场景 1:函数声明 vs var 变量(同名)

先看一段经典代码:

console.log(a); // 输出:function a() {} var a = 10; function a() {} console.log(a); // 输出:10

为什么第一次打印的是函数,而不是 undefined 或 10?这就是优先级规则在起作用:函数声明的提升优先级高于 var 变量声明

拆解 JS 引擎的预编译和执行过程:

  1. 预编译阶段:先提升函数声明 function a() {},再提升 var a(但由于 a 已经被函数声明占用,var a 的提升会被忽略,不会重复声明)。此时作用域顶部的 a 是函数 a() {}。
  2. 执行阶段:第一行 console.log(a),访问的是提升后的函数 a,所以输出函数体。
  3. 执行 var a = 10; 时,是对已存在的 a 进行赋值,将函数覆盖为 10。
  4. 第二行 console.log(a),此时 a 已经是 10,所以输出 10。

注意:这里是「变量声明」被忽略,不是「赋值」被忽略。如果变量声明后有赋值操作,依然会覆盖函数。

场景 2:函数声明 vs let/const 变量(同名)

如果把 var 换成 let/const,情况会完全不同:

console.log(a); // 报错:Cannot access 'a' before initialization let a = 10; function a() {}

为什么会报错?因为 let/const 存在「暂时性死区(TDZ)」:

虽然 let/const 变量也会提升,但提升后会被置于暂时性死区中,在声明语句(let a = 10)执行前,任何访问都会报错。此时即使有同名的函数声明,也无法突破暂时性死区——let/const 的暂时性死区优先级高于函数提升

补充:如果函数声明在 let 声明之后,同样会报错,因为同名的 let 变量提升后占据了标识符,函数声明无法重复定义:

let a = 10; function a() {} // 报错:Identifier 'a' has already been declared

场景 3:函数表达式 vs 变量(同名)

函数表达式(如 var fn = function(){})本质上是「变量声明 + 函数赋值」,所以它的提升规则和 var 变量完全一致,优先级自然也和 var 变量相同(不存在函数声明的高优先级)。

看代码案例:

console.log(b); // 输出:undefined var b = function() { console.log('函数表达式'); }; var b = 20; console.log(b); // 输出:20

拆解过程:

  1. 预编译阶段:提升两个 var b 声明,由于重复声明,仅保留一个,此时 b 的值为 undefined。
  2. 执行阶段:第一行 console.log(b),输出 undefined。
  3. 执行 var b = function(){},将 b 赋值为函数。
  4. 执行 var b = 20,将 b 赋值为 20,覆盖函数。
  5. 第二行 console.log(b),输出 20。

这里要注意:函数表达式的函数体不会被提升,所以第一次打印的是 undefined,而不是函数——这是和函数声明的核心区别。

三、总结:优先级核心规则(表格梳理)

为了方便记忆,用表格汇总不同场景下的优先级顺序(从高到低):

场景优先级顺序核心结论
函数声明 vs var 变量函数声明 > var 变量声明同名时,预编译后先存在函数,var 声明被忽略,赋值后覆盖函数
函数声明 vs let/const 变量let/const 暂时性死区 > 函数声明同名时,声明前访问报错;声明后函数无法重复定义
函数表达式 vs 变量(任意声明)同变量优先级(无函数提升优势)函数表达式仅提升变量声明,值为 undefined,赋值后覆盖

四、实战避坑建议

理解了优先级规则后,在实际开发中可以通过以下几点避免踩坑:

  1. 避免函数和变量同名:这是最根本的解决办法,尽量让标识符具有唯一性,减少优先级竞争。
  2. 优先使用 let/const 替代 var:let/const 的暂时性死区可以避免“声明前访问”的bug,同时不允许重复声明,让代码更严谨。
  3. 区分函数声明和函数表达式:如果需要函数在声明前被访问,用函数声明;如果需要控制函数的可用时机,用函数表达式(配合 var/let 声明)。
  4. 养成“先声明后使用”的习惯:无论变量还是函数,尽量在作用域顶部声明,避免依赖提升机制,让代码可读性更强。

五、最后案例

console.log(c); var c = 30; function c() { console.log('c1'); } var c = function() { console.log('c2'); }; console.log(c);

核心提示:结合场景 1 和场景 3 的规则,拆解预编译和执行过程。

总结一下:函数与变量的优先级,本质是「提升机制的竞争」。记住“函数声明优于 var 变量声明,let/const 暂时性死区优于函数声明”这两个核心点,再结合具体场景拆解,就能轻松应对所有相关问题。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/26 6:31:51

两两交换链表中的节点

递归解法详解题目要求两两交换链表中的相邻节点,且不能修改节点的值,只能交换节点本身。递归方法通过分解问题为子问题来实现。递归思路 将链表的前两个节点视为node1和node2,交换这两个节点后,node1的下一个节点应指向剩余链表交…

作者头像 李华
网站建设 2026/5/25 21:23:45

Docker极简入门:从零到实战

Docker 极简入门实战大纲 第一章:Docker 初识 痛点引入: 开发与部署环境不一致带来的困扰。 Docker 是什么? 不是虚拟机!轻量级容器技术。 核心概念:镜像(Image)、容器(Container)、仓库(Repository)。 类比:镜像 = 软件包 (.exe/.dmg/.deb) + 运行环境 (JDK/Python等),…

作者头像 李华
网站建设 2026/5/24 15:42:49

Spring Boot 应用开发知识点总结

一、Spring Boot 核心原理:理解「约定优于配置」的本质​ Spring Boot 的核心优势在于简化配置、快速开发,其底层依赖两大核心机制:自动配置与 Starter 依赖,这是掌握框架的根本所在。​ 1. 自动配置(AutoConfigurat…

作者头像 李华
网站建设 2026/5/24 21:05:11

窗口置顶神器:3分钟学会让重要窗口永不消失的终极技巧

窗口置顶神器:3分钟学会让重要窗口永不消失的终极技巧 【免费下载链接】AlwaysOnTop Make a Windows application always run on top 项目地址: https://gitcode.com/gh_mirrors/al/AlwaysOnTop 还在为重要窗口被其他程序遮挡而烦恼吗?窗口置顶工…

作者头像 李华
网站建设 2026/5/25 7:35:35

Day 16 C++提高之模板

Day 16 C提高之模板 一、模板的概念 模板就是建立通用的模具,大大提高复用性。例如,生活中的模板:一寸照片的模板、PPT模板、论文模板。 模板特点:通用性很强,但是不能直接使用,只是一个框架,模…

作者头像 李华
网站建设 2026/5/26 5:15:55

蓝桥杯 162.通电(Prim算法)

2015 年,全中国实现了户户通电。作为一名电力建设者,小明正在帮助一带一路上的国家通电。这一次,小明要帮助 nn 个村庄通电,其中 1 号村庄正好可以建立一个发电站,所发的电足够所有村庄使用。现在,这 nn 个…

作者头像 李华