前言
- 每一次的回头从会看到不同的东西
- 不同的体会,更加深入的理解
先看看 定时器延时每一秒输出一个数字0-4 (看到别人的公众号发过)
- setTimeout 是一个延时执行的定时器(异步)
- 在var中使用,因为作用域相同所以最后赋值都是一样
- let的好处体现
- 闭包
- async await (异步中使用同步方法)
1 | // 错误用例 |
解决1 熟悉es6的都知道 let是个好东西
- 只要把var改let这个问题就解决了
- 因为let的i每一次都会生成一个作用域相隔开
1
2
3
4
5
6
7
8
9
10
11for (let i = 0; i < 5; i++) {
setTimeout(() => {
console.log(new Date,i)
}, 1000);
}
// 执行结果
2019-03-15T07:19:21.106Z 0
2019-03-15T07:19:21.110Z 1
2019-03-15T07:19:21.111Z 2
2019-03-15T07:19:21.111Z 3
2019-03-15T07:19:21.111Z 4
解决2 熟悉闭包的同学 这个也不是问题
- 每一次作为数据传进来不就可以了这也是一个不错的方法
1
2
3
4
5
6
7
8
9
10
11
12
13for (var i = 0; i < 5; i++) {
(j => {
setTimeout(() => {
console.log(j);
}, 1000);
})(i)
}
// 执行结果
2019-03-15T07:21:58.003Z 0
2019-03-15T07:21:58.007Z 1
2019-03-15T07:21:58.007Z 2
2019-03-15T07:21:58.007Z 3
2019-03-15T07:21:58.007Z 4
看看上面好像真的成功的但是再看看输出的时间其实还是未能实现每一秒输出一个,所有的数据都是在同一时间被执行出来,那能不能解决呢?看看下一个方法
解决3 Es7 async await 实现同步(把异步的定时器限制住)
1 | const sleep = (timeountMS) => new Promise((resolve) => { |
数组去重复 (每一次看别人写的都比自己写的好学习起来)
- 三目运算符运用
- forEach
- concat 数组合并
- …arr es6解构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21// 多数组合并去重复
test = (arr, ...arr2) => {
// 先是合并数组
let array = arr.concat(...arr2);
// 定义一个对象存储
let obj = {}
// 新数组
let result = []
// 循环遍历
array.forEach(item => {
// 三目运算符 判断是对象中存有,没有就吧值设为真 并且添加如数组
// 这里为什么要是为真呢,如果出现数据是false的时候依然使用数据去存储这样就会出现问题了
obj[item] ? '' : (obj[item] = true) && result.push(item)
})
return result
}
let sum = test([1, 2, 3], [5, 6,2, 3], [4, 5,6, 2])
console.log(sum);
// 输出结果
[ 1, 2, 3, 5, 6, 4 ]
Es6版 set Map
- 随着 ES6 的到来,去重的方法又有了进展,比如我们可以使用 Set 和 Map 数据结构,以 Set 为例,ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值
set
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15var array = [1, 2, 1, 1, '1'];
function unique(array) {
return Array.from(new Set(array));
}
console.log(unique(array)); // [1, 2, "1"]
// 再次简化
function unique(array) {
return [...new Set(array)];
}
// 再简化
var unique = (a) => [...new Set(a)]Map
1
2
3
4function unique (arr) {
const seen = new Map()
return arr.filter((a) => !seen.has(a) && seen.set(a, 1))
}
Promise 异步/回调地狱/async await
Promise
- promise里面包含两个参数res,rej我喜欢用简写,一个是成功回调一个是失败回调
- 所以在我们调用时也是要输入两个回调函数的,一个成功执行,一个失败执行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22// 定义promisey异步函数
const sleep = (test) => new Promise((res,rej) => {
if (test == 1) {
res('成功')
} else if (test == 0) {
res('再次成功')
} else {
rej('失败了兄弟')
}
})
// 使用
// 调用传入参数 .then中有可以写入两个函数前面为成功的调用后面为失败时的调用
// 和上面是一一对应的
// 前面的参数等于 test 后面...then
sleep(1).then((data) => {
console.log(data); // 成功时获取到的数据
}, (err) => {
console.log(err); // 错误时获取到的错误返回
})
// 输出结果
成功
Promise 回调地狱
- 很多时候我们都想在这个执行完毕后再去执行另外一个操作
- 在不影响后面的操作时,我们想到了使用Promise 异步
- 但是我们还不满足我们想在这个操作执行完毕再去执行另外一个操作
- 这个时候我们就会一个套一个的函数去写,这样就会似得代码非常的繁琐
- Promise中实现回调地狱解决这个问题
- 升级上面这个回调方法,实现回调地狱
- 在.then的后面再加.then方法就可以了
- 可以无限的去套用
- 虽然每个都有err但是只是输出报错没有去处理,回调地狱还是会往下走
- 后面的都会出错
1
2
3
4
5
6
7
8
9
10sleep(1).then((data) => {
console.log(data); // 成功时获取到的数据
return sleep(2) // 再次的执行异步函数
}, (err) => {
console.log(err); // 错误时获取到的错误返回
}).then((data)=> { // 继续用.then接受
console.log(data) // 再次成功
},(err) => {
console.log(err)
})
- catch属性解决你一切烦恼也不需要写那么多次err的错误处理
- catch 的作用: 如果前面有任何的 Promise 执行失败,则立即终止所有 promise 的执行,并 马上进入 catch 去处理 Promise中 抛出的异常;
1
2
3
4
5
6
7
8sleep(1).then((data) => {
console.log(data); // 成功时获取到的数据
return sleep(2) // 再次的执行异步函数
}).then((data)=> { // 继续用.then接受
console.log(data) // 再次成功
}).catch((err) => {
})
async/await (axios封装调用中很常使用)
- 其实在我们很多的前端业务请求时也是使用的异步操作
- 例如我们前端在请求后端api时,这个过程我们需要作为一个异步去操作不影响其他业务的操作
- 但是这个作为异步,可是数据总不是异步把所以数据得同步的获取
- es7就帮了我们很大的忙,因为await起到同步阻挡的作用
1
2
3
4
5
6
7
8var test = async() => { // 声明即执行的 async 函数表达式
let abc = await sleep(1);// 都是异步操作唯独到这里被卡住了,要等待数据的返回才会去执行后面
console.log(abc);
console.log('这个永远不会在前面');
}
test()
console.log('这个百分之99的机会都是在前面,还有那个一估计是内存卡了');
判断是否是一个数组(最近刚用过)
- Array.isArray
- 这个是我在做项目的时候想要判断是否是数组的时候上网查到的方法(数据过滤),用起来挺方便的
- 返回值是boolean
1
2const arr=[1,2,3];
Array.isArray(arr) // 是返回 true 不是返回false
- instanceof
- 在网上好像说这个不太严谨,忘记了是什么了找不到那个文章
1
2
3
4
5var isArray = function(obj) {
return obj instanceof Array;
};
var arr = '[{ id: 1 }]';
console.log(isArray(arr));
对象/数组互转
对象转数组
只取内容加入数组
1
2
3
4
5
6var arr = []
for (let i in obj) {
arr.push(obj[i]); //属性
//arr.push(obj[i]); //值
}
console.log(arr); // [ 5, 8, 4, 6 ]拆分为多个对象存入数组
1
2
3
4
5
6
7var arr = []
for (let i in obj) {
let o = {};
o[i] = obj[i];
arr.push(o)
}
console.log(arr); // [ { '未完成': 5 }, { '已完成': 8 }, { '待确认': 4 }, { '已取消': 6 } ]
数组转对象
1 | let obj = {}; |
数组的升序和降序
- 这个挺有意思的很多算法题里面都会用到,一开始我还不懂这个啥意思哎
- sort 排序,再升入我就不是很会了
- 要实现排序必须要有的条件就是要实现排序函数先
- 如果想按照其他标准进行排序,就需要提供比较函数,该函数要比较两个值,然后返回一个用于说明这两个值的相对顺序的数字。比较函数应该具有两个参数 a 和 b,其返回值如下:
若 a 小于 b,在排序后的数组中 a 应该出现在 b 之前,则返回一个小于 0 的值。
若 a 等于 b,则返回 0。
若 a 大于 b,则返回一个大于 0 的值。
1 | // 升序: |
说了排序就看看冒泡排序/快速排序
冒泡排序
- 声明一个done作为表示判断,这个也是我看别人写才想到的
- 主要是用来在对比没有任何一次遍历时位置的更改,说明排序已经结束了无需在做后面的排序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21var arr = [3, 4, 1, 2];
function bubbleSort (arr) {
var max = arr.length - 1;
for (var j = 0; j < max; j++) {
// 声明一个变量,作为标志位
var done = true;
for (var i = 0; i < max - j; i++) {
if (arr[i] > arr[i + 1]) {
var temp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = temp;
done = false;
}
}
if (done) {
break;
}
}
return arr;
}
console.log(bubbleSort(arr));
快速排序
- 这里面有递归的思想,然而我用断点去看把自己都绕进去了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22var quickSort = function(arr) {
if (arr.length <= 1) {
return arr;
}
var pivotIndex = Math.floor(arr.length / 2);
var pivot = arr.splice(pivotIndex, 1)[0];
var left = [];
var right = [];
for (var i = 0; i < arr.length; i++) {
if (arr[i] < pivot) {
left.push(arr[i]);
} else {
right.push(arr[i]);
}
}
return quickSort(left).concat([pivot], quickSort(right));
};
var aa = quickSort([3, 2, 5, 77, 32, 3, 1, 3, 4, 5, 2, 3])
console.log(aa);
上面出现了递归,就看看递归吧
第一个递归
- 递归:函数中调用函数自己,此时就是递归,递归一定要有结束的条件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18var i = 0;
function f1() {
i++;
if (i < 5) { // 限制小于5都会再执行一次f1函数
f1();
}
console.log("从前有个山,山里有个庙,庙里有个和尚给小和尚讲故事:");
}
f1();
// 输出结果
从前有个山,山里有个庙,庙里有个和尚给小和尚讲故事:
从前有个山,山里有个庙,庙里有个和尚给小和尚讲故事:
从前有个山,山里有个庙,庙里有个和尚给小和尚讲故事:
从前有个山,山里有个庙,庙里有个和尚给小和尚讲故事:
从前有个山,山里有个庙,庙里有个和尚给小和尚讲故事:
来个小案例让你知道递归的厉害 (看了这个再回头看上面的快速排序你就和觉得开窍了很多)
递归实现:n个数字的和,5 计算 1+2+3+4+5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31//函数的声明
function getSum(x) {
// 判断条件就是在这只要到1就停止返回1
if (x == 1) {
return 1;
}
// 每一次都是自身 + 函数调用小于自身的1
return x + getSum(x - 1);
}
//函数的调用
console.log(getSum(5));
/*
*
* 执行过程:
* 代码执行getSum(5)--->进入函数,此时的x是5,执行的是5+getSum(4),此时代码等待
* 此时5+getSum(4),代码先不进行计算,先执行getSum(4),进入函数,执行的是4+getSum(3),等待, 先执行的是getSum(3),进入函数,执行3+getSum(2),等待,先执行getSum(2),进入函数,执行 2+getSum(1);等待, 先执行getSum(1),执行的是x==1的判断,return 1,所以,
* 此时getSum(1)的结果是1,开始向外走出去
* 2+getSum(1) 此时的结果是:2+1
* 执行:
* getSum(2)---->2+1
* 3+getSum(2) 此时的结果是3+2+1
* 4+getSum(3) 此时的结果是4+3+2+1
* 5+getSum(4) 此时的结果是5+4+3+2+1
*
* 结果:15
*
*
*
* */求一个数字各个位数上的数字的和: 123 —>6 —1+2+3
1
2
3
4
5
6
7
8function getEverySum(x) {
if(x<10){
return x;
}
//获取的是这个数字的个位数 然后下一次的时候除去
return x%10+getEverySum(parseInt(x/10));
}
console.log(getEverySum(1364));求斐波那契数列
1
2
3
4
5
6
7function getFib(x) {
if(x==1||x==2){
return 1
}
return getFib(x-1)+getFib(x-2);
}
console.log(getFib(12));