函数——可复用的代码块
在 JavaScript 中另一个基本概念是 函数 , 它允许你在一个代码块中存储一段用于处理单任务的代码,然后在任何你需要的时候用一个简短的命令来调用,而不是把相同的代码写很多次。在本文中,我们将探索函数的基本概念,如函数的基本语法、如何定义和调用函数、函数的作用域和参数。
基本的电脑知识,对 HTML 与 CSS 有基本的了解,及已阅读: JavaScript 第一步 。 了解 Javascript 函数背后的基本概念。我能在哪找到函数?
在 JavaScript 中,你将发现函数无处不在。事实上,到目前为止,我们一直在使用函数;我们只是还没正式地讨论它们。然而现在是时候了,让我们开始聊聊函数,并探索它们的语法。
几乎任何时候,只要你使用一个带有一对圆括号(
()
)的 JavaScript 结构,并且你
没有
使用比如
for 循环
、
while 或 do...while 循环
,或者
if...else 语句
这样的常见的内置语言结构时,那么你就正在使用函数。
浏览器内置函数
在这套课程中我们已经使用了很多浏览器内置函数。
例如,当我们操作一个字符串的时候:
const myText = "我是一个字符串";
const newString = myText.replace("字符串", "香肠");
console.log(newString);
// replace() 字符串函数接受源字符串和目标字符串,
// 将源字符串替换为目标字符串,并返回新形成的字符串
或者当我们操作一个数组的时候:
jsconst myArray = ["我", "爱", "巧克力", "青蛙"];
const madeAString = myArray.join(" ");
console.log(madeAString);
// join() 函数接受一个数组,
// 将所有数组元素连接成一个单一的字符串,并返回这个新字符串
或者当我们生成一个随机数时:
jsconst myNumber = Math.random();
// random() 函数生成一个随机
// 数字在 0 和 1 之间,并返回该数字
我们都在使用函数!
备注: 如果需要,你可以随意将这些代码输入浏览器控制台以便于你熟悉其功能。
JavaScript 语言中有许多内置的函数,它们可以让你无需自己编写所有的代码,就能做很多有用的事情。事实上,许多你调用(专业词语,意指“运行”或“执行”)浏览器内置函数时调用的代码并不能用 JavaScript 来编写——大多数调用浏览器后台的函数的代码,是使用像 C++ 这样更低级的系统语言编写的,而不是像 JavaScript 这样的 web 编程语言。
请记住,这些内置浏览器函数不是核心 JavaScript 语言的一部分——其中部分函数被定义为浏览器 API 的一部分,它建立在默认语言之上,以提供更多的功能(请参阅本课程的早期部分以获得更多的描述)。我们将在以后的模块中更详细地介绍如何使用浏览器 API。
函数与方法
函数与方法
对象的成员
函数
被称为
方法
。你还不必了解 JavaScript 中已构建的对象在更深层次上是如何运作的——你可以等到下一小节,我们会教给你有关对象运作方式的一切以及如何创建它们。在我们继续之前,我们需要澄清一些有关方法和函数概念之间可能存在的混淆——当你在网络上浏览相关信息的时候,你很可能会碰上这两个术语。
到目前为止我们所使用的内置代码同属于这两种形式:
函数
和
方法
。你可以在
这里
查看内置函数、内置对象以及其相关方法的完整列表。
你在过去的课程中也见到过很多
自定义函数
——在你的代码中而非浏览器中定义的函数。每当你看到一个后面带有括号的自定义名称,那么你使用的是自定义函数。在我们的
循环文章中
的
random-canvas-circles.html
示例(参见完整的
源代码
)中,我们包含一个如下所示的自定义
draw()
函数:
js
function draw() {
ctx.clearRect(0, 0, WIDTH, HEIGHT);
for (let i = 0; i < 100; i++) {
ctx.beginPath();
ctx.fillStyle = "rgb(255 0 0 / 50%)";
ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI);
ctx.fill();
该函数在 <canvas>
元素中绘制 100 个随机大小的圆。每次我们想要这样做,我们只需要调用这个函数:
jsdraw();
而不是每次我们想要这样做,都需要写出所有的代码。函数可以包含任何你喜欢的代码——甚至可以在函数内调用其他函数。以上示例代码调用了 random()
函数三次,该函数由以下代码定义:
jsfunction random(number) {
return Math.floor(Math.random() * number);
我们需要这个函数,因为浏览器的内置 Math.random() 函数只生成一个 0 到 1 之间的随机十进制数。我们想要一个 0 到一个指定数字之间的随机整数。
调用函数
调用函数
你现在可能很清楚这一点,但以防万一,我们还是提醒一下:要在函数定义之后实际使用它,你必须运行(或调用)它。这可以通过在代码的某个地方包含函数名,然后加上圆括号来实现。
js
function myFunction() {
alert("你好");
myFunction();
// 调用一次该函数
备注: 这种创建函数的形式,也被称为函数声明。它总是被提升的,这样你就能在函数定义之前调用该函数。
函数参数
函数参数
有些函数在调用它们时需要指定
参数
——这些值需要放在函数括号内,函数才能正确地完成其工作。
备注:
参数(parameter)有时称为参数(argument)、属性(property)或甚至特性(attribute)。
例如,浏览器的内置
Math.random()
函数不需要任何参数。当被调用时,它总是返回 0 到 1 之间的随机数:
js
const myNumber = Math.random();
浏览器的内置字符串 replace() 函数需要两个参数:在主字符串中查找的子字符串,以及用于替换该字符串的子字符串:
jsconst myText = "我是一个字符串";
const newString = myText.replace("字符串", "香肠");
备注: 当你需要指定多个参数时,它们以逗号分隔。
可选参数
可选参数
还应该注意,有时参数不是必需的——你不必指定它们。如果你没有指定某些参数,该函数一般会采用某种默认行为。例如,数组的
join()
函数的参数是可选的:
js
const myArray = ["我", "爱", "巧克力", "青蛙"];
const madeAString = myArray.join(" ");
console.log(madeAString);
// 返回 '我爱巧克力青蛙'
const madeAnotherString = myArray.join();
console.log(madeAnotherString);
// 返回“我,爱,巧克力,青蛙”
如果没有包含参数来指定连接/分隔符,默认情况下会使用逗号。
默认参数
默认参数
如果你正在编写一个函数,并希望支持可选参数,你可以在参数名称后添加
=
,然后再添加默认值来指定默认值:
js
function hello(name = "克里斯") {
console.log(`你好,${name}!`);
hello("阿里"); // 你好,阿里!
hello(); // 你好,克里斯!
匿名函数和箭头函数
匿名函数和箭头函数
到目前为止,我们创建了如下函数:
js
function myFunction() {
alert("你好");
但是你也可以创建一个没有名称的函数:
js(function () {
alert("你好");
});
这就是所谓的匿名函数,因为它没有名字。当一个函数希望接收另一个函数作为参数时,你经常会看到匿名函数。在这种情况下,函数参数通常作为匿名函数传递。
备注: 这种创建函数的形式也称为函数表达式。与函数声明不同,函数表达式不会被提升。
匿名函数示例
匿名函数示例
例如,你想在用户输入文本框时运行一些代码。为此,你可以调用文本框的
addEventListener()
函数。该函数希望你(至少)传给它两个参数:
要监听的事件名称,本例中为
keydown
事件发生时要运行的函数。
当用户按下某个按键时,浏览器将调用你提供的函数,并传递给它一个包含该事件信息的参数,其中包括用户按下的特定按键:
js
function logKey(event) {
console.log(`You pressed "${event.key}".`);
textBox.addEventListener("keydown", logKey);
你可以将一个匿名函数传入 addEventListener()
,而不是定义一个单独的 logKey()
函数:
jstextBox.addEventListener("keydown", function (event) {
console.log(`You pressed "${event.key}".`);
});
箭头函数
箭头函数
如果你传递这样一个匿名函数,你可以使用另一种形式,即
箭头函数
。你可以用
(event) =>
来代替
function(event)
:
js
textBox.addEventListener("keydown", (event) => {
console.log(`You pressed "${event.key}".`);
});
如果函数只接受一个参数,可以省略参数周围的括号:
jstextBox.addEventListener("keydown", event => {
console.log(`You pressed "${event.key}".`);
});
最后,如果函数只包含一行 return
语句,也可以省略圆括号和 return
关键字,隐式地返回表达式。在下面的示例中,我们使用 Array
的 map()
方法将原始数组中的每个值加倍:
jsconst originals = [1, 2, 3];
const doubled = originals.map(item => item * 2);
console.log(doubled); // [2, 4, 6]
map()
方法依次获取数组中的每一项,并将其传递给给定函数。然后,它将该函数返回的值添加到一个新数组中。
因此,在上面的例子中,箭头函数 item => item * 2
相当于:
jsfunction doubleItem(item) {
return item * 2;
你可以使用同样简洁的语法重写 addEventListener
示例。
jstextBox.addEventListener("keydown", (event) =>
console.log(`You pressed "${event.key}".`),
在这种情况下,回调函数隐式返回 console.log()
的值,即 undefined
。
我们建议你使用箭头函数,因为它们可以使你的代码更简短、更易读。要了解更多信息,请参阅 JavaScript 指南中的有关部分,以及我们有关箭头函数的参考文档。
备注: 注意:箭头函数和普通函数之间存在一些细微差别。它们超出了本入门指南的范围,并且不太可能在我们在这里讨论的案例中产生影响。要了解更多信息,请参阅箭头函数参考文档。
箭头函数实时示例
箭头函数实时示例
下面是我们上面讨论的“keydown”示例的完整工作示例:
HTML 文件:
html
<input id="textBox" type="text" />
<div id="output"></div>
JavaScript 文件:
jsconst textBox = document.querySelector("#textBox");
const output = document.querySelector("#output");
textBox.addEventListener("keydown", (event) => {
output.textContent = `You pressed "${event.key}".`;
});