09.函数(function)
函数(Function)
- 函数也是一个对象(JS中万物皆对象)
- 它具有其他对象所有功能
- 函数中可以
存储代码,且可以在需要的时候调用这些代码
语法:
function 函数名( ){
语句...
}
调用函数:
- 调用函数就是执行函数中所存储的代码
- 语法:函数对象( )
- 使用typeof检查函数对象时会返回function
代码
查看代码
<script>
// 创建一个函数
function fn() {
console.log("你好!")
console.log("hello!")
console.log("萨瓦迪卡")
}
// 调用函数
fn()//你好!hello!萨瓦迪卡
fn()//你好!hello!萨瓦迪卡
fn()//你好!hello!萨瓦迪卡
// 使用typeof检查函数对象
console.log(typeof fn) //function
</script>
函数的定义方式
函数声明
function 函数名( ){
语句...
}
函数表达式
const 变量 = function ( ){
语句...
}
箭头函数
const 变量 = ( )=>{
语句...
}
const 变量 = ( )=> 语句...
查看代码
<script>
function fn1() {
console.log("函数声明")
}
const fn2 = function () {
console.log("函数表达式")
}
const fn3 = () => {
console.log("箭头函数1")
}
const fn4 = () => console.log("箭头函数2")
fn1() //函数声明
console.log(typeof fn1) //function
fn2() //函数表达式
console.log(typeof fn2) //function
fn3() //箭头函数1
console.log(typeof fn3) //function
fn4() //箭头函数2
console.log(typeof fn4) //function
</script>
参数
形式参数
- 在定义函数时,可以在函数中指定数量不等的形式参数(形参)
- 在函数中定义形参,相当于在函数内部声明了对应的变量但没有赋值
实际参数
- 在调用函数时,我们可以在函数的( )中传递数量不等的实参
- 实参会赋值给对应的形参
- 参数:
- 如果实参和形参数量相同,则对应的实参会赋值给对应的形参
- 如果实参多于形参,则多余的实参不会使用(下面两种情况在别的语言中肯定报错,但JS不会,应为JS曾经是以不报错为最高原则的语言)
- 如果形参多于实参,则多于的形参显示
undefined
参数类型
- JS中不会检查参数的类型,可以传递任何类型的值作为参数
- 对象也可以作为参数传递,并且在函数中修改对象,其“真实”对象也会改变。
- 函数作为参数,函数也是一个对象(一等函数),别的对象能做的事函数也可以。
参数默认值
- 定义参数时,可以为参数指定默认值
- 默认值,在没有对应的实参时生效
- 当默认值是{ }时,每次调用此函数,默认值对象都是一个新对象。
参数:
<script>
/* 定义两个可以求和的函数 */
function sum1(a, b, c) {
console.log(a + b) //3
}
const sum3 = (a, b) => {
console.log(a + b) //helloworld!
}
sum1(1, 2, 3)
sum3("hello ", "world!")
</script>
参数默认值:
<script>
// 添加默认值
const fn = (a = 10, b = 20, c = 30) => {
console.log("a = ", a) //a = 1
console.log("b = ", b) //b = 2
console.log("c = ", c) //c = 30
}
// 传两个实参
fn(1, 2)
</script>
函数作为参数:
<script>
function fn(a) {
a()
}
// 调用1
fn(
() => console.log("我是传进来的箭头函数!")
)
// 调用2
fn(
function () {
console.log("我是传进来的匿名函数")
})
</script>

思考一:
当我第一次调用fn时,将a指向的对象name改为了"猪八戒",那我们第二次调用fn时是一个孙悟空一个猪八戒还是两个都是猪八戒呢?
<script>
// 函数每次调用都会重新创建默认值
function fn(a = { name: "孙悟空" }) {
console.log("a = ", a.name)
a.name = "猪八戒"
console.log("a = ", a.name)
}
fn()
fn()
</script>
当默认值是{ }时,每次调用此函数,默认值对象都是一个新对象。

但是下面这种情况例外:
// 对象
const obj = { name: "孙悟空" }
// 函数
function fn(a = obj) {
console.log("a = ", a.name)
a.name = "猪八戒"
console.log("a = ", a.name)
}
fn()
fn()
应为对象定义在外面,所以a指向的对象发生改变,后面的所有指向他的变量也都改变。

函数的返回值
- 在函数中可以通过return关键字来指定函数的返回值
- 返回值就是函数的执行结果,函数执行完毕返回值便会作为结果返回
- JS中任何值都可以作为返回值使用(包括对象和函数之类)
- 如果return后不跟任何值,则相当于返回undefined
- 如果不写return,函数的返回值依然是undefined
- return一执行函数立即结束,后面的代码不再执行
<script>
function sum(a, b) {
return a + b; //返回值 5
}
console.log(sum(1, 4))
</script>
特殊
- 箭头函数的返回值可以直接写在箭头后(前提只有返回值这一句话)
- 如果直接在箭头后设置对象字面量的返回值时,对象字面量必须用()括起来(不然会被当成代码块处理)
返回值
const sum1 = (a, b) => a + b;
console.log(sum1(2, 3)) // 5
返回对象
<script>
const fn1 = () => { name: "孙悟空" }
console.log(fn1()) //undefined
const fn2 = () => ({ name: "孙悟空" })
console.log(fn2()) //Object { name: "孙悟空" }
</script>
作用域(scope)
- 作用域指的是一个变量的可见区域
- 作用域分为两种:
- 全局作用域
- 在网页运行时创建,在网页关闭时销毁
- 所有直接编写到script标签中的代码都位于全局作用域中
- 全局作用域中的变量是全局变量,可以在任意位置访问
- 局部作用域
- 块作用域
- 块作用域是一种局部作用域
- 块作用域在代码块执行时创建,在代码块执行完毕时销毁
- 在块作用域中声明的变量是局部变量,只能在块中访问,外部无法访问
- 函数作用域
- 函数作用域在函数调用时创建,调用结束后销毁
- 函数每次调用都会产生一个全新的函数作用域
- 在函数中定义的变量是局部变量,只能在函数内部访问,外部无法访问
- 块作用域
- 全局作用域
作用域链
当我们使用一个变量时,JS解释器会就近原则先在当前作用域中找变量
- 如果找到则直接使用
- 如果没找到则去上一层作用域中找,找到了则使用
- 如果没找到则继续上一层找,以此类推
- 如果到全局作用域都没找到,则报错 xxx is not defined
<script>
// 全局变量
let a = 10
// 局部块
{
let a ="第一代码块中的a"
{
let a = "第二代码块中的a"
console.log(a); //第二代码块中的a
}
}
</script>

浙公网安备 33010602011771号