网页开发入门|16 函数

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

网页开发入门|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>
按钮监听自定义函数
按钮监听自定义函数

这个函数被调用的时候,浏览器将依次弹出两个提示窗口,分别为helloworld。其中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)
求3+7的值
求3+7的值

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

复制过程
复制过程

如果需要把第三个常量也加进去。

const num3 = 2
const sum_ = sum + num3
alert(sum_)
求3、7、2三个数的和
求3、7、2三个数的和

因为常量的值无法修改,于是每进行一步计算都要定义一个新的常量,这也实在是太不方便了。

于是我们引入一个新的概念,变量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
}

在函数的主体中,定义了变量sumavg分别存储两个参数的和,以及其平均值。为了让外部程序可以获取avg的值,在函数的最后一行,使用了return语句将avg的值进行返回。

于是在函数外部,可以使用如下代码获取mean函数的返回值。

let c = mean(num1, num2)
alert(c)
求1和2的平均数
求1和2的平均数

返回值使得我们无须关心函数内部的变量名,即可使用函数的计算结果。

既然函数内部的变量名不再需要暴露给外部,更进一步,我们希望函数封装的更加严密一些,使得内部的变量名都只在函数内部有效,而不要穿透到函数外部去,“污染”公共空间。

这样的变量(常量)称作局部变量(常量)。在函数内部,使用letconst)定义的变量(常量),都是局部变量(常量)。这个变量(常量)有效的工作范围,也称作作用域或者 闭包

我将本课程所有的代码托管在gitee上了,你可以点击这个链接,或到gitee.com上搜索弦五 网页开发入门,查看和获取本课程的全部代码。