函数
一、定义
将任意代码封装到一起,在需要的时候进行调用执行
二、语法
1.声明式:
function 函数名(){
函数体-封装的代码
}
函数名() -函数调用语句
2.赋值式
var 函数名 = function(){
函数体-封装的代码
}
函数名() -函数调用语句
三、函数参数问题
1.形参:封装函数时,函数名后跟的参数为形参
2.实参:函数调用时,需要传入的参数
例:
function fn(形参1,形参2,形参3,...){
函数体
}
fn(实参1,实参2,实参3,...)
3.参数个数问题
a.形参比实参少:一一对应,多出来的实参不用
b.形参比实参多:一一对象,多出来的形参为undefined
4.参数默认值
第一种方式
形参=形参 || 默认值
function fn(m){
m=m || 100
函数体
}
第二种方式-ES6的新特性
形参=默认值
function fn(m = 100){
函数体
}
四、函数返回值-return
return后面跟值,则返回给函数返回一个值到函数调用处;return后不跟值,一般用于函数体中,用于终止函数体代码,继续往后执行。
五、函数的优点
1.封装代码,使代码更加简洁;
2.代码复用问题,在重复功能的时候直接调用;
3.代码执行时机,随时可以在需要执行的时候执行。
六、递归函数
1.定义
在函数体中自身调用自身,这样的函数称为递归函数
2.注意事项
一定要有结束的递归语句,不然称为死递归;
结束递归,判断一个条件,满足递归结束的条件,return;
改变递归条件的语句。
3.应用场景
后面的结果,是由前面推导的这类问题。
4.优缺点
优点:容易实现
缺点:
效率较低
递归是有时间和空间消耗的,因为存在重复计算问题。
可能导致调用栈溢出
每一次函数调用在内存栈中分配空间,而每个进程的栈的容量是有限的。当递归调用的层级太多时,就会超出栈的容量,从而导致栈溢出。
七、ES6新增函数特性
1.arguments
在函数内部自带的变量,表示所有实参的集合,是一个伪数组。
存在length属性,值为实参的个数。
2.自调用函数
(function(){
console.log('自调用函数')
})()
自调用函数的作用:改变变量作用域,防止变量污染。
3.箭头函数
1.什么是箭头函数?
箭头函数是对函数的一种简写形式。但是箭头函数只能简写函数表达式,不能简写声明式函数。
2.语法:
(函数的形参) => {函数体内要执行的代码}
3.箭头函数简写三种形式
1.当形参只要一个时,括号可以省略
函数的形参 => {函数体内要执行的代码}
2.当函数体中只有一条语句时,花括号可以不写
(函数的形参) => 函数体内要执行的代码
3.当函数体中只有一条return语句时,花括号和return都可以不写
原箭头函数:(函数的形参) => {return 函数体内要执行的代码}
(函数的形参) => 函数体内要执行的代码
综上述三条,箭头函数可以简写为: 函数的形参 => 函数体内要执行的代码
4.箭头函数的特点
箭头函数中的this关键字指向的时应用上下文(上一级作用域的this指向的对象)
例:
hello直接调用者是obj,第一个this指向obj,setTimeout箭头函数,this指向最近的函数的this指向,即也是obj。
const obj = {
num: 10,
hello: function () {
console.log(this); // obj
setTimeout(() => {
console.log(this); // obj
});
}
}
obj.hello();
八、预解析
1、学习函数,需要了解什么是预解析。
我们书写的JS源代码会通过浏览器进行解析,然后执行代码,获得结果。而预解析则是,JS源代码后会对部分代码提到代码最前面进行解析(如:变量、申明式函数等),然后浏览器再一步一步往下解析执行代码获得结果。这种就叫做预解析。
2.预解析注意事项
1.声明式函数
在内存中先声明有一个变量名是函数名,并且这个名字代表的内容是一个函数。
2.var关键字
在内存中先声明有一个变量名。
3.同名变量和函数解析方式
同名变量和函数,函数优先。
4.if条件不管成不成立语句块都会预解析。
5.return语句后代码不执行,但会进行预解析。
九、作用域
1.什么是作用域
变量起作用的范围。
2.分类
私有作用域:函数体内定义变量起作用的区域
全局作用域:函数体最外层定义的变量起作用的区域
3.访问规则
内层函数的变量可以访问外层函数的变量,访问未定义的变量会出现报错。
4.作用域链
给未定义的变量赋值,现在自己的作用域范围内查找,如果没有找到,继续到上层作用域范围中查找,直到最外层的全局作用域范围内查找,都没有,则直接生成一个变量。