函数
什么是函数
函数:完成指定任务并且已经命名的代码块,可以用来进行反复使用。
函数本质上也是一种数据,也属于对象类型;函数也是值,与其他数据类型不同的是,函数中包含的是代码,这些代码是可以执行的。
函数的作用
- 解决代码冗余问题,形成代码的复用。
- 封装代码,让函数内部的代码对外部不可见。
- 可以把整个项目的代码,通过函数模块化。
函数的种类:
- 系统函数,系统已经提供的一些函数。
alert()
、parseInt()
。 - 自定义函数,如果系统函数不能满足要求那就自己写。
如果说有系统函数能够实现功能就用系统函数,不要自己写。
函数自定义和调用
步骤:
- 将你要实现的功能先写出来。
- 将代码用大括号包含起来。
- 使用关键字
funciton 函数名称()
来声明函数。 - 将里面经常变得量提取出来作为参数。
需求,打印5行5列的表格。
function printTable() {
document.write('<table border="1">');
for (var i = 1; i <= 5; i++) {
document.write('<tr>');
for (var j = 1; j <= 5; j++) {
document.write("<td>第" + i + "行,第" + j + "列</td>");
}
document.write('</tr>');
}
document.write('</table>');
}
上面确实定义了一个能够打印5行5列的自定义函数,但是不能使用。函数不调用不执行。
调用函数函数名()
。
注意:
function test(){
console.log('!@#$');
}
- 函数名要有意义。起函数名的规则要遵循标识符的定义规则。
- 函数有3种定义方式,__这种声明方式可以重复(可以和自定义、系统函数都可以重复)__发生重复后面的覆盖前面的。
- 这种方式声明的函数可以在函数定义之前调用,也可以在函数定义之后调用。
其他声明方式
-
函数表达式声明
格式:
var variable = function(){ 语句; };
注意:
-
使用函数表达式方式声明的函数,末尾要有分号。
-
这种方式声明函数,其外围是表达式。
-
这种方式调用函数 必须在创建函数之后(执行到这个表达式才行)。
第一种方式声明函数会在程序运行之前就已经声明了,这种方式声明函数只会在运行到这一行的时候才声明。
-
-
函数构造器声明(不建议用)
格式:
var variable = new Function('args0','arg1'......'语句');
为什么不建议用的原因:
因为这种方法会导致代码解释两次。
函数的其他注意点
函数是数据,函数名是这个数据的标识。
-
如果需要访问函数对应的数据而不执行函数的话,必须去掉函数后面的那对括号。
test();//因为括号前面是函数 所以他被当做函数调用符来使用了。 console.log(1 * (2 + 3));//括号因为包含的是表达式所以当做分组操作符来使用了。
-
函数是一个数据,函数名是标识,一个函数可以有多个标识。
函数的参数
自定义函数的设计原则:用户可以控制自定义函数,可以对自定义函数进行微调。
步骤:
- 将你要实现的功能先写出来。
- 将代码用大括号包含起来。
- 使用关键字
funciton 函数名称()
来声明函数。 - 将里面经常变得量提取出来作为参数。
- 形参:声明函数时,形式上的参数。
- 实参:调用函数时在
()
中实际传入的参数值。
注意:
- 形参和实参传值是一一对应的。
- 多个形参和多个实参之间使用逗号分隔。
- 函数的形参就相当于在函数内部定义了一个变量。
- 如果要获得形参的个数,那么可以使用
length属性
。 - JS函数的形参、实参的个数可以不相等。
- 如果实参比形参少,那么多出来的形参将会自动被赋值为
undefiend
。 - 如果实参比形参多,那么多出来的实参可以使用
arguments对象
来获得。
- 如果实参比形参少,那么多出来的形参将会自动被赋值为
arguments对象
-
arguments对象只有在函数内部才有。(参数对象)
-
array-like
,类数组,像数组但不是数组。为什么像数组因为其中也包含了索引和length属性。arguments
对象可以使用下标的方式来访问传递进来的实参。function printTable(row, column) { console.log(row); console.log(column); console.log(arguments); console.log(arguments[0]); console.log(arguments[1]); console.log(arguments[2]); console.log(arguments[3]); console.log(arguments[4]); } printTable(1,2,3,4,5,6);
-
函数中的形参在JS中可以不写,可以使用
arguments对象
获得,但是使用形参会比较方便。arguments对象
通常用来在处理不知道有多少个实参传递进来的情况:任意个数的数值相加
function total(){ console.log(arguments); var num = 0; for (var i = 0; i < arguments.length ;i++) { num += arguments[i]; } console.log(num); } total(1,2,3);
-
arguments对象中有一个length属性用来确定传递进来多少个实参。
-
arguments对象可以和形参一起使用(但是一般不这样用),他们两个是不一样的东西。传递值给形参是赋值操作,arguments对象是接收到的参数,系统自动放到这个对象中。
function test(num1){ console.log(num1 + arguments[1]); } test(1,2);
-
arguments对象中保存着一个叫
callee
的属性,这个属性指向了拥有arguments对象的这个函数
函数的返回值
return语句
将return后面的值
返回到函数调用处(函数从哪里调用返回到哪里)
什么时候该用return什么时候不用return完全取决于函数的功能,如果你要使用返回的结果那就用return。如果不再使用函数的结果那就不用。
注意:
- 函数定义时返回值不是必须的,如果没有给定返回值那么默认也会返回一个值,这个值就是
undefined
。 - 只写一个return,后面不写返回的值,函数也会返回一个值这个值还是
undefined
。 - 函数会在执行完return语句之后停止函数的执行并且退出函数。(return语句之后的任何代码都永远不会执行。)
通过以上这些特点:return有两个作用:
- 返回函数最终要返回的值。
- 终止函数的执行。(
return
)
函数的函数体(函数要干什么事)、参数、返回值是组成一个完整函数的三大件。
- 无参数无返回值。
- 有参数没有返回值。
- 无参数有返回值。
- 有参数有返回。(最多的)
函数其他
IIFE
IIFE:
Immediately Invoked Function Expression
,意为立即调用的函数表达式,也就是说,声明函数的同时立即调用这个函数。
现在必须将
function(){
console.log('foo');
}
当成函数表达式语句。
函数表达式语句:不能以大括号开头,不能以function关键字开始(和函数声明很像)
- IIFE函数只能运行一次。因为引用类型没有表示,执行完成之后垃圾回收机制就回收了。
- 定义之后马上调用,调用完成之后马上释放。
- IIFE不会被提升,但是内部的代码因为还是属于函数体所以会被提升。
用处:
- 初始化项目时。
- 框架里头会用。JQuery.js。
函数的递归调用
递归’很难理解’。
函数的递归调用就是自己调用自己。
递归:进去
归:出来
注意
- 自己就是这个函数,是自己调用自己。当自己做完一件现在的事情的时候,你会去做上一次没做完的事。
- 递归调用一定要有一个限制,否则就是一直自己调用自己,永不翻身。这就是无限递归。
- 递归调用适合用在不确定具体调用多少次的情况。
回调函数
回调函数的精髓:函数是对象类型的值,可以被当做参数传入到函数中。
- 将一个引用类型赋值给一个变量时,变量存储的是引用类型的地址。
- 一个引用类型可以有很多名字,一个改变引用类型的值,另外一个的值也会改变。
- 函数的参数,如果是普通值,即是赋值;如果是引用类型,传递的是引用类型的内存地址。
- 一个函数本身也是值,一个对象,可以被当做实参传递到函数中并且执行。
- 一个函数本身也是值,也是一个对象,可以被当做返回值返回回来。
什么是回调函数
回调函数被认为是一种高级函数,一种被作为参数传递给另外一个函数(OF)的高级函数,回调函数会在OF内被调用或执行。
function test(fn){
console.log('!!!!');
console.log(fn);//打印函数本身
fn();//执行函数。
}
function t(){
console.log('这是t函数!!!');
}
test(t);
回调函数的本质:是一种模式,解决问题的套路。
回调函数的用处
-
通用化:代码简洁。
俯瞰整个代码结构。
将通用的功能提取出来然后将各种规则提取出来。
减少了耦合
、容易扩展
。 -
事件监听和处理 会用到。
-
Ajax请求数据 会用到。
-
框架中的各种生命周期函数 会用到。
案例
-
定义一个函数,求总价(单价*数量),并且组合成
¥100
,这种格式。 -
定义一个函数,打印100遍:
Hello world!!!
。(不用参数和返回值) -
定义一个函数,打印N遍:
Hello world!!!
。(不用返回值,用参数) -
定义一个函数,求1到n的和。
-
定义一个函数,求1到n的阶乘。
-
定义一个函数,给定一个数组得到这个数组的最大值和最小值。
-
封装函数加工数组,每一项加10输出。
-
封装函数实现打印1到N的质数。
-
封装函数实现数组排序。
-
封装函数实现数组翻转。
-
封装函数实现数组去重。