跟着 MDN 学JavaScript day_19:函数返回值
引言
在前面两篇文章中,我们学习了函数的基本概念,并亲手创建了自定义函数。但到目前为止,我们创建的函数主要是在执行一些操作,比如在页面上显示消息框,而并没有将任何处理结果反馈给调用者。在实际编程中,很多函数的作用不仅仅是执行某个动作,更重要的是完成某种计算并将结果传递回来,供后续代码使用。这种函数执行完毕后回传的结果就是返回值。
一、什么是返回值
返回值这个词非常直白,它指的就是函数执行完毕后返回的那个值。虽然你可能没有刻意思考过这个概念,但在之前的学习中你已经无数次接触过返回值了。每当你在代码中调用一个函数,并将它的结果赋值给一个变量,或者直接使用它的结果进行其他操作时,你就在使用返回值。
1.1 熟悉的例子
const myText = "天气很冷";
const newString = myText.replace("冷", "热");
console.log(newString); // 输出 "天气很热"
在这段代码中,myText.replace("冷", "热") 这个函数调用执行后,返回了一个新字符串 "天气很热"。这个返回值被赋值给了 newString 变量。如果���们不把返回值存起来,这个新字符串就会丢失,因为它只是临时产生的一个值。
在MDN文档中查阅任何一个函数的说明页面,你都会找到一个名为"返回值"的专门章节。文档编写者深知理解返回值对于正确使用函数至关重要,养成查阅文档中返回值说明的习惯,能让你少走很多弯路。
二、有返回值与无返回值的函数
并不是所有函数都有有意义的返回值。在我们的参考文档中,有些函数的返回值被标记为空值 void 或未定义值 undefined,这意味着这个函数执行完毕后不会回传任何有用的数据。
// 无返回值的函数:只执行操作(副作用),不返回数据
function displayMessage(msgText, msgType) {
const html = document.querySelector("html");
const panel = document.createElement("div");
panel.setAttribute("class", "msgBox");
html.appendChild(panel);
const msg = document.createElement("p");
msg.textContent = msgText;
panel.appendChild(msg);
const closeBtn = document.createElement("button");
closeBtn.textContent = "x";
panel.appendChild(closeBtn);
closeBtn.onclick = function () {
panel.parentNode.removeChild(panel);
};
// 没有 return 语句 → 默认返回 undefined
}
// 有返回值的函数:计算并返回结果
function squared(num) {
return num * num;
}
| 类型 | 特征 | 示例 |
|---|---|---|
| 无返回值函数 | 执行副作用操作,没有 return 语句或返回 undefined |
displayMessage() |
| 有返回值函数 | 通过 return 回传计算结果 |
squared(num) |
有返回值的函数通常被用作计算的中间步骤。一个函数处理完数据后返回结果,这个结果可以作为另一个函数的输入,形成处理管道。这种链式处理数据的方式是函数式编程思想的体现。
三、使用return关键字
要从自定义函数中返回值,你需要使用 return 关键字。return 语句有两个作用:
| 作用 | 说明 |
|---|---|
| 指定返回值 | return 后面的表达式的值就是函数的返回值 |
| 终止函数执行 | 一旦执行到 return,函数立即停止运行,之后的代码不会被执行 |
3.1 基本示例
我们之前见过的一个实际例子来自 random-canvas-circles.html:
function randomNumber(number) {
return Math.floor(Math.random() * number);
}
这个函数接收一个整数参数 number,函数体只有一行 return 语句:
Math.random()生成一个[0, 1)的随机小数- 乘以
number后得到[0, number)的随机小数 Math.floor()向下取整,得到[0, number-1]的随机整数- 最终结果通过
return返回给调用者
3.2 两种写法对比
// 写法一:直接在 return 中计算(更简洁)
function randomNumber(number) {
return Math.floor(Math.random() * number);
}
// 写法二:先计算再返回(更易读,适合复杂逻辑)
function randomNumber(number) {
const result = Math.floor(Math.random() * number);
return result;
}
两种写法功能完全相同。当计算逻辑比较复杂时,先计算再返回可能让代码更容易理解。
3.3 "函数调用被返回值替换"的思维模型
理解这种思维模型非常重要。比如在 draw 函数中调用了三次 random:
ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI);
假设这三次 random 调用分别返回了 500、200 和 35,那么这行代码实际执行时就等价于:
ctx.arc(500, 200, 35, 0, 2 * Math.PI);
执行流程:
random(WIDTH) → 计算 → 返回 500 → 替换调用位置
random(HEIGHT) → 计算 → 返回 200 → 替换调用位置
random(50) → 计算 → 返回 35 → 替换调用位置
→ ctx.arc(500, 200, 35, 0, 2 * Math.PI) → 执行
JavaScript引擎会先执行函数调用,获取返回值,然后用返回值替换掉函数调用的位置,最后再执行外层语句。
四、主动实践:构建带返回值的函数库
理论知识讲再多也不如亲手写一遍。让我们构建一个简单的函数库,包含几个数学计算函数,每个函数都接收参数并返回计算结果。
4.1 三个计算函数
function squared(num) {
return num * num;
}
function cubed(num) {
return num * num * num;
}
function factorial(num) {
var x = num;
while (x > 1) {
num *= x - 1;
x--;
}
return num;
}
| 函数 | 功能 | 示例调用 | 返回值 |
|---|---|---|---|
squared(5) |
计算平方 | 5 * 5 |
25 |
cubed(5) |
计算立方 | 5 * 5 * 5 |
125 |
factorial(5) |
计算阶乘 | 5 × 4 × 3 × 2 × 1 |
120 |
factorial 函数的实现使用了 while 循环来累乘:
// 以 factorial(5) 为例,执行流程:
// 初始:num=5, x=5
// 第1次循环:num=5×(5-1)=20, x=4
// 第2次循环:num=20×(4-1)=60, x=3
// 第3次循环:num=60×(3-1)=120, x=2
// 第4次循环:num=120×(2-1)=120, x=1
// x>1 为 false,循环终止
// return 120
4.2 事件监听与输入处理
为了让这些函数真正工作起来,需要监听输入框的变化事件:
input.addEventListener("change", () => {
const num = parseFloat(input.value);
if (isNaN(num)) {
para.textContent = "You need to enter a number!";
} else {
para.textContent = `${num} squared is ${squared(num)}. `;
para.textContent += `${num} cubed is ${cubed(num)}. `;
para.textContent += `${num} factorial is ${factorial(num)}. `;
}
});
事件处理流程:
用户输入 → "change"事件触发
↓
parseFloat(input.value) 将字符串转为浮点数
↓
isNaN(num)?
├─ true → 显示错误提示 "You need to enter a number!"
└─ false → 依次调用三个函数,用返回值拼接输出字符串
| 关键函数 | 作用 |
|---|---|
parseFloat() |
将字符串解析为浮点数,无法解析时返回 NaN |
isNaN() |
检测一个值是否为 NaN,是则返回 true |
这个输入验证很重要——如果用户在输入框中输入了字母或其他非数字内容,parseFloat 会返回 NaN,而用 NaN 进行数学运算会导致所有结果都变成 NaN,产生无意义的输出。
这里可以看到返回值的实际运用:每个函数调用都返回一个数值,这些数值直接在字符串模板中被拼接显示。如果没有返回值机制,我们需要在每个函数内部直接操作DOM来显示结果,代码会变得混乱且难以复用。
五、函数库的思维与错误处理
5.1 函数库的概念
当你能熟练编写自己的函数后,自然会产生构建个人函数库的想法。函数库就是一组相关函数的集合,可以保存在一个单独的JavaScript文件中,在需要的时候引入使用。
math-utils.js
├── squared(num) // 计算平方
├── cubed(num) // 计算立方
├── factorial(num) // 计算阶乘
├── isPrime(num) // 判断质数
└── gcd(a, b) // 计算最大公约数
5.2 防御性编程
在编写函数时,养成良好的错误处理习惯非常重要:
// 带防御性检查的平方函数
function squared(num) {
if (num === undefined || num === null) {
console.warn("squared() 缺少参数");
return 0; // 返回合理的默认值
}
return num * num;
}
| 原则 | 说明 |
|---|---|
| 验证必要参数 | 缺少关键参数时给出提示或返回默认值 |
| 提供参数默认值 | 可选参数使用 param = defaultValue |
| 清晰的函数命名 | 如 squared 准确传达"计算平方"的含义 |
六、总结
函数返回值是JavaScript函数体系中最后一个基础概念,但它绝不是最不重要的。有了返回值,函数就不再只是执行操作的孤立代码块,而是变成了可以串联组合的数据处理单元。
核心要点回顾
| 知识点 | 核心内容 |
|---|---|
| 返回值定义 | 函数执行完毕后回传给调用者的值 |
return 关键字 |
指定返回值 + 终止函数执行 |
| 无返回值函数 | 执行副作用操作,默认返回 undefined |
| 替换思维模型 | 函数调用被返回值替换,再执行外层语句 |
| 链式处理 | 一个函数的返回值作为另一个函数的输入 |
| 错误处理 | 验证参数、提供默认值、防御性编程 |
完整代码回顾
// ====== 函数定义 ======
function squared(num) {
return num * num;
}
function cubed(num) {
return num * num * num;
}
function factorial(num) {
var x = num;
while (x > 1) {
num *= x - 1;
x--;
}
return num;
}
// ====== 事件绑定 ======
input.addEventListener("change", () => {
const num = parseFloat(input.value);
if (isNaN(num)) {
para.textContent = "You need to enter a number!";
} else {
para.textContent = `${num} squared is ${squared(num)}. `;
para.textContent += `${num} cubed is ${cubed(num)}. `;
para.textContent += `${num} factorial is ${factorial(num)}. `;
}
});
如果本文中有任何概念让你感到困惑,不要犹豫,重新阅读相关章节或者动手在浏览器控制台中试验代码。编程学习最好的方式就是亲手实践。在后续的学习中,你还会接触到更高级的函数概念,比如将函数作为参数传递给另一个函数的回调函数模式,以及能够返回函数的函数。这些进阶内容都建立在扎实的基础概念之上,现在打好基础,未来的学习就会水到渠成。
更多推荐

所有评论(0)