跳转至

初学函数

函数的作用

人类语言里面,我们不仅会给人和物起名字, 比如 小张, 足球, iphone

有时候,我们还要给 一串动作起名字,指代 一种做事的方法,一种流程。

比如:我们公司的面试流程是

    把求职者带到3号会议室
    请求职者 完成答卷
    让测试经理来面试 求职者
    让技术总监面试 求职者


我们会把上面这 做事的方法,起名叫 面试流程

面试流程 就代表了这一串动作。


以后,我们想告诉 HR 给来的求职者面试的时候,只要说,给他走 面试流程 ,就行了。

不需要说, HR ,请你做如下的事情

把求职者带到3号会议室
请求职者 完成答卷
让测试经理来面试 求职者
让技术总监面试 求职者

你们会这么说吗?

不会,因为这样太麻烦了。我给它起名字 面试流程 ,只要说 :“走面试流程”,HR 自然知道是什么意思。这样就方便多了。

定义函数

同样的道理,在编程上,如果我要多次输出面试的流程,就像下面的代码,

console.log("把求职者带到3号会议室")
console.log("请求职者 完成答卷")
console.log("让测试经理来面试 求职者")
console.log("让技术总监面试 求职者")

每次都全部写一遍太烦了, 就可以定义一个名字来代表要执行这四条语句

定义一个名字 对应多个语句操作, 称之为定义函数

所以:定义函数 就好像是给 一段代码 起了个名字

js中,我们是这样定义函数的:

function interview(){
    console.log("把求职者带到3号会议室")
    console.log("请求职者 完成答卷")
    console.log("让测试经理来面试 求职者")
    console.log("让技术总监面试 求职者")
}

function 是关键字 表示定义一个函数

后面是函数的名字,紧接着后面需要一个括号 ,这个括号中间,根据需要还可以有 参数,这里我们先不讲它

最后函数里面要执行的所有代码 放在一个花括号中,表示这个函数名字代表的具体动作是什么,称之为函数体

建议 把 函数体中的代码 整体缩进 2个 或者 4 个 空格,这样代码的可读性更好一些。


这样定义好了以后,后面的代码要指代这个面试的流程,只需要写名字 interview 就行了。

比如:

console.log(interview)

运行一下,发现会输出内容如下

ƒ interview(){
    console.log("把求职者带到3号会议室")
    console.log("请求职者 完成答卷")
    console.log("让测试经理来面试 求职者")
    console.log("让技术总监面试 求职者")
}

表示这个 interview 是 一个函数类型的对象。

调用函数

特别要注意的是,js引擎执行到 定义函数 的语句时,并不会执行函数体里面的代码。

要执行函数体里面的代码,必须 调用函数

js代码怎么调用函数呢?就是在 函数名后面加上括号。

比如,要执行 interview 这个名字代表的动作,就在后面加上括号 interview()

如下:

interview()
console.log('后续代码')

interview() 就叫 调用函数 interview ,有时也叫做 执行函数 interview。

当js引擎 执行到 这行调用函数的代码时,就会跑到 函数 interview 里面,去执行函数里面的语句。

函数必须先定义,后面才能调用。

调用后返回

注意,当js引擎执行完被调用函数内部的代码后,还会 返回 到调用它的代码处,继续执行后面的代码。

上面的例子里面, 执行完 interview 对应的函数内部代码后, 会返回调用处,执行后面的 这条语句

console.log('后续代码')

函数的参数

前面提到过,函数调用括号里面的内容 称之为函数的 参数

有的函数要完成功能,需要告诉它一些信息。

比如 console.log 函数,如果你不告诉它要打印的内容是什么,它怎么能打印信息到屏幕上呢?

参数的作用 就是: 提供 函数完成功能 所必须的信息


有参数的函数像这样

function func(para1,para2){
    // 函数内容
}

函数的参数都是放在函数定义的括号里面的。

比如上面示例代码中的 para1,para2

参数其实也是一个变量,所以他们的命名规则和变量的命名规则一样。

参数可以没有,可以是一个,也可以是多个。

参数之间用逗号隔开。

调用有参数的函数时, 通常 应该传入对应个数的参数。

是一个参数,就传入一个,两个就是传入两个

我们上面interview的例子里面,如果我们要加上显示出面试者的名字,就可以这样

function interview(interviewee){
    console.log("求职者是 " + interviewee)
    console.log("把" + interviewee + "带到3号会议室")
    console.log("请" + interviewee + "完成答卷")
    console.log("让测试经理来面试" + interviewee)
    console.log("让技术总监面试" + interviewee )
}
interview('王小五')

我们在定义的时候,并不知道将来调用的时候是谁来面试。

但是没有关系。可以作为参数,定义在这里。

面试者来了,我们在调用函数的时候,会将面试者的名字作为参数传递过来。

在执行

interview('王小五')

的时候, js引擎就会到 函数 interview 准备去执行里面的代码,并且在执行函数代码前,会将参数变量 interviewee 赋值为 '王小五'


调用函数的时候,如果 传如的参数值个数 比定义参数的个数少,有的参数没有传值,js引擎会自动传入一个 undefined 值。

如下

interview()

运行结果如下

求职者是 undefined
把undefined带到3号会议室
请undefined完成答卷
让测试经理来面试undefined
让技术总监面试undefined

undefined 是js内置的,表示没有数据内容的对象。


调用函数的时候,如果 传如的参数值个数 比定义参数的个数多,多余的参数会在执行函数时被丢弃。

函数的返回值

什么是函数返回值

有的函数执行一个流程就完了,并不需要返回什么信息,比如 console.log 函数,就是打印一下参数字符串,就完成了它的任务。

但是有的函数,需要返回一个结果给调用者。

比如 计算两个数字平方和的函数,必须要返回一个结果,告诉调用代码,平方和的计算结果。

函数要返回结果,就必须要使用 return 关键字,后面加上返回的结果对象

比如:

function squarep(num1,num2){
    return num1**2 + num2**2
}

var ret = squarep(1,2)
console.log(ret)

语句 var ret = squarep(1,2) 等号右边的 就是函数调用的表达式。

js引擎在执行这条语句的时候,会执行squarep函数对应的代码,函数代码最后返回一个平方和的计算结果。

这个计算结果(是一个数字对象) 就被赋值给了变量 ret

所以接下来的语句 console.log(ret),就可以打印出1 和 2 的平方和 计算结果 5


js引擎执行代码的时候,一旦执行了函数中的 return 语句,就会立即从函数中返回到调用的地方,该函数下面还有代码,也不会再执行了。

比如

function squarep(num1,num2){
    return num1**2 + num2**2
    console.log('这条语句在return后面,不会执行')
}

ret = squarep(1,2)
console.log(ret)


如果一个函数定义,里面并没有写return语句,像这样

function func1(){
    console.log('你好')
}

console.log(func1())    

那么该函数调用后会返回一个 undefined


console.log不是返回值

我的一些零基础的学员, 经常傻傻分不清下面这两段代码有什么区别

function squarep(num1,num2){
    var ret = num1**2 + num2**2
    console.log(ret)
}

ret = squarep(1,2)


function squarep(num1,num2){
    var ret = num1**2 + num2**2
    return ret
}

ret = squarep(1,2)


他们会这样告诉我: 第1段代码运行后打印出了结果,所以函数 squarep 有返回值,而第2段代码运行后没有打印结果所以squarep没有返回值。

天哪,至少有5个小班学员有这样的误解了。

再次强调,之所以你在屏幕上能看到打印结果,是因为代码里面有console.log语句的原因,不是因为有返回值。

返回值要能显示在屏幕上也必须调用console.log打印出来。

像这样

function squarep(num1,num2){
    var ret = num1**2 + num2**2
    return ret
}

ret = squarep(1,2)
console.log(ret)

上面第1段代码,由于没有写return语句,所以返回的是None(空对象)而不是计算结果,它只是打印了计算结果。

而第2段代码才是返回了计算平方和的结果。

参数缺省值

没有特别指定的情况下, 函数的参数的缺省值就是 undefined ,如果你调用的时候没有给某个参数传值,其值就是 undefined

有时我们需要给函数特别指定缺省值.


假设,我们要实现一个函数,统计考试得分超过指定分数的人数。

function  overScoreStudents(studentScoreList, score){
    var count = 0

    // 下面的代码用到了循环和判断,后面章节会学习到
    for (var ss of studentScoreList){
        if (ss >= score)
            count += 1
    }

    return count
}

在调用这个函数的时候,大部分时候 都是统计超过及格分数线60的人数。像这样

overScoreStudents([76,56,67],60)

所以,我们调用该函数的时候,第二个参数通常都是填写 60 。

这样显得就有些麻烦。

这时候,可以在定义函数的时候,给它加上缺省值,像下面这样:

function  overScoreStudents(studentScoreList, score=60){
    ...
}

这样,在调用这个函数的时候,如果score参数还是传入60 就可以不用写了,像这样

overScoreStudents([76,56,67])

js执行引擎 发现该函数参数score有缺省值,就会自动帮我们传入缺省值60 给 参数score。

当然如果我们调用的时候传入了参数,比如像下面这样,js引擎就会将 70 传给参数score。

overScoreStudents([76,56,67], 70)

变量的有效范围

变量的有效范围有3种

  • 全局 Global scope

  • 函数内部 Function scope

  • 代码块 Block scope

全局范围

大家来看这样一个例子

var upChars = '零壹贰叁肆伍陆柒捌玖'

console.log('4 对应的汉字是:' + upChars[4])

function getHan(num){
  console.log(num + '对应的汉字是:' + upChars[num])
}

getHan(5) 

定义在所有函数外部的变量,称之为 全局变量

全局变量的有效范围是整个代码文件。

上面的例子中 upChars 就是一个 全局变量。

函数内部代码 可以访问 全局变量的。

函数内部

大家来看这样一个例子

function func(num1,num2){
    var ret = num1 + num2
    return ret
}

func(1,2)
console.log(num1)   
console.log(ret)   

运行程序,可以发现 这样的错误提示

Uncaught ReferenceError: ret is not defined
    at <anonymous>:7:13

定义在某个函数内部的变量,称之为 局部变量 。比如这里的 ret

函数的 参数变量 也是 局部变量,比如这里的 num1,num2

局部变量有效范围只能是该函数内部。


因为 ret 是 func 函数内部的 局部变量 , 有效范围只能是 func函数内部, 不能在外部使用。

同样的,参数变量, 比如上面的 num1, num2 也是函数 内部的局部变量,这两个变量名也只能在 func函数内部使用。

代码块

在 ES6(2015)之前,JavaScript 只有 Global Scope 和 Function Scope。

ES6 引入了两个重要的新 JavaScript 关键字: letconst

这两个关键字在 JavaScript 中提供了 代码块作用域

{ } 花括号代码块 内声明的变量不能从块外访问

比如

{
    let upChars = '零壹贰叁肆伍陆柒捌玖'
}

console.log('4 对应的汉字是:' + upChars[4])

运行结果是

Uncaught ReferenceError: upChars is not defined
    at <anonymous>:5:27


const也是这样

{
    const upChars = '零壹贰叁肆伍陆柒捌玖'
}

console.log('4 对应的汉字是:' + upChars[4])


在函数内部的代码块,也是这样的规则

function func(num1,num2){
    {
        let ret = num1 + num2
    }
    return ret
}

func(1,2)

运行也会报错

Uncaught ReferenceError: ret is not defined
    at func (<anonymous>:5:5)
    at <anonymous>:8:1

而这样就可以

function func(num1,num2){
    {
        let ret = num1 + num2
        return ret
    }
}

func(1,2)

var vs let

前面我们说过 var 和 let 都可以定义一个变量.

但是它们定义的变量存在有效范围的差异,如下所示:

function run() {
  var aaa = "aaa";
  let bbb = "bbb";

  console.log(aaa, bbb); // aaa bbb

  {
    var ccc = "ccc"
    let ddd = "ddd";
    console.log(ccc, ddd); // ccc ddd
  }

  console.log(ccc); // ccc
  console.log(ddd); // ddd is not defined
}

run()

运行结果是

aaa bbb
ccc ddd
ccc
Uncaught ReferenceError: ddd is not defined
    at run (<anonymous>:14:15)
    at <anonymous>:17:1

可以发现, 最后打印 ddd 变量 的代码是错误的,

因为let 定义的变量如果在块内, 有效范围只能在本代码块内.

而 var 定义的变量如果在块内, 其有效范围却可以是整个函数

范围覆盖

函数里面可以直接使用外部的全局变量,比如

var upChars = '零壹贰叁肆伍陆柒捌玖'
function getZh(){
    console.log(upChars)
}

getZh() 


如果在函数内部要对全局变量进行重新赋值,可以这样做

var upChars = '零壹贰叁肆伍陆柒捌玖'
function change(){
    upChars = '零一二三四五六七八九'
}

change()
console.log(upChars)



大家再来看这样一个例子

var upChars = '零壹贰叁肆伍陆柒捌玖'
function getZh(){
    var upChars = '零一二三四五六七八九'
    console.log(upChars)
}

getZh() 

在函数内部,如果 局部变量 和 全局变量同名,使用的是 局部变量。


再看这个例子

var upChars = '零壹贰叁肆伍陆柒捌玖'
function getZh(){
    var upChars = '零一二三四五六七八九'
    {
        var upChars = '0123456789'
        console.log(upChars)
    }
}

getZh() 

一些内置函数

输入框 - prompt 函数

prompt 函数可以让浏览器弹出一个对话框,提示让用户输入单行文本信息

比如

let phone = prompt("请输入电话号码", "13900000001")
console.log(phone)

其中

  • 第1个参数是 输入提示语

  • 第2个参数是 缺省输入值

  • 返回值是 用户确认(点击、回车)后,输入框内的字符串

提示框 - alert 函数

alert 函数可以让浏览器弹出一个对话框,提示用户一段信息

比如

alert("输入电话号码错误,必须是数字")

参数是 提示语

确认框 - confirm 函数

confirm 函数可以让浏览器弹出一个对话框,让用户确认一段信息,并选择是或者否

比如

let ok = confirm("确定要删除个人资料吗?");
console.log(ok)

其中

  • 参数是 确认信息

  • 如果用户 点击是 返回true , 点击否 返回false

返回的是 布尔值,表示是、否。 后面教程会讲到

parseInt、parseFloat

可以使用 parseInt 函数,把字符串表示的数字转化为 整数,

可以使用 parseFloat 函数,把字符串表示的数字转化为 数字(整数或小数),

比如

parseInt('34')   // 返回 34
parseInt('34.4') // 还是返回 34
parseFloat('34') // 返回 34
parseFloat('34.4') // 返回 34.4

您需要高效学习,找工作? 点击咨询 报名实战班

点击查看学员就业情况