函数递归
注意:
(1) 外层函数在执行过程中,调用内层函数
(2) 外层函数需要等待内层函数执行完毕后,才会继续向后执行
(3) 外层函数和内层函数都可以设置自己的返回值, 内层函数的返回值不会直接传递给外层
递归(函数在执行过程中调用了自己)
注意:
递归需要有跳出条件(临界值), 否则会形成死递归
RangeError:超过了最大调用堆栈大小 => 死递归
var i = 10; function fn() { console.log(i); // if (i <= 1) { // 满足特定条件之后停止递归 // return i; // } else { // i--; // fn(); // } if (i <= 1) { // 满足特定条件之后停止递归 return i; } i--; fn(); } fn();
JS基本数据
string number boolean null undefined object(array)
值类型(基本数据类型): string number boolean null undefined
(1) 值类型存储在栈内存当中 => 一个萝卜一个坑
引用类型(引用数据类型): object(array)
(2) 存储在堆内存当中 => 对象都是引用类型(null除外)
浅复制: 多个变量/数据 引用同一片内存地址,如果一个内存地址中的数据改变,另一个也会受到影响;
深复制 得到一个与原数组数据相同的新数组
数组的拓展方法
(1) 官方提供的专门操作数组的方法
(2) 一般情况下仅数组可用
语法:
数组.方法名(参数);
学习数组的拓展方法需要注意:
(1) 每个方法的功能(做什么事)
(2) 调用方法后的返回值(有什么结果)
(3) 是否影响原数组
对数组中的元素进行增删改查
尾部新增和头部新增
push() 在数组尾部新增一个或多个元素(多个元素之间用逗号分隔)
返回值: 新增元素后数组的长度
是否影响原数组: 是
var list = [1, 2, 3];
// var result = list.push("a");
var result = list.push("a","b","c");
console.log(result);
console.log(list);
unshift() 在数组头部新增一个或多个元素(多个元素之间用逗号分隔)
返回值: 新增元素后数组的长度
是否影响原数组: 是
var list = [1, 2, 3];
var result = list.unshift("a"); // 4
console.log(result);
console.log(list);
var list = [1, 2, 3];
var result = list.unshift("a","b","c"); // 6
console.log(result);
console.log(list);
尾部删除和头部删除
pop() 删除数组尾部的元素 (每次删除一个)
返回值: 被删除的元素
是否影响原数组: 是
var list = [1, 4, 7, 2, 5, 8 ,"a","b"];
var result = list.pop();
console.log(result);
console.log(list);
var result = list.pop();
console.log(result);
console.log(list);
shift() 删除数组头部的元素(每次删除一个)
返回值: 被删除的元素
是否影响原数组: 是
var list = [1, 4, 7, 2, 5, 8 ,"a"];
var result = list.shift();
console.log(result);
console.log(list);
splice() 任意位置增删改
splice(startIndex,n) 删除
=> 自指定下标位置(startIndex)开始,删除n个元素
返回值: 被删除的元素形成的新数组
是否影响原数组: 是
var list = [1, 4, 7, 3, 6, 9, 2, 5, 8];
var result = list.splice(3,3);
console.log(result);
console.log(list);
splice(startIndex,0,arg1,arg2,...argN) 新增
=> 自指定下标位置(startIndex)开始,删除0个元素后,新增一个或多个元素(自第三参数开始都是新增的元素)
返回值: 被删除的元素形成的新数组 => 空数组(没有被删除的元素)
是否影响原数组: 是
var list = [1, 4, 7, 3, 6, 9, 2, 5, 8];
var result = list.splice(3, 0, "a", "b", "c");
console.log(result);
console.log(list);
splice(startIndex,n,arg1,arg2,...argN) 修改
=> 自指定下标位置(startIndex)开始,先删除n个元素后,再新增一个或多个元素(自第三参数开始都是新增的元素)
返回值: 被删除的元素形成的新数组
是否影响原数组: 是
var list = [1, 4, 7, 3, 6, 9, 2, 5, 8];
var result = list.splice(3, 3, "a", "b", "c");
console.log(result);
console.log(list);
查
includes() 判断数组中是否存在某个元素
返回值: 存在就返回true 不存在就返回false
是否影响原数组: 否
var list = [1, 4, 7, 3, 6, 9, 2, 5, 8];
var result = list.includes(6);
console.log(result);
console.log(list);
indexOf() 查找某个元素在数组中第一次出现的位置
返回值: 存在就返回下标 不存在就返回-1
是否影响原数组: 否
注意:
indexOf() 也可以用于判断数组中是否存在某个元素
存在 index != -1 或 index >= 0
不存在 index == -1
var list = [1, 4, 6, 7, 3, 6, 9, 2, 5, 8];
var result = list.indexOf(6);
console.log(result);
console.log(list);
var result = list.indexOf("6");
console.log(result);
console.log(list);
reverse() 数组的反转
返回值: 翻转后的原数组
是否影响原数组: 是
var list = ["a", "b", "c", "d", "e", "f", "g"];
var result = list.reverse();
console.log(result);
console.log(list);
console.log(result === list);
slice(startIndex,endIndex) 数组裁切 [startIndex,endIndex)
startIndex 起始下标(默认:0)
endIndex 终止下标下标(默认: 数组的长度)
返回值: 裁切的内容形成的新数组
是否影响原数组: 否
var list = ["a", "b", "c", "d", "e", "f", "g"];
取出"c", "d", "e"放到新数组 ["c", "d", "e"]
var result = list.slice(2, 5);
console.log(result);
console.log(list);
等价于
var arr = [];
for (var i = 2; i < 5; i++) {
var item = list[i];
arr.push(item);
}
console.log(arr);
如果不传参可以实现数组的深复制 => 得到一个与原数组元素相同的新数组
var result = list.slice();
console.log(result);
console.log(list);
console.log(result === list); // false
concat() 数组拼接
数组拼接:(可以接收多个数组,元素拼接形成新数组 => 如果concat中的参数是一个数组, 遍历该数组,将该数组中的每个元素放到新数组中,如果concat中的参数是非数组,直接放到新数组中)
返回值: 拼接后形成的新数组
是否影响原数组: 否
将三个数组拼接形成一个新数组
var arr1 = [1,2,3];
var arr2 = [4,5,6];
var arr3 = [7,8,9];
新建数组, 将arr1, arr2 arr3 中的元素放到新数组中
var arr = arr1.concat(arr2,arr3);
console.log(arr);
console.log(arr1,arr2,arr3);
var arr = arr1.concat(arr2,arr3,"a","b","c");
console.log(arr);
console.log(arr1,arr2,arr3);
对比push
var result = arr1.push(arr2,arr3);
console.log(result);
console.log(arr1);
concat之数组深复制 => 得到一个与原数组元素相同的新数组
var list = ["a", "b", "c", "d", "e", "f", "g"];
var result = list.concat();
console.log(result);
console.log(list);
console.log(list === result);
join(char) 用特定字符将数组拼接形成字符串(char默认是 ,)
返回值: 拼接后形成的新字符串
是否影响原数组: 否
var list = ["a", "b", "c", "d", "e", "f", "g"];
var result = list.join("-");
var result = list.join("+");
var result = list.join("/");
var result = list.join(""); // "abcdefg"
var result = list.join(); // 默认参数 ","
console.log(result);
console.log(list);
模拟实现join => 将数组中的元素拼接形成以下字符串 : "a-b-c-d-e-f-g"
"a-b-c-d-e-f-g"
"a-b-c-d-e-f-g-"
var str = "";
var char = "";
for(var i=0;i<list.length;i++){
var item = list[i];
if(i == list.length - 1){
str += item;
}else{
str += item + char;
}
}
console.log(str);
数组的遍历方法:
for循环遍历 => 自行指定循环时下标的起始值和终止值
var list = [1,4,7,2,5,8,3,6,9];
for(var i = 0;i<list.length;i++){
var item = list[i];
console.log(item,i);
}
for...in => 遍历数组返回数组的下标
// 语法 for(var i in 数组){}
// 注意:
// (1) for...in遍历数组时,下标是字符串类型
// (2) for...in遍历数组时, 会自动跳过空余位置
var list = [1,4,7,2,5,8,3,6,9];
var list = [1, 4, 7, , , , 3, 6, 9];
console.log(list);
for (var i in list) {
console.log(i, list[i]);
}
for...of => 遍历数组返回数组的值(缺点: 只会遍历数组返回数组的值,没有下标)
// 语法 for(var val of 数组){}
// 注意:
// for...of 遍历数组时, 不会跳过空余位置,而是返回undefined
var list = [1, 4, 7, 2, 5, 8, 3, 6, 9];
// var list = [1, 4, 7, , , , 3, 6, 9];
var sum = 0;
for (var val of list) {
console.log(val);
sum += val;
}
console.log(sum);
数组的遍历方法 => 数组的拓展方法(官方封装的专门供数组使用的方法)
语法: 数组.方法名()
forEach map filter some every find findIndex reduce reduceRight
forEach() 数组的遍历方法
作用: 遍历数组,每次循环时执行传入的函数(回调函数),
回调函数 => 有三个形式参数(参数可以自己改), item:循环当前元素, index:循环的当前下标, array: 原数组(被遍历的数组 -> 很少用
返回值: undefined (forEach内部没有设置返回值 => 默认返回undefind)
var list = [1, 4, 7, 8, 5, 2, 3, 6, 9];
// 遍历数组
list.forEach(function(item,index,array){ // 形参(item:循环当前元素, index:循环的当前下标, array: 原数组(被遍历的数组 -> 很少用))
console.log(item,index,array); // 每次循环时执行的代码
});
var list = [1, 4, 7, 8, 5, 2, 3, 6, 9];
var sum = 0;
// 遍历数组
list.forEach(function(item){ // 形参(item:循环当前元素, index:循环的当前下标, array: 原数组(被遍历的数组 -> 很少用))
console.log(item); // 每次循环时执行的代码
sum += item;
});
console.log(sum);
map() 数组映射(根据原数组得到新数组)
作用: 遍历数组,每次循环时执行传入的函数(回调函数),接收每次函数执行的结果(返回值),放到新数组中,并返回该新数组
回调函数 => 有三个形式参数(参数可以自己改), item:循环当前元素, index:循环的当前下标, array: 原数组(被遍历的数组 -> 很少用)
返回值:新数组
var list = [1, 4, 7, 8, 5, 2, 3, 6, 9];
// 遍历数组
var result = list.map(function(item,index,array){ // 形参(item:循环当前元素, index:循环的当前下标, array: 原数组(被遍历的数组 -> 很少用))
console.log(item,index,array); // 每次循环时执行的代码
return item * 10;
});
console.log(result);
console.log(list);
等价于
var list = [1, 4, 7, 8, 5, 2, 3, 6, 9];
var fn = function(item,index,array){ // 形参(item:循环当前元素, index:循环的当前下标, array: 原数组(被遍历的数组 -> 很少用))
console.log(item,index,array); // 每次循环时执行的代码
return item * 10;
}
var arr = [];
for(var i in list){
var result = fn(list[i],Number(i),list);
arr.push(result);
}
console.log(arr);
filter() 数组过滤/筛选(筛选除所有满足条件的元素)
作用: 遍历数组,每次循环时执行传入的函数(回调函数),函数的返回值一般是一个条件表达式(筛选条件),把满足条件的元素放到新数组(如果返回值非布尔值,会先隐式转化为布尔值,在判断)
回调函数 => 有三个形式参数(参数可以自己改), item:循环当前元素, index:循环的当前下标, array: 原数组(被遍历的数组 -> 很少用)
返回值:新数组
var list = [1, 4, 7, 8, 5, 2, 3, 6, 9];
// 遍历数组
var result = list.filter(function(item,index,array){ // 形参(item:循环当前元素, index:循环的当前下标, array: 原数组(被遍历的数组 -> 很少用))
console.log(item,index,array); // 每次循环时执行的代码
// return item % 2 == 0; // 条件表达式(true(偶数) / false(奇数))
// return item % 2 == 0 && item % 3 == 0; // 条件表达式(true(6的倍数) / false(非6的倍数))
return item % 2 ; // 返回值非布尔值 (0(false) 1(true)) =>
});
console.log(result);
find() 数组查找(查找满足条件的元素的第一个元素)
作用: 遍历数组,每次循环时执行传入的函数(回调函数),函数的返回值一般是一个条件表达式(筛选条件),返回满足条件的第一个元素(如果返回值非布尔值,会先隐式转化为布尔值,在判断)
回调函数 => 有三个形式参数(参数可以自己改), item:循环当前元素, index:循环的当前下标, array: 原数组(被遍历的数组 -> 很少用)
返回值: 存在就返回第一个满足条件的元素 不存在: undefined
findIndex() 数组查找(查找满足条件的元素的第一个元素的下标)
返回值: 存在就返回第一个满足条件的元素的下标 不存在: -1
/* var list = [1, 4, 7, 8, 5, 2, 3, 6, 9];
// 遍历数组
var result = list.find(function(item,index,array){ // 形参(item:循环当前元素, index:循环的当前下标, array: 原数组(被遍历的数组 -> 很少用))
console.log(item,index,array); // 每次循环时执行的代码
// return item % 4 == 0; // 找4的倍数
// return item % 3 == 0; // 找3的倍数
return item % 3 == 0 && item % 4 == 0; // 找3 4的倍数
});
console.log(result); */
var list = [1, 4, 7, 8, 5, 2, 3, 6, 9];
// 遍历数组
var result = list.findIndex(function (item, index, array) { // 形参(item:循环当前元素, index:循环的当前下标, array: 原数组(被遍历的数组 -> 很少用)
console.log(item, index, array); // 每次循环时执行的代码
// return item % 4 == 0; // 找4的倍数
return item % 3 == 0; // 找3的倍数
// return item
})
reduce(fn,initValue) 数组归并(额外提供了一个贯穿循环的变量)
作用: 遍历数组,每次循环时执行传入的函数(回调函数),
reduce的第一参数是一个函数 => 传入到reduce中(实际参数)
回调函数有四个参数 prev item index array
prev:
(1) 默认接收reduce方法的第二参数作为初始值,如果不设置第二参数作为初始值,默认将数组的第一个元素作为初始值,并从数组的第二个元素开始遍历
(2) 接收上一次函数执行的结果 作为prev的初始值
item 循环的当前元素
index 循环的当前下标
array 原数组
reduce的第一参数是一个函数
initValue 设置prev的初始值
返回值: 最后一个函数执行后返回的结果
var list = [1, 4, 7, 8, 5, 2, 3, 6, 9];
// 遍历数组
var result = list.reduce(function(sum,item,index,array){ // 形参(item:循环当前元素, index:循环的当前下标, array: 原数组(被遍历的数组 -> 很少用))
console.log(sum,item,index,array); // 每次循环时执行的代码
return sum + item; // 1 5 12
},0);
console.log(result);
如果不设置initValue(prev的初始值)
var list = [1, 4, 7, 8, 5, 2, 3, 6, 9];
// 遍历数组
var result = list.reduce(function(prev,item,index,array){ // 形参(item:循环当前元素, index:循环的当前下标, array: 原数组(被遍历的数组 -> 很少用))
console.log(prev,item,index,array); // 每次循环时执行的代码
return prev + item; // 1 5 12
});
console.log(result);
some() 判断是否存在满足条件的元素(本质: 假设法, 假设没有,找到一个就是由)
// 作用: 遍历数组,每次循环时执行传入的函数(回调函数),函数的返回值一般是一个条件表达式(判断条件),只要有一个元素满足条件就返回true,都不返回返回false(如果返回值非布尔值,会先隐式转化为布尔值,在判断)
// 回调函数 => 有三个形式参数(参数可以自己改), item:循环当前元素, index:循环的当前下标, array: 原数组(被遍历的数组 -> 很少用)
// 返回值: 只要有一个元素满足条件就返回true,都不返回返回false
var list = [1, 4, 7, 8, 5, 2, 3, 6, 9];
// 遍历数组
var result = list.some(function (item, index, array) { // 形参(item:循环当前元素, index:循环的当前下标, array: 原数组(被遍历的数组 -> 很少用))
console.log(item, index, array); // 每次循环时执行的代码
// return item % 3 == 0; // 找3的倍数
return item % 3 == 0 && item % 4 == 0; // 找3 4的倍数
});
console.log(result);
every() 判断数组中的元素是否都满足条件(本质:假设法 假设都满足(true),有一个不满足就返回false)
// 作用: 遍历数组,每次循环时执行传入的函数(回调函数),函数的返回值一般是一个条件表达式(判断条件),只要有一个元素不满足条件就返回false,都满足返回true(如果返回值非布尔值,会先隐式转化为布尔值,在判断)
// 回调函数 => 有三个形式参数(参数可以自己改), item:循环当前元素, index:循环的当前下标, array: 原数组(被遍历的数组 -> 很少用)
// 返回值:只要有一个元素不满足条件就返回false,都满足返回tru
var list = [1, 4, 7, 8, 5, 2, 3, 6, 9];
var result = list.every(function (item, index, array) { // 形参(item:循环当前元素, index:循环的当前下标, array: 原数组(被遍历的数组 -> 很少用))
console.log(item, index, array); // 每次循环时执行的代码
// return true;
// return item % 2 == 0; //都是偶数
// return item % 2 == 1; //都是奇数
return item > 0;
});
回调函数(callback)
回调函数(callback) => 把函数当成参数(实际参数)传入到另一个函数中,让它在另一个函数中执行 (简单的来说:传入的函数并没有立即执行,而是需要在接收的函数内调用才会执行)