网页开发入门|16 函数
函数可以看作由若干基本的脚本组成的整体,有特定的效果,并且有一个专属的名字。

通过上节课的学习,我们知道了把脚本代码统一放到<script>
标签里,可以以更加舒服的姿势来写脚本。
但还遗留了一个问题:<script>
标签里的脚本在页面加载时会立刻运行,而不是监听到用户的操作后再运行。
有时候这很有用,比如当我们打开一个网页看视频,会希望视频在页面打开后立刻播放,而不是等用户点击播放按钮后播放。
但是在更多的时候,我们还是希望当监听到用户的操作时,再运行对应的脚本。
本节课,我们就来解决这个问题。
自定义函数
先回顾一下使用on*****
进行监听启用脚本时的代码。
<button onclick="alert('hello')">点我</button>
根据这行代码,用户在点击这个按钮元素时,浏览器将弹出提示窗口。
这里的alert()
就是浏览器提供的功能,在更多时候会称作函数,这是个习惯问题,在英语里都是function。
一个函数可以看作由若干基本的脚本组成的整体,有特定的效果并且有一个专属的名字。除了浏览器定义好的函数,我们也可以自定义一些函数。
自定义的函数需要写在<script>
标签里,基础语法如下:
<script>
function func_name(arg) { do something }
</script>

function
与定义常量时写的const
类似,也是一个关键字,告诉浏览器,这行代码要定义一个函数。
尽管你可以随意的给函数起名字,但最好还是与函数实际要做的事情一致为好,否则过了一段时间之后,可能自己也会忘记定义的函数是做什么用的了。
在括号内列出函数所需要的参数,多个参数可以使用,
隔开。

参数对函数很重要,它是函数运行时要参考的值,也直接影响了函数运行的效果。比如在alert('hello')
中的'hello'
就是alert()
函数的参数,它直接决定了要在页面上弹出的内容是什么。
在定义函数的时候,我们并不知道未来会传入的参数会是什么,于是在定义函数时会使用一个常量来指代参数的值,以方便书写函数功能时使用,这里的常量也称作参数名。
有的书上,称参数名为型参parameter,参数值为实参argument。
最后的代码片段是函数的主体,里面是所定义的函数的功能,里面的代码将会依次运行。
作为例子,这里我们定义了一个名为greet
的函数。
<script>
function greet(name) { alert('hello'); alert(name); }
</script>
这个函数主体中有两句代码,都是alert()
函数。第一个alert()
函数将会要求浏览器弹出一个'hello'
,第二句要求浏览器弹出参数name
所具有的参数值。
接下来,就可以在元素的监听属性中使用这个自定义函数。
<button onclick="greet('world')">点我</button>

这个函数被调用的时候,浏览器将依次弹出两个提示窗口,分别为hello
和world
。其中world
即为name
的参数值。
在一行里写太长的代码不方便阅读,最好将每一句代码放到单独的一行中,例如:
<script>
function greet(name) {
alert('hello');
alert(name);
}
</script>
现在,我们写在<script>
标签中的代码就不会在页面加载时立刻运行了,而是当监听到用户操作时,触发了相应的函数,才会运行函数中的代码。
简便起见,在本课程后面的部分,当我们再写JS
代码时,就省略<script>
标签,直接写内部的代码了。
函数把批量的代码封装在一起,对外给出一个更加清爽的调用方式,实现了复杂功能的“一处定义,多处使用”,增强了代码的可读性和可维护性。
计算与变量
函数还很擅长实现复杂计算。
计算是计算机最基本的能力了,在网页中也会大量使用。比如在渲染页面元素时,需要根据其样式属性计算它们在页面中的(绝对)位置,浏览器才知道如何进行正确的渲染。

再比如在网页中实现购物功能,需要能根据商品单价和数量算出总价。

在JS
中实现计算非常的容易,以下代码实现了对两个常量的求和:
const num1 = 3
const num2 = 7
// 求和
const sum = num1 + num2
// 求差
// const diff = num1 - num2
// 求积
// prod = num1 * num2
// 求商
// quot = num1 / quot
alert(sum)

请切记,这里代码中的=
并不是数学上的等于,而是赋值,即令sum
的值为右侧的计算结果10
。

如果需要把第三个常量也加进去。
const num3 = 2
const sum_ = sum + num3
alert(sum_)

因为常量的值无法修改,于是每进行一步计算都要定义一个新的常量,这也实在是太不方便了。
于是我们引入一个新的概念,变量variable。与常量不同,变量所存储的值是可以被修改的,也就是可以被多次赋值。
初次定义变量,需要使用let
关键字。之后,如果对变量再次赋值(即修改变量值)则不必再写let
let v = 1
alert(v)
v = 3
alert(v)

这样当我们再次实现多个数相加时,只需定义一个变量记录结果即可。
let s = num1 + num2
s = s + num3
alert(s)

再次强调,=
不是数学上的等于,而是赋值,即令s
的值为右边的计算结果。

关键词var也可以用于定义变量,鉴于在较新的JS标准中,已经不再鼓励使用var,此处不再展开说明。
返回值与作用域
变量可以把计算的结果暂存,以便在其它需要的地方使用。
但如果计算的过程发生在函数内部,根据封装的思想,我们不希望在函数之外,还需要了解内部定义的变量名。
为此,函数提供了返回值的能力,即将函数的运算结果以匿名(不起名)的方式对外部提供。在外部可以使用任意的名字,将返回值定义为常量或变量。
例如,定义一个求平均数的函数mean
:
function mean(a, b) {
let sum = a + b
let avg = sum / 2
return avg
}
在函数的主体中,定义了变量sum
和avg
分别存储两个参数的和,以及其平均值。为了让外部程序可以获取avg
的值,在函数的最后一行,使用了return
语句将avg
的值进行返回。
于是在函数外部,可以使用如下代码获取mean
函数的返回值。
let c = mean(num1, num2)
alert(c)

返回值使得我们无须关心函数内部的变量名,即可使用函数的计算结果。
既然函数内部的变量名不再需要暴露给外部,更进一步,我们希望函数封装的更加严密一些,使得内部的变量名都只在函数内部有效,而不要穿透到函数外部去,“污染”公共空间。
这样的变量(常量)称作局部变量(常量)。在函数内部,使用let
(const
)定义的变量(常量),都是局部变量(常量)。这个变量(常量)有效的工作范围,也称作作用域或者 闭包。
我将本课程所有的代码托管在gitee
上了,你可以点击这个链接,或到gitee.com
上搜索弦五 网页开发入门,查看和获取本课程的全部代码。