什么是函数
- 函数就是语句(功能)的封装,可以让这些代码方便地被复用;
- 函数具有“一次定义,多次调用”的优点;
- 使用函数,可以简化代码,让代码更具有可读性;
函数的定义
- 和变量类似,函数必须先定义然后才能使用
- 使用function关键字定义函数,function是“功能”的意思
function name(params) {
// 函数体语句
}
// 匿名函数
var fun = function (params) {
// 函数体语句
}
函数的调用
- 执行函数体中的所有语句,就称为“调用函数”;
- 函数必须要调用才能够执行;
fun() //调用函数
函数声明的提升
fun(); // 函数被执行
function fun() {
console.log('函数被执行');
}
函数表达式不能提升
如果函数使用函数表达式的写法定义的,则没有提升的特性
fun(); // 引发错误: Uncaught TypeError: fun is not a function
var fun = function () {
console.log('函数被执行');
}
函数的参数
- 参数是函数内的一些待定值,在调用函数时,必须传入这些参数的具体值;
- 函数的参数可多可少,函数可以没有参数,也可以有多个参数,多个参数之间需要用逗号隔开;
arguments
函数内arguments表示它接收到的实参列表,它是一个类数组对象
类数组对象:所有属性均为从0开始的自然数序列,并且有length属性,和数组类似可以用方括号书写下标访问对象的某个属性值,但是不能调用数组的方法;
function fun() {
console.log(arguments); // Arguments(4) [11, 1, 2, 45, callee: ƒ, Symbol(Symbol.iterator): ƒ]
console.log(arguments[0]); // 11
console.log(arguments[1]); // 1
}
fun(11,1,2,45);
// 不管用户传入多少个实际参数,永远能够计算它们的和
function fun2() {
var sum = 0;
for(var i = 0; i < arguments.length; i++){
sum += arguments[i];
}
console.log('所有参数的和是' + sum); // 所有参数的和是12
}
fun2(1,2,3,6)
函数的返回值
- 函数体内可以使用return关键字表示“函数的返回值”
// 函数的功能是返回两个参数的和
function sum(a, b) {
return a + b;
}
var result = sum(3,5);
console.log('两个数字的和是'+result);
- 调用一个有返回值的函数,可以被当做一个普通值,从而可以出现在任何可以书写值的地方
function sum(a, b) {
return a + b;
}
var result = sum(3,5) * sum(4,2);
console.log(result); // 48
function sum(a, b) {
return a + b;
}
var result = sum(3,sum(4,2));
console.log(result); // 9
- 调用函数时,一旦遇见return语句则会立即退出函数,将执行权交还给调用者;
function fun() {
console.log(1);
return 2;
console.log(3);
}
console.log(4)
var char = fun();
console.log(char);
console.log(5);
内置sort()方法
数组排序可以使用sort()方法,这个方法的参数又是一个函数;
这个函数中的a、b分别表示数组中靠前和靠后的项,如果需要将它们交换位置,则返回任意正数;否则就返回负数;
var arr = [33,552,11,44];
arr.sort(function (a,b) {
if (a>b) {
return 1;
} else {
return -1;
}
})
console.log(arr); // (4) [11, 33, 44, 552]
递归
函数的内部语句可以调用这个函数自身,从而发起对函数的一次迭代。在新的迭代中,又会执行调用函数自身的语句,从而又产生一次迭代。当函数执行到某一次时,不再进行新的迭代,函数被一层一层返回,函数被递归;
递归的要素
边界条件:确定递归到何时终止,也称为递归出口;
递归模式:大问题是如何分解为小问题的,也称为递归体;
// 斐波那契数列
// 编写一个函数,这个函数的功能是返回斐波那契数列中下标为n的那项的值
function fib(n) {
// 数列的下标为0和1的项的值是1
if (n==0 || n==1) return 1;
// 斐波那契数列的本质特征就是每一项都等于前面两项的和
return fib(n-1) + fib(n - 2);
}
// console.log(fib(6));
// 书写一个循环语句,计算斐波那契数列的前15项
for(var i = 0; i < 15; i++){
console.log(fib(i));
}
实现深克隆
使用递归思想;如果遍历到项是基本类型值,则直接推入结果数组;如果遍历到的项是数组,则重复执行浅克隆的操作;
// 复习浅克隆
var arr = [11,22,55,66,3,[1,2]];
var result = [];
for (var i = 0; i < arr.length; i++) {
result.push(arr[i]);
}
// 输出结果数组
console.log(result);
// 测试是否实现了克隆,就是说本质上是内存中的不同数组了
console.log(arr == result);
// 测试这样的克隆是浅克隆,“藕断丝连”
arr[5].push(9);
console.log(result);
// 深克隆
// 原数组
var arr1 = [1,2,3,4,[5,8,[5,9]]];
// 函数,这个函数会被递归
function deepClone(arr) {
// 结果数组;定义在里面是因为,他是一个局部变量,每次遍历的时候都要重新生产
// “每一层”都会有一个结果数组
var result = [];
// 遍历数组的每一项
for(var i = 0; i < arr.length; i++){
// 类型判断,如果遍历到的项是数组
if (Array.isArray(arr[i])) {
// 递归
result.push(deepClone(arr[i]));
}else{
// 如果遍历到的项不是数组,是基本类型值,就直接推入到结果数组中
// 相当于是递归的出口
result.push(arr[i]);
}
}
// 返回结果数组
return result;
}
// 测试一下
var arr2 = deepClone(arr1);
console.log(arr2); // (5) [1, 2, 3, 4, Array(3)]
// 是否藕断丝连;否
console.log(arr1[4] == arr2[4]); // false
arr1[4].push(99);
arr1[4][2].push(19);
console.log(arr1[4]) // (4) [5, 8, Array(3), 99]
console.log(arr2[4]); // (3) [5, 8, Array(2)]