1. 尾调用
指某个函数的最后一步是调用另一个函数,只要最后一步不是调用函数,就不属于尾调用。
例如:
function f(x){
return g(x);
}
2. 尾递归
函数调用自身,称为递归。如果尾调用自身,就称为尾递归。递归好用内存较大,容易"栈溢出"错误,而尾递归只存在一个调用记录,所以永远不会发生"栈溢出"错误。
例如:
function factorial(n, total) {
if (n === 1) return total;
return factorial(n - 1, n * total);
}
factorial(5, 1)
3. map数据类型(key,value模式)
map是一组键值对的结构,具有极快的查找速度。
let map = new Map(['张三',67],['李四',89],['王五',92])
map.set('赵六', 67); // 添加新的key-value
map.has('赵六'); // 是否存在key '赵六' => true
map.get('赵六'); // 取值:=>67
map.delete('赵六'); // 删除key '赵六'
map.clear() //清空所有
1.生成 keys 的数组
[...map.keys()]
2.生成 values 的数组
[...map.values()]
3.生成键值对的数组
[...map.entries()] // [[1,"xxx"], [2, "yyy"]]
4. set数据类型(key)
一组key的集合,但不存储value。而且key不能重复,Set 没有 map, filter,需要先转换成为数组。
set本身是一个构造函数 把 Set 转成 Array
1.Array.from
2.拓展运算符 [...set]
var set = new Set([1, 2, 3, 3, '3']);
set = {1, 2, 3, "3"}
3和'3'不是相同元素
set.add(3) //增加新的key,如果重复添加不会生效
Set 常用于数组去重;Map 是为了解决对象非字符串不能作为 key 的问题
5. for in,for of,forEach,map,filter,find
for in
遍历对象,for...in循环不仅遍历数字键名,还会遍历手动添加的其他键,甚至包括原型链上的键。
let obj = {
name:"张三",
age:21,
work:"前端"
}
for (let index in obj) {
console.log("key为---",index,"val为---",obj[index])
}
//输出 key为---name val为---张三
for of
可以与break、continue和return配合使用,只循环集合本身的元素
var a = ['A' , 'B' , 'C'];
a.name = 'Hello';
for(var x of a) {
//只循环集合本身的元素
console.log('A','B', 'C')
}
foreach(不生成新数组,也不改变原数组)
无法跳出循环,break命令或return命令都不能奏效。 会从头到尾对数组里的每个元素遍历一遍,他不会生成新数组,也不改变原数组,回调函数接收三个值,分别是 数组的元素,索引和当前数组
let arr = ["a","b","c","d"]
arr.forEach((el,index,array) => {
if(el == "b" ) return
console.log(el,index,array)
})
在上边的例子中我加了一个判断,如果满足元素等于b,return出去,按理说遍历时满足这个条件后边就不遍历了,但是foreach不会,他会接着向下进行把每个元素遍历一遍。
map(不修改原数组,返回新数组)
和foreach类似,map也会把数组的每一项都遍历一遍,他会返回一个新数组,但是原数组保持不变,值得注意的是,map不会对空数组进行检测
let arr = [1,2,3,4,5]
let b = arr.map((el,val,array) => {
return el = el*2
})
//输出 [2,4,6,8,10]
filter(不修改原数组,返回新数组)
filter为过滤的意思,也就是说它会把满足条件的元素拿出来形成一个新的数组
let arr = [1,2,3,4,5,6,7,8,9]
let result = arr.filter(el => {
return el % 2 == 0
})
//输出 [2,4,6,8]
巧妙的运用filter去除数组中重复的元素:
let phone = ['苹果','锤子','三星','华为','锤子','苹果','小米','锤子']
let result = phone.filter((el,index,arr) => {
return arr.indexOf(el) == index
})
//输出 ["苹果", "锤子", "三星", "华为", "小米"]
find(不修改原数组,返回查找到的值)
array.find(function(currentValue, index, arr),thisValue),其中currentValue为当前项,index为当前索引,arr为当前数组,thisValue为匹配值
1.find() 方法返回通过测试(函数内判断)的数组的第一个元素的值。
2.如果没有符合条件的元素返回 undefined
3.find() 对于空数组,函数是不会执行的。
4.find() 并没有改变数组的原始值。
let test = [1, 2, 3, 4, 5];
let a = test.find(item => item > 3);
console.log(a); //4,查找到第一个匹配的就不在继续查找
let b = test.find(item => item == 0);
console.log(b); //undefined
6. Object.assign(targetObj1(目标对象), sourceObj1(源), sourceObj2(源));
如果目标对象有重名的会覆盖前面的属性
let targetObj1 = { a: 1 };
let sourceObj1 = { b: 1 };
let sourceObj2 = { c: 3 };
Object.assign(targetObj1, sourceObj1, sourceObj11);
console.log(targetObj1); //输出 {a: 1, b: 1, c: 3}
4覆盖1,5覆盖2,因为它们在数组的同一位置,所以就对应位置覆盖了
console.log(Object.assign([1, 2, 3], [4, 5])); //输出[4,5,3]
可以合并多个对象
let target = {
a:33,
b:44
}
let sources = {
c:55,
d:66
}
const merge = (target, ...sources) => Object.assign(target, ...sources);
console.log(merge(target,sources)) // {a: 33, b: 44, c: 55, d: 66}
浅拷贝
let obj = {a:1,b:2}
let obj1 = Object.assign(obj,{c:4,d:5})
深拷贝
let obj1 = Object.assign({}, obj); // obj赋值给一个空{}
obj1.a = 3;
7. 扩展运算符(…)
用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中
let bar = { a: 1, b: 2 };
let baz = { ...bar }; // { a: 1, b: 2 }
const arr1 = [1, 2];
const arr2 = [...arr1]; // [1,2]
//扩展运算符可以与解构赋值结合起来,用于生成数组
const [first, ...rest] = [1, 2, 3, 4, 5];
first // 1
rest // [2, 3, 4, 5]
如果将扩展运算符用于数组赋值,只能放在参数的最后一位,否则会报错。
const [...rest, last] = [1, 2, 3, 4, 5]; // 报错
const [first, ...rest, last] = [1, 2, 3, 4, 5]; // 报错
扩展运算符还可以将字符串转为真正的数组
[...'hello']
// [ "h", "e", "l", "l", "o" ]