一般来说,一个函数是可以通过外部代码 调用 的一个“子程序”(或在递归的情况下由内部函数调用)。像程序本身一样,一个函数由称为函数体的一系列语句组成 。
在 JavaScript 中,函数是头等 (first-class)对象,因为它们可以像任何其他对象一样具有属性和方法。
默认情况下,JavaScript引擎或者浏览器会内置一些已经实现好的函数。
比如:alert/prompt/console.log/String/Number/Boolean等。
可以理解:函数其实就是某个代码片段的封装,这段代码帮助我们完成某一个特定的功能。
语法:
由 关键字 funciton
,并跟随函数名称、函数参数列表、定义函数的JS语句
function name([param,[, param,[..., param]]]) {
[statements]
}
name
: 函数名param
: 要传递给函数的参数的名称。不同引擎中的最大参数数量不同。statements
: 包含函数体的语句案例:
假设你要编写一些反复“发出叫声”的代码:在小狗较大时发出较大的 叫声(显示大写的WOOF WOOF),而小狗较小时发出较小的叫声(显 示小写的woof woof)。 之后需要在代码中多次使用这种发出叫声的功能。
下面来编写一个可反复使用的bark函数。
function bark(name, weight) {
if (weight > 20) {
console.log(name + ' says WOOF WOOF')
} else {
console.log(name + ' says woof woof')
}
}
⚠️ 函数定义完后,里面的代码是不会执行的, 函数必须调用才会执行。
定义的函数并不会自动执行它。定义了函数仅仅是赋予函数以名称并明确函数被调用时该做些什么。
通过 函数名() 即可。
bark("旺旺",20) // 旺旺 says woof woof
在开发中,函数内部是可以调用另外一个函数的。
既然函数中可以调用另外一个函数,那么函数是否可以调用自己呢?
函数,把 具有独立功能的代码块 组织为一个小模块,在需要的时候调用
函数的参数,增加函数的 通用性,针对 相同的数据处理逻辑,能够 适应更多的数据;
形参和实参
bark("旺旺", 20) // 旺旺 says woof woof
bark("旺旺2", 10) // 旺旺2 says woof woof
bark("旺旺3", 18) // 旺旺3 says woof woof
bark("旺旺4", 30) // 旺旺4 says WOOF WOOF
回想我们之前使用的prompt函数,函数需要接受参数,并且会返回用户的输入;
所以说, 函数不仅仅可以有参数,也可以有返回值:
undefined
的。return
语句指定返回值。
function sum(num1, num2) {
if (num1 < 0 || num2 < 0) return '数字要大于0'
return num1 + num2
}
console.log(sum(-1, 0)) // 数字要大于0
console.log(sum(1, 2)) // 3
在JavaScript(ES5之前)中没有块级作用域的概念,但是函数可以定义自己的作用域。
作用域(Scope) 表示一些标识符的作用有效范围(所以也有被翻译为有效范围的);
函数的作用域表示在函数内部定义的变量,只有在函数内部可以被访问到;
| 外部变量和局部变量的概念 :
❣️ 定义在函数内部的变量,被称之为局部变量(Local Variables)。
❣️ 定义在函数外部的变量,被称之为外部变量(Outer Variables)。
什么是全局变量?
在函数中,访问变量的顺序是什么呢?
let a = '张三'
function fn() {
let b = '局部b'
console.log('fn中访问:', a)
console.log(b)
}
function fn2() {
console.log('fn2中访问:', a)
}
fn()
fn2()
// fn中访问: 张三
// 局部b
// fn2中访问: 张三
在JavaScript中,函数并不是一种神奇的语法结构,而是一种特殊的值。
前面定义函数的方式,我们称之为 函数的声明(Function Declaration) ;
还有另外一种写法是 函数表达式(Function Expressions) :
var foo = function () {
console.log("函数表达式 foo")
}
◼ 注意,function关键字后面没有函数名
函数表达式允许省略函数名 。
⚠️ 无论函数是如何创建的,函数都是一个值!
函数声明 | 函数表达式 | |
---|---|---|
语法 | 在主代码流中声明为单独的语句的函数 | 在一个表达式中或另一个语法结构中创建的函数 |
JavaScript创建函数的时机 | 在函数声明被定义之前,它就可以被调用。这是内部算法的原故; 当 JavaScript 准备 运行脚本时,首先会在脚本中寻找全局函数声明,并创建这些函数; | 函数表达式是在代码执行到达时被创建,并且仅从那一刻起可用 |
开发中如何选择呢?
- 当我们需要 声明一个函数 时, 首先考虑函数声明语法。
- 它能够为组织代码提供 更多的灵活性 ,因为我们可以在声明这些函数之前调用这些函数。
头等函数(first-class function;第一级函数)是指在程序设计语言中,函数被当作头等公民。
即,函数 可以作为 其他函数的参数、函数的返回值、赋值给变量(函数的表达式写法)、存储在数据结构中(存储在对象、数组中)或者也支持匿名函数 。
通常我们对头等公民的编程方式,称之为 函数式编程 。
JavaScript就是符合函数式编程的语言,这个也是JavaScript的一大特点!
const foo1 = function () {
console.log("foo1函数被执行了")
}
foo1() // foo1函数被执行了
let foo2 = foo1
foo2() // foo1函数被执行了
function foo(fn){
fn()
}
function bar() {
console.log("我是bar函数被调用了~")
}
foo(bar) // 我是bar函数被调用了~
foo这种函数我们也可以称之为高阶函数(Higher-order function);
高阶函数必须至少满足两个条件之一:
- 接受 一个或多个函数作为输入
- 输出一个函数
function sayHello(name) {
function hi() {
console.log("hi:", name)
}
return hi
}
const fn = sayHello("kobe") //柯里化
// console.log("fn:", fn)
fn() // hi: kobe
// 函数存储在对象中
const obj = {
name: '张三',
eating: function () {
console.log("eating")
}
}
obj.eating()
// eating
// 函数存储在数组中
function bar1() {
console.log("bar1被执行~")
}
function bar2() {
console.log("bar2被执行~")
}
function bar3() {
console.log("bar3被执行~")
}
// 事件总线
const arrFns = [bar1, bar2, bar3]
arrFns.forEach((fn) => {
fn()
})
// bar1被执行~
// bar2被执行~
// bar3被执行~
如果在传入一个函数时,我们没有指定这个函数的名词或者通过函数表达式指定函数对应的变量,那么这个函数称之为匿名 函数。
[参考]
- https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions
- https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Functions
- coderwhy