点击勘误issues (opens new window),哪吒感谢大家的阅读

在JavaScript中另一个基本概念是函数, 它允许你在一个代码块中存储一段用于处理单任务的代码,然后在任何你需要的时候用一个简短的命令来调用,而不是把相同的代码写很多次。 在本文中,我们将探索函数的基本概念,如基本语法、如何定义和调用、范围和参数。

# 我能在哪找到函数?

在 JavaScript中, 你将发现函数无处不在 。事实上, 到目前为止,我们一直在使用函数,只是我们还没很好的讨论它们。然而现在是时候了,让我们开始聊聊函数,并探索它们的语法。

几乎任何时候,只要你使用一个带有一对圆括号()的JavaScript结构,并且你不是在使用一个常见的比如for for循环,while或do…while循环,或者if语句这样的内置语言结构时,那么您就正在使用函数。

# 浏览器内置函数

当我们操作一个字符串的时候,例如:

var myText = 'I am a string';
var newString = myText.replace('string', 'sausage');
console.log(newString);
// the replace() string function takes a string,
// replaces one substring with another, and returns
// a new string with the replacement made
1
2
3
4
5
6

或者当我们操作一个数组的时候:

var myArray = ['I', 'love', 'chocolate', 'frogs'];
var madeAString = myArray.join(' ');
console.log(madeAString);
// the join() function takes an array, joins
// all the array items together into a single
// string, and returns this new string
1
2
3
4
5
6

或者当我们生成一个随机数时:

var myNumber = Math.random()
// the random() function generates a random
// number between 0 and 1, and returns that
// number
1
2
3
4

JavaScript有许多内置的函数,可以让您做很多有用的事情,而无需自己编写所有的代码。事实上, 许多你调用(运行或者执行的专业词语)浏览器内置函数时调用的代码并不是使用JavaScript来编写——大多数调用浏览器后台的函数的代码,是使用像C++这样更低级的系统语言编写的,而不是像JavaScript这样的web编程语言。

请记住,这些内置浏览器函数不是核心JavaScript语言的一部分——被定义为浏览器API的一部分,它建立在默认语言之上,以提供更多的功能(请参阅本课程的早期部分以获得更多的描述)。我们将在以后的模块中更详细地使用浏览器API。

# 函数与方法

程序员把函数称为对象方法(method)的一部分。你还不必了解JavaScript中已建构的对象在更深层次上是如何运作的——你可以等到下一小节,我们会教给你有关对象运作方式的一切。在我们继续前进之前,我们需要澄清一些有关方法和函数概念之间可能存在的误会——当你在网络上浏览相关信息的时候,你很可能会碰上这两个术语。

到目前为止我们所使用的内置代码同属于这两种形式:函数和方法。你可以在这里查看内置函数,内置对象以及其相关方法的完整列表。

严格说来,内置浏览器函数并不是函数——它们是方法。这听起来有点可怕和令人困惑,但不要担心 ——函数和方法在很大程度上是可互换的,至少在我们的学习阶段是这样的。

二者区别在于方法是在对象内定义的函数。浏览器内置函数(方法)和变量(称为属性)存储在结构化对象内,以使代码更加高效,易于处理。

# 自定义函数

您在过去的课程中还看到很多定制功能 - 在代码中定义的功能,而不是在浏览器中。每当您看到一个自定义名称后面都带有括号,那么您使用的是自定义函数.

自定义函数:draw()

function draw() {
  ctx.clearRect(0,0,WIDTH,HEIGHT);
  for (var i = 0; i < 100; i++) {
    ctx.beginPath();
    ctx.fillStyle = 'rgba(255,0,0,0.5)';
    ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI);
    ctx.fill();
  }
}
1
2
3
4
5
6
7
8
9

该函数在<canvas>元素中绘制100个随机圆。每次我们想要这样做,我们可以使用这个函数来调用这个功能

draw();
1

而不是每次我们想重复一遍,都要写出所有的代码。函数可以包含任何您喜欢的代码 - 甚至可以从内部函数调用其他函数。以上函数例如调用random()函数三次,由以下代码定义:

function random(number) {
  return Math.floor(Math.random()*number);
}
1
2
3

我们需要这个函数,因为浏览器的内置Math.random()函数只生成一个0到1之间的随机十进制数。我们想要一个0到一个指定数字之间的随机整数。

# 调用函数

现在你可能很清楚这一点,但仅仅为了防止……,要在函数定义之后,实际使用它,你必须运行或调用它。这是通过将函数名包含在代码的某个地方,后跟圆括号来完成的。

function myFunction() {
  alert('hello');
}

myFunction()
// calls the function once
1
2
3
4
5
6

# 匿名函数

到目前为止,我们刚刚创建了如下函数:

function myFunction() {
  alert('hello');
}
1
2
3

但是您也可以创建一个没有名称的函数:

function() {
  alert('hello');
}
1
2
3

这个函数叫做匿名函数 — 它没有函数名! 它也不会自己做任何事情。 你通常将匿名函数与事件处理程序一起使用, 例如,如果单击相关按钮,以下操作将在函数内运行代码:

var myButton = document.querySelector('button');

myButton.onclick = function() {
  alert('hello');
}
1
2
3
4
5

上述示例将要求<button> 在页面上提供可用于选择并单击的元素。 您在整个课程中已经看到过这种结构了几次,您将在下一篇文章中了解更多信息并在其中使用。

你还可以将匿名函数分配为变量的值,例如:

var myGreeting = function() {
  alert('hello');
}
1
2
3

现在可以使用以下方式调用此函数:

myGreeting();
1

有效地给变量一个名字;还可以将该函数分配为多个变量的值,例如:

var anotherGreeting = function() {
  alert('hello');
}
1
2
3

现在可以使用以下任一方法调用此函数

myGreeting();
anotherGreeting();
1
2

但这只会令人费解,所以不要这样做!创建方法时,最好坚持下列形式:

function myGreeting() {
  alert('hello');
}
1
2
3

您将主要使用匿名函数来运行负载的代码以响应事件触发(如点击按钮) - 使用事件处理程序。 再次,这看起来像这样:

myButton.onclick = function() {
  alert('hello');
  // I can put as much code
  // inside here as I want
}
1
2
3
4
5

TIP

匿名函数也称为函数表达式。函数表达式与函数声明有一些区别。 函数声明会进行声明提升(declaration hoisting),而函数表达式不会。

# 函数参数

一些函数需要在调用它们时指定参数 ——这些参数值需要放在函数括号内,才能正确地完成其工作。

TIP

Note: 参数有时称为参数(arguments),属性(properties)或甚至属性(attributes)

例如,浏览器的内置Math.random()函数不需要任何参数。当被调用时,它总是返回0到1之间的随机数:

var myNumber = Math.random();
1

浏览器的内置字符串replace()函数需要两个参数:在主字符串中查找的子字符串,以及用以下替换该字符串的子字符串:

var myText = 'I am a string';
var newString = myText.replace('string', 'sausage');
1
2

TIP

Note:当您需要指定多个参数时,它们以逗号分隔。

还应该注意,有时参数不是必须的 —— 您不必指定它们。如果没有,该功能一般会采用某种默认行为。作为示例,数组 join()函数的参数是可选的:

var myArray = ['I', 'love', 'chocolate', 'frogs'];
var madeAString = myArray.join(' ');
// returns 'I love chocolate frogs'
var madeAString = myArray.join();
// returns 'I,love,chocolate,frogs'
1
2
3
4
5

如果没有包含参数来指定加入/分隔符,默认情况下会使用逗号

# 函数作用域和冲突

我们来谈一谈 scope即作用域 — 处理函数时一个非常重要的概念。当你创建一个函数时,函数内定义的变量和其他东西都在它们自己的单独的范围内, 意味着它们被锁在自己独立的隔间中, 不能被函数外的代码访问。

所有函数的最外层被称为全局作用域。 在全局作用域内定义的值可以在任意地方访问。

JavaScript由于各种原因而建立,但主要是由于安全性和组织性。有时您不希望变量可以在代码中的任何地方访问 - 您从其他地方调用的外部脚本可能会开始搞乱您的代码并导致问题,因为它们恰好与代码的其他部分使用了相同的变量名称,造成冲突。这可能是恶意的,或者是偶然的。

例如,假设您有一个HTML文件,它调用两个外部JavaScript文件,并且它们都有一个使用相同名称定义的变量和函数:

<!-- Excerpt from my HTML -->
<script src="first.js"></script>
<script src="second.js"></script>
<script>
  greeting();
</script>
1
2
3
4
5
6
// first.js
let name = 'Chris';
function greeting() {
  alert('Hello ' + name + ': welcome to our company.');
}
1
2
3
4
5
// second.js
let name = 'Zaptec';
function greeting() {
  alert('Our company is called ' + name + '.');
}
1
2
3
4
5

这两个函数都使用 greeting() 形式调用,但是你只能访问到 first.js 文件的greeting()函数(第二个文件被忽视了)。另外,第二次尝试使用 let 关键字定义 name 变量导致了一个错误。

上次更新: 1/19/2022, 3:07:00 AM