JavaScript - 函数提升:初学者指南

你好,未来的JavaScript魔法师们!今天,我们将深入探讨JavaScript一个非常有趣的特点,这个特点经常让新手们措手不及:函数提升。别担心,如果听起来有点神秘——在本课结束时,你将能够像专业人士一样提升函数!

JavaScript - Function Hoisting

函数提升是什么?

在我们深入了解细节之前,让我们从一个简单的定义开始:

函数提升是JavaScript中的一种行为,其中函数声明会被移动到其作用域的顶部,在代码执行之前。

现在,我知道你们在想什么:“但是老师,这究竟是什么意思?”让我们通过一些例子来分解它,好吗?

示例 1:神奇出现的函数

sayHello(); // 这可以工作!

function sayHello() {
console.log("Hello, world!");
}

如果你是编程新手,你现在可能正在挠头。“我们怎么能在定义之前调用函数?”你问。好吧,我亲爱的学生们,这就是函数提升的魔力!

在这个例子中,JavaScript将整个sayHello函数提升到其作用域的顶部。所以,幕后,代码就像是这样编写的:

function sayHello() {
console.log("Hello, world!");
}

sayHello(); // 现在更有意义了,对吧?

示例 2:两个函数的故事

让我们再来一个例子,让事情更有趣:

greeting("John"); // 输出:"Hello, John!"
farewell("John"); // 错误:farewell不是一个函数

function greeting(name) {
console.log("Hello, " + name + "!");
}

var farewell = function(name) {
console.log("Goodbye, " + name + "!");
};

在这个两个函数的故事中,我们看到不同的行为。greeting函数在调用其声明之前可以正常工作,多亏了提升。但可怜的farewell抛出了错误。为什么?因为只有变量声明var farewell被提升,而不是函数赋值。

函数提升的规则

现在我们已经看到了函数提升的实际应用,让我们制定一些基本规则:

  1. 函数声明被完全提升。
  2. 变量声明被提升,但它们的赋值不被提升。
  3. 函数表达式(当你将函数赋值给变量时)不被提升。

让我们通过更多例子来探索这些规则!

示例 3:声明与表达式

// 这可以工作
hello();

function hello() {
console.log("Hello from a function declaration!");
}

// 这不可以工作
goodbye(); // 错误:goodbye不是一个函数

var goodbye = function() {
console.log("Goodbye from a function expression!");
};

在这里,hello是一个函数声明,所以它被完全提升。但goodbye是一个函数表达式,所以只有var goodbye部分被提升,函数本身没有被提升。

JavaScript 变量提升

现在我们已经涵盖了函数提升,让我们快速了解一下变量提升。这是一个相关的重要概念。

示例 4:神秘的未定义

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

在这个例子中,x的声明被提升,但它的赋值没有被提升。所以第一个console.log输出undefined,而第二个输出已赋值。

示例 5:Let 和 Const - 新来的孩子

console.log(a); // 错误:在初始化之前无法访问'a'
let a = 10;

console.log(b); // 错误:在初始化之前无法访问'b'
const b = 20;

随着ES6中letconst的引入,我们得到了新的行为。这些声明被提升,但它们没有被初始化。这创建了一个“暂时死区”,在这个区域内,你不能在声明之前访问变量。

实际影响和最佳实践

现在我们理解了提升是如何工作的,这对我们开发者意味着什么?

  1. 始终在作用域的顶部声明你的变量。 这使你的代码更清晰,并防止了意外的行为。

  2. 对于你想要在代码中使用的函数,使用函数声明。 它们的提升行为可以是有益的。

  3. 对函数表达式要谨慎。 记住,它们不像函数声明那样被提升。

  4. 当有疑问时,一起声明和初始化。 这消除了关于变量值的任何模糊性。

  5. 考虑使用letconst代替var 它们提供了更可预测的作用域行为。

下面是一个总结不同声明的提升行为的表格:

声明类型 提升了? 初始化了?
函数声明
var undefined
let 否(TDZ)
const 否(TDZ)
函数表达式

结论

就这样,我正在成长的程序员们!我们已经解开了JavaScript中函数提升的神秘面纱。记住,理解这些概念不仅仅是为了知道规则——这是关于编写更干净、更可预测的代码。

在你继续你的JavaScript之旅时,你将遇到许多更多迷人的(有时是令人困惑的)特性。但是不要气馁!每次你学到新东西,你离成为JavaScript忍者就更近一步。

继续练习,继续编码,最重要的是,继续提问。毕竟,唯一愚蠢的问题是那个你没有问的问题!

下次见,快乐编码!

Credits: Image by storyset