入门魔法 - function 函式

前情提要

艾草:「你可以帮我算一下 100 + 100 是多少吗?」

「200 啊...」

艾草:「那在加 6 次 100 呢?」

「...? 你在干嘛呀,啊是不会自己算喔。」

艾草:「啊我就数学烂啊!我在算你的魔力总量多少了啦。」

「没有什麽方便计算的魔法吗?」

艾草:「啊,我想到了啦,那今天来教你函式好了,函式可以包装计算功能用喔。很方便的唷~~
(≖‿ゝ≖)✧ 」
https://ithelp.ithome.com.tw/upload/images/20210924/20139066eB0IvBD43M.png

(唉... 数学不会背叛你... 因为不会就是不会,呜呜呜呜呜)


函式

函式可以拿来包装各个你想执行的任务,并透过呼叫函式,来多次执行这个任务。

例如可以透过函式来做加法计算功能,而当你需要丢数字进去运算时,就可以不断地去呼叫该函式,并得到相加的数字。

让我们先来了解应该如何定义函式吧?

函式的组成

  1. 函式的名称(可自定义)
  2. 小括号 () 用来放置参数,可用,逗号分隔每个参数
  3. 大括号 {} 内部可以放想执行的 JavaScript 程序码

当我们透过以上三个步骤组合函式後,函式会长成什麽样子呢?

函式陈述式

function test(){
	console.log("Hello World!")
}

没错,这个样子就完成了,但你会发现你想印出来的 "Hello World!" 根本没印出来!等等先不要怀疑自己写错了,其实是因为你没有呼叫函式啦!

该如何呼叫呢?其实就是透过我们自定义的名称,含後面的()小括号,就可以呼叫成功罗!

function test(){
	console.log("Hello World!")//Hello World!
}
test()

真是太好了,可喜可贺。

但也不是每个函式都需要有名称的,有些函式也可以是匿名的,例如用函式表达式来定义的函式。

函式表达式

函式表达式该如何撰写呢?
首先,先宣告一个变数後,在将一个函式赋予给该变数。

let test = function(){
	console.log("Hello World!")//Hello World!
}
test()

而函式表达式的呼叫方式是变数名称加上()小括号。

至於什麽是陈述式、表达式,未来学习中阶魔法时会介绍到唷!

知识点:函式

  • 函式的定义方式有函式陈述式、函式表达式
  • 函式的组成包含:名称、参数、想执行的程序码
  • 记得要呼叫函式,函式才会执行

参数

还记得函式的组成第二点有提到参数吗?那参数又是什麽呢?

让我们用一开始说到的加法计算功能来了解参数吧!

让我们来设定两个参数,分别为 num1 、num2:

function add (num1,num2){
	console.log(`${num1 + num2}`)//num1 、 num2 参数会被带入执行,印出 3
}
add (1,2)

参数是可以自定义的,可以依据情境定义参数後,在呼叫函式时,传参数进去。

那如果今天我定义了两个参数却只传一个参数进去会报错吗?

function add (num1,num2){
	console.log(num2)//undefined
	console.log(`${num1 + num2}`)//NaN
}
add (1)

可以看到参数二的地方因为未给值,会被赋予 undefined

如果要解决这个问题可以透过预设带入参数的方式,可以透过 = 号提前赋予参数预设值,这样参数在呼叫时未给予值,也可以带入预设值,范例如下:

function add (num1,num2 = 0){
	console.log(num2)//0
	console.log(`${num1 + num2}`)//1
}
add (1)

呼叫时未给予参数 num2 值时,因为该参数已经有预设值了,会带入 0 。

知识点:参数

  • 参数可藉由 , 逗号的方式分隔
  • 参数只存活在大括号内
  • 定义的参数少於传进去的参数时,会自动将未被定义的参数赋予 undefined
  • 可以预设带入参数的值,如果呼叫时未给予该参数值时会赋予预设值

而参数只能存活在函式的 {} 大括号内,那当我们希望拿到函式回传的值要怎麽办呢?

可以使用 return 的方式,接下来让我们了解 return 吧!


return

让我们来学学 return 是怎麽运作的吧!

在函式内可以透过 return 回传值,并将该值赋予到呼叫它的变数上,如下:

function calcBmi(heightNum, weightNum) {
  let bmi = (weightNum / (((heightNum / 100) * heightNum) / 100)).toFixed(2);
  return bmi; //回传 bmi 到呼叫它的地方
}
let shannonBmi = calcBmi(168, 55); //赋予函式回传的值到变数上
console.log(shannonBmi); //19.49

当初学 return 的时候卡关了一小阵子,一直想不通怎麽一直丢来丢去的,後来就一直会提醒自己 return 就是会回传值到呼叫它的地方,当执行到 return 就会中断该函式。

function calcBmi(heightNum, weightNum) {
  let bmi = (weightNum / (((heightNum / 100) * heightNum) / 100)).toFixed(2);
  return bmi;
  console.log("123456789"); //不会执行
}
let shannonBmi = calcBmi(168, 55);

这样子是不是代表整个函式只能写一个 return 呢?其实不是的!

让我们看看以下的范例会更清楚:

function add(num1, num2) {
  if (num1 < 0 && num2 < 0) {
    return 0; //当符合 if 条件时执行此 return 後并中断函式
  } else {
    return num1 + num2; //当不符合 if 条件时执行此 return 後并中断函式
  }
  console.log("123"); //都不会执行到
}

return 其实可以设定多组,但要特别留意的地方在函式内只要执行了一次 return 就会中断该函式。

那如果我们什麽值都不 return 还会中断函式吗?

function add(num1, num2) {
  return;
  console.log("123"); //没有执行
}

return 还是有中断函式的效果。

最後来聊一个跟 return 有关联性的东西自动插入分号(automatic semicolon insertion,ASI), 自动插入分号是什麽意思呢?

return 来举例好了!

如果我们今天想 return num1+num2 ,但不小心断行了,会发现:

function add (num1,num2){
	return
	num1+num2;
}
let shannonNum = add (1,2);
console.log(shannonNum)//undefined

为什麽 shannonNum 居然变成 undefined 了!

那是因为 return 会被自动插入分号,所以其实执行时长这样:

function add(num1, num2) {
  return;
  num1 + num2;
}
let shannonNum = add(1, 2);
console.log(shannonNum); //undefined

那当然就被中断而没有回传值出去,所以要特别留意 return 的断行。

知识点:return

  • 可透过 return 回传值并将值赋予到变数上
  • 函式只要执行到一次 return 就会被中断
  • return 即使不回传值一样能中断函式
  • 要留意 return 会受自动插入分号的影响

总结

  • 函式的组成包含:名称、参数、想执行的程序码,要执行时需呼叫函式
  • 参数间透过 , 逗号区隔,且可自定义名称,也可自定义预设值
  • 想回传函式的值可以透过 return ,只要执行一次 return 就会中断函式

小练习

1.请问以下关於函式的叙述何者错误?
A 参数名称可以自定义,并可给予预设值
B 想回传函式内的值可以透过 return
C 函式可以不用呼叫也会自动执行
D 执行到一次 return 就会中断该函式

解答:函式需要透过呼叫才能执行,选项 C 错误。

2.请参考以下程序码,选出错误叙述的选项

function add(num1, num2 = 1) {
  return num1 + num2;
  console.log("123");//选项一
}
let numA = add(1);
console.log(numA);//选项二
let numB = add(1, 3);
console.log(numB);//选项三

A 选项一不会执行,因为 return 中断函式了
B 选项二因为 numA 呼叫时没有带入第二个参数,所以会印出 NaN
C 选项三会印出 4
D 范例程序码的函式为函式陈述式

解答:参数 num2 有带入预设值 1 ,呼叫时未给予值会带入预设值,所以选项二会印出 2 ,选项 B 错误。


参考文献

JavaScript 必修篇 - 前端修练全攻略(六角学院)
https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Guide/Functions
https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Statements/return


<<:  Day9-JDK性能监控工具:jstat(下)

>>:  Day 12 阿里云架设网站-网站负载均衡

视觉化KBARS日K(2)-日K成果展示

先上最後的成果图~ 今天我们的范例换一个套件, 这次我们使用的是echarts, 跟之前一样,取出k...

Flutter - Flutter 网路 GIF 图片重复播放

Flutter - Flutter 网路 GIF 图片重复播放 参考资料 Flutter开发实战系列...

Day 25 (Js)

1.= (1)=设值 (2)= =比较 (3)= = =型态 (4)=> 箭头函式 var x...

DAY14 - 档案类的物件关系厘清(3) - ArrayBuffer

ArrayBuffer ArrayBuffer (又称byte-array) 就是一段固定大小的记...

从 JavaScript 角度学 Python(13) - 输出入资料

前言 接下来讲一点比较互动性质的东西,其实也是为了下一个章节铺陈,不然我真的快没梗了 QQ 输入资料...