函数声明的提升和变量声明的提升

本文深入解析JavaScript中不同类型的函数(声明式、赋值型、匿名、自执行)的执行顺序及预编译过程,帮助理解变量提升、函数覆盖等概念。

函数的执行顺序(声明式函数、赋值型函数、匿名函数、自执行函数)

声明式函数和赋值型函数的区别在于:在js的预编译期间,声明式函数会被提前提取出来,然后才会按照顺序执行JS代码

	//函数声明
    a();//a
	function a() {
		console.log("a");
	}
    //函数赋值
	b();//Uncaught TypeError: b is not a function
	var b = function() {
		console.log("b");
	}
    
    // 匿名函数
    function() {} 

	// 函数使用IIFE自执行
	(function () {
		console.log("C") //C
	})()

JS的解析分为两个阶段:预编译 和 执行期

· 预编译期间:对当前js文件中的所有 声明变量 和 函数进行处理,但是需要注意:1 ,此时处理的只是声明式函数,2,变量也只是进行了声明但是没有进行初始化和赋值。

接下来,我们结合上面分析的来进行示例

    f();//输出函数声明2
	function f(){
		console.log("输出函数声明1")
	}
	function f(){
		console.log("输出函数声明2")
	}

结论1 :都是函数声明的情况下,后面的函数会层叠前面的函数

 

    f();//输出函数声明
	function f() {
		console.log("输出函数声明")
	}
	var f = function() {
		console.log("输出函数表达式")
	}

结论2:声明函数提前于赋值函数(函数表达式)

 

console.log(a);// undefined
var a;
console.log(b);//Uncaught ReferenceError: b is not defined

结论3:变量声明处于预编译阶段。证明了我们上面的所说的都是对的

 

<script>
  f();
</script>
<script>
  function f(){};
</script>

结论4:js引擎是按照代码块的顺序来执行的。对于还没有加载的代码,是没有办法进行处理的。这也是编译核心所在

 

console.log(f);  // Function
function f() {
  console.log(1);
}
var f = 3;

结论5:函数声明提升优先级大于变量的声明,会优先把标识符给函数使用

 

<script>
  console.log(a);
</script>
<script>
  console.log(3);
</script>

结论6:代码块之间如果报错,其他的模块如果正确依旧可以正确执行

 总结和整理

JS的执行顺序如下:

  • 1.读入第一个代码块
  • 2.做语法分析,有错则报语法错误,并跳转到 5
  • 3.对var变量和function做 预编译(永远不会报错,因为只解析正确的)
  • 4.执行代码块,有错则报错
  • 5.如果还有下一个代码块,则读入下一个代码端,重复 2
  • 6.结束

ES之前,JS没有变量作用域。只有 函数作用域 和 全局作用域。

{ var a = 3; } 
console.log(a); // 3

使用了ES6的let之后,{ }内即为一个变量作用域

{
  let a = 3;
}
console.log(a); // error

 

 

 

实战!

代码一:

f();
var scope = 'out';
function f() {
  console.log(scope);
  var scope = 'in';
  console.log(scope);
}
  • 变量覆盖,后面定义声明的会覆盖前面的。
  • 函数内部:先进行变量声明。

实际运行过程:

var scope = 'out';
function f() {
  var scope;    // 覆盖了外部的。
  console.log(scope);
  scope = 'in';
  console.log(scope);
}
f();

代码二:

var getName = function(){
  console.log(2);
}
function getName (){
  console.log(1);
}
getName();

这题看懂了前面的话很容易:

  • 函数声明被放在了预编译阶段。
  • 后来的会覆盖前面的。
    实际运行过程
function getName (){
  console.log(1);
}
var getName = function(){
  console.log(2);
}
getName();  // 2

代码三:

getName();     // 1
function getName() {
  console.log(1);
}
var getName = function() {
  console.log(2);
}

依旧很容易,不解释。变量赋值来得太慢,不像龙卷风。

<think> 首先,用户的问题是关于JavaScript中函数声明提升变量声明提升的优先级。我需要基于提供的站内引用来回答这个问题。 关键引用总结: - 引用[1]:提到函数声明变量声明提升时有着显著的差异,并强调函数提升优先级更高。 - 引用[2]:总结结论:函数提升优先级比变量提升要高,且不会被变量声明覆盖,但会被变量赋值覆盖。 - 引用[3]:解释优先级:函数提升优先级高于变量函数提升后不会被变量声明覆盖,但会被赋值覆盖。 - 引用[4]:提到函数提升只针对具名函数,匿名函数赋值不会提升。 - 引用[5]:再次确认函数声明提升优先级高于变量声明提升。 核心点:函数声明提升的优先级高于变量声明提升。 在回答中,我需要: - 使用系统级指令:所有行内数学表达式用$...$,独立公式用$$...$$。但这里没有数学表达式,所以可能不需要。 - 使用中文回答。 - 结构清晰,逐步解释。 - 在回答末尾自然地添加引用标识。 - 生成相关问题作为结尾。 回答结构: 1. **介绍提升机制**:简要解释什么是提升(hoisting)。 2. **解释优先级**:详细说明函数声明提升优先级高于变量声明提升。 3. **举例说明**:使用代码示例来演示优先级的体现。 4. **对比不同声明方式**:提到var、let、const的差异,但引用主要讨论var函数声明。 5. **总结结论**:基于引用的结论。 6. **添加引用**:在适当位置添加引用标识。 7. **生成相关问题**:在末尾添加几个相关问题。 生成的相关问题: - 类似于示例,问题要基于主题。 - 例如: 1. 如何避免提升机制带来的问题? 2. letconst在提升中有何不同? 3. 函数表达式函数声明提升区别是什么? 引用标识: - 在解释结论时,自然地添加引用标识,如[^2]、[^3]等。 确保回答可靠: - 基于引用,说明函数提升优先级高于变量提升。 - 引用[2]说函数提升不会被变量声明覆盖,但会被变量赋值覆盖。 - 引用[3][^5]也支持这一点。 完整回答: - 开头:直接回答问题。 - 主体:逐步解释。 - 结尾:相关问题。 代码示例: - 引用中的代码可以简化使用。 例如: ```javascript console.log(a); // function a() {} function a() {} var a = 1; console.log(a); // 1 ``` 过程解释: - 提升后:函数声明优先,变量声明不覆盖函数,但赋值会覆盖。 最终输出: - 使用中文,清晰分段。 </think> ### JavaScript中函数声明提升变量声明提升的优先级 在JavaScript中,提升(hoisting)是一种机制,引擎在执行代码前会将声明变量声明函数声明)移动到作用域顶部。基于提供的引用内容,以下是函数声明提升变量声明提升优先级的详细解释: 1. **优先级规则** - **函数声明提升优先级高于变量声明提升**:当函数声明变量声明同名时,函数声明会优先被提升到作用域顶部。这意味着函数声明会覆盖同名的变量声明,但不会被变量声明覆盖(变量声明只是声明,而非赋值)。 - **变量赋值会覆盖函数声明**:如果变量声明后被赋值,赋值操作会覆盖之前的函数声明,因为函数声明提升后,变量赋值发生在代码执行阶段。 - 这一规则的核心原因是:JavaScript引擎将函数视为“第一公民”,函数声明在编译阶段就被完整提升,而变量声明提升声明部分(值为`undefined`),赋值留在原地[^2][^3][^5]。 2. **代码示例演示** 考虑以下代码: ```javascript console.log(a); // 输出:function a() {} function a() { console.log('Hello'); } var a = 1; console.log(a); // 输出:1 ``` - **提升后的等效代码**: ```javascript // 函数声明优先提升 function a() { console.log('Hello'); } // 变量声明提升(但未赋值) var a; // 此时 a 已被函数声明覆盖 console.log(a); // 输出函数 a,因为变量声明未赋值 a = 1; // 变量赋值覆盖函数声明 console.log(a); // 输出 1 ``` - **过程分析**: - 函数声明 `function a() {}` 优先提升到顶部,定义函数。 - 变量声明 `var a;` 提升,但未赋值(值为`undefined`),不覆盖函数。 - 第一次 `console.log(a)` 输出函数体(因为函数覆盖变量)。 - 赋值 `a = 1` 执行后,函数被覆盖。 - 第二次 `console.log(a)` 输出数字 `1`[^3][^5]。 3. **关键注意事项** - **仅限具名函数声明**:提升只适用于 `function` 关键字声明的具名函数(如 `function foo() {}`)。匿名函数赋值(如 `var b = function() {}`)不会提升函数体,只提升变量声明部分[^4]。 - **var vs. let/const**:`var` 函数声明提升,但 `let` `const` 也有提升(称为“暂时性死区”),因为它们未初始化前不能访问,优先级行为与 `var` 不同(引用未覆盖此点,需额外注意)[^1]。 - **避免混淆**:同名函数变量声明时,函数声明总是“赢”在提升阶段,但赋值操作能改变最终值[^2][^3]。 4. **结论** JavaScript中函数声明提升的优先级高于变量声明提升,但变量赋值可以覆盖函数声明。理解这一点有助于避免意外错误,例如在代码中过早访问变量。在实际开发中,推荐使用 `let` `const` 替代 `var`,并避免同名声明以减少提升相关的问题[^1][^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值