JavaScript - 函数提升



函数提升

JavaScript 中的函数提升是一种默认行为,其中函数声明在执行代码之前移动到其本地范围的顶部。因此,您可以在声明函数之前在其范围内调用该函数。请务必注意,仅提升声明,而不提升初始化。因此,变量或函数在使用之前应该已经初始化。

与函数 hoisting 类似,变量 hoisting 也是一种默认行为,其中变量声明将移动到其局部范围的顶部。我们可以在声明函数之前使用它。

让我们考虑以下 JavaScript 代码。


add(5,10); // 15
function add(x, y){
	 	return x + y;
}

在上面的 JavaScript 代码中,函数 add 在声明之前被调用。这是可能的,因为 JavaScript 解释器将函数声明提升到范围的顶部。所以上面的代码相当于 –


function add(x, y){
	 	return x + y;
}
add(5,10); // 15

函数提升仅适用于函数声明,不适用于函数表达式。因此,如果函数是使用函数表达式 .. 定义的,则不会将其提升到顶部。


add(5,10); // ReferenceError: Cannot access 'add' before initialization
const add = function (x, y){
	 	return x + y;
}

让我们编写一些完整的函数提升 JavaScript 示例。

示例:函数提升

在下面的示例中,我们定义了 printMessage() 函数,打印调用它的位置。

此外,我们在函数定义之前和之后调用 printMessage() 函数。它打印输出时没有任何错误,因为函数被提升到其范围的顶部。


<html>
<body>
	 	<p id = "output"> </p>
	 	<script>
	 	 	 printMessage("Top"); 	 	 	 	
	 	 	 function printMessage(pos) {
	 	 	 	 	document.getElementById("output").innerHTML +=	
	 	 	 	 	"The function is called from the " + pos + "<br/>";
	 	 	 } 	 	 	 	
	 	 	 printMessage("Bottom");
	 	</script>
</body>
</html>

输出

The function is called from the Top
The function is called from the Bottom

在下面的示例中,我们在 'if' 块内定义了函数。因此,该函数被提升到 'if' 块的顶部,并且你只能在初始化之前在 'if' 块内执行该函数。

你不能在 'if' 块之外访问该函数。


<html>
<body>
	 	<p id = "output"> </p>
	 	<script>
	 	 	 // test("Top"); // Out of scope
	 	 	 if (1) {
	 	 	 	 	test("Top"); // In the same scope
	 	 	 	 	function test(pos) {
	 	 	 	 	 	 document.getElementById("output").innerHTML +=	
	 	 	 	 	 	 "The function is called from the " + pos + "<br/>";
	 	 	 	 	}
	 	 	 	 	test("Bottom"); // In the same scope
	 	 	 }
	 	</script>
</body>
</html>

输出

The function is called from the Top
The function is called from the Bottom

在 JavaScript 中,提升是非常重要的行为。但始终建议在代码的开头声明函数或变量。由于 JavaScript 总是按照声明、初始化和使用的顺序来解释代码。

JavaScript 变量提升

默认情况下,JavaScript 的提升行为将 variables 声明移动到变量范围的顶部。在 JavaScript 中,使用 'var' 关键字声明的变量被提升到其范围的顶部,但使用 'let' 和 'const' 关键字声明的变量不会被提升到其顶部。

例如


var x = y;
var y;

上面的代码类似于下面的代码,因为 variables 声明被提升到顶部。


var y;
var x = y;

让我们通过以下示例来了解变量提升。

示例:变量提升

在下面的示例中,我们初始化了变量 y,在输出中打印了它的值,并在最后声明了它。下面的代码打印一个值,没有任何错误,因为变量 y 被提升到全局范围的顶部。


<html>
<head>
	 	<title> JavaScript - Variable Hoisting </title>
</head>
<body>
	 	<p id = "output"> </p>
	 	<script>
	 	 	 y = 10;
	 	 	 document.getElementById("output").innerHTML =	
		 	 	"The value of the y is : " + y;
	 	 	 var y;
	 	</script>
</body>
</html>

输出

The value of the y is : 10

示例:带函数的变量提升

在下面的示例中,我们定义了 printNum() 函数。在 printNum() 函数中,我们初始化了变量 y,打印了它的值,然后声明了它。

变量 y 被提升到函数的顶部,因此你可以在其声明之前访问它,但不能在函数外部访问它。


<html>
<head>
	 	<title> JavaScript - Variable Hoisting with function </title>
</head>
<body>
	 	<p id = "output"> </p>
	 	<script>
	 	 	 const output = document.getElementById("output");
	 	 	 function printNum() {
	 	 	 	 	y = 20;
	 	 	 	 	output.innerHTML += "The value of the variable y is : " + y;
	 	 	 	 	var y; // Function scope
	 	 	 }
	 	 	 printNum();
	 	 	 // Variable Y can't be accessible here
	 	</script>
</body>
</html>

输出

The value of the variable y is : 20

但是,变量初始化不会提升到块的顶部。

示例:未提升变量初始化

下面的示例演示了变量在顶部提升,但变量初始化不是。在这里,我们打印变量 x 而不对其进行初始化。因此,它会在输出中打印 'undefined'。


<html>
<body>
	 	<p id = "output"> </p>
	 	<script>
	 	 	 var x;
	 	 	 document.getElementById("output").innerHTML = "x is -> " + x;
	 	 	 x = 10;
	 	</script>
</body>
</html>

输出

x is -> undefined

示例:使用 let 和 const 关键字进行提升

下面的示例演示了使用 'let' 和 'const' 关键字声明的变量没有提升到顶部。因此,您始终需要在使用它之前对其进行定义。

我们使用了 'try...catch“ 块来处理错误。在输出中,用户可以观察到当我们访问使用 'let' 关键字声明的变量时,下面的代码给出的错误。


<html>
<head>
	 	<title> Hoisting with let and const </title>
</head>
<body>
	 	<p id = "output"> </p>
	 	<script>
	 	 	 const output = document.getElementById("output");
	 	 	 try {
	 	 	 	 	x = 10;
	 	 	 	 	output.innerHTML += "The value of x is -> " + x;
	 	 	 	 	let x;
	 	 	 }catch (error) {
	 	 	 	 	output.innerHTML += error.message;
	 	 	 }
	 	</script>
</body>
</html>

输出

Cannot access 'x' before initialization