05 函数
将一系列代码或者操作行为打包到一起形成的就是函数,一块有特定功能的代码. 存放运行逻辑的代码块,以便重复使用.
- 函数声明(函数定义)
function xx () {} console.log(xx)//f xx(){}
function为关键字 , 和var let const 一样,专门用来声明函数,函数名见名知意.跟上小括号,小括号内放形参,大括号内放执行的代码,运行的逻辑代码.
函数名 + () 执行
- 函数表达式
let fn = function(){}
区别函数声明和函数表达式 : 函数声明 是function开头 作为关键字,声明函数,并紧接 函数名 (){} 函数声明必须是一条单独的语句,并且必须具备函数名,这是调用函数的基础, 除此之外 其他都是函数表达式,可以成为其他语句的一部分,比如赋值.
- 具名函数/有名函数
function xx()
{console.log("么么哒")}//有名函数,可以直接通过函数名调用
xx()
let fn = function(){console.log("不么么哒")}
//赋值给变量,变量接收函数,变量名即为函数名 因此也是有名函数 fn直接调用 fn()
- 匿名函数/没有名字的函数
//由于没有名字的函数, 没有办法进行调用,所以它不能是单独的一条语句
function(){}//直接报错 //更多的是配合别的语句使用,如赋值操作,或者存于数组 或者对象中,可以通过数组序号和对象属性调用
box.onclick = function(){}
let arr = [function(){}]
let json = { fn1: function(){} }
-
函数表达式的自执行
有名函数声明不能自执行,会报错,需要被调用
let fn = function(){console.log("函数的执行")}
fn()// let 声明 先声明, 再使用
function(){}()// 匿名函数直接执行,js解释器会区别函数声明和函数表达式,当前语句是以function开头,
因此识别为 函数声明,函数声明必须带上函数名,因此直接报错 并且 函数声明也不能自执行
因此,可以进行如下 (function(){console.log("自执行1")}())
//用括号全部包住,防止识别为函数声明,就可以自执行了
//或者 (function(){console.log("自执行2")})()
一般我们不会选择函数立马自执行,需求上没啥意义,而且立即执行的函数表达式 函数名不能再次调用 .
let fn = function(){console.log(123)}()
fn()
//uncaught TypeError: fn is not a function
- 函数的他执行
函数被其他东西触发,比如事件函数,函数通过等号赋值给事件的时候,称之为事件函数,触发事件使函数处触发,称之为 函数的他执行
如果实际操作中需要立即执行函数,可是使用下面的立即执行函数表达式
- IIFE 立即执行函数表达式
记住第一种就行了
js几种情况必须写分号 () [ ] 开头的前面 必须写
let a = 1 (function(){console.log("自执行1")}())
//会报错 1和 ( 会连起来 所以要用分号隔开
(function(){console.log("自执行1")}())
(function(){console.log("自执行2")})()
!function(){}()
+function(){}()
-function(){}()
~function(){}()
return this 参数
return
let fn = function(){console.log(123)}()
console.log(fn)
//函数已经执行,fn 接收到了一个undefined
函数执行,会返回一个值,通过 return 返回,如果没有指定return的值,则返回undefined`
//等价于 let fn = function(){ console.log(123) return undefined }()
return 决定函数执行之后,将要抛出的东西,比如一个函数内部运算好的值,或者一个对象,或者一个固定值.一旦return, return后面的内容,将不再执行.
let fn = function(){ console.log(123)
return 1
console.log(321)
//不会被执行
}()
console.log(fn)
return 后面可以接多个值 ,但只会返回最后一个值
return 1,2,3,"我爱你" //返回我爱你
return 后面可以接运算,但是会运算到最简结果,再将结果返回出去
return 0 || 2 //遇到false用过 遇到true停下
return a === 2 ? b = 2:b = 3
return funtion (){console.log("我是儿子")}
return函数可以通过 接收的变量再执行
let fn = function(){
console.log("爸爸")
return function (){console.log("崽崽")}
}()
//fn等于return返回的函数
fn()
//函数执行 崽崽
this
函数的this指向,指向调用函数的对象,如果没有,则指向window
this是一个关键字,js赋予它特殊的意义,最终决定this指向的是调用对象,而不是执行环境.其实函数的调用是这样的window.fn() 只不过window可以省略,函数的this指向可以通过方法人为改变
function fn(){
function zq(){console.log(this)}
//指向window zq()
}
fn()
let o = { a:{ b:{ c:function(){console.log(this)} } }}
o.a.b.c() // this指向 {c:f} 这个对象
函数参数
执行函数如果没有参数,里面的代码逻辑是死的.每次运行,得到的结果一致,不能根据调用环境需求不同而做出 改变
function fn(){ console.log(1) }
fn()//每次输出都是1
形参 和 实参
形参不需要声明,js可以识别,可以理解为已经默认声明过了 形参的目的是,模拟参数 , 安排参数参与函数内部的逻辑,当实参进来的时候.直接代入进去就可以了参与逻辑执行了,说白了,形参就是实参还没来时,代替模拟实参需要干的事情.
形参的命名见名知意就好,不强做要求. 不根据名字来对应实参,而是通过参数的顺序
function zq (adj){ console.log(`简直是太${adj}`) } zq("可爱") zq("温柔) zq("善良")
可以多个形参 多个实参 可以不对齐
function zq (adj1,adj2){ console.log(`简直是又${adj}又${adj2}`) }
zq("可爱","善良","美丽")//实参多 形参少
zq("温柔")//形参多 实参少
形参多 实参少 ,则多的形参得到的值为undefined
实参多,形参少, 则只拿前面的实参,一一对应,后面实参不管了