前端知识点总结2

205 阅读6分钟

1. reduce方法

语法: arr.reduce(callback,[initialValue])

callback:执行数组中每个值的函数,包含四个参数
    1.previousValue(上一次调用回调返回的值,或者是提供的初始值initialValue)
    2.currentValue(数组中当前被处理的元素)
    3.index(当前元素在数组中的索引)
    4.array(调用 reduce 的数组)
initialValue:(作为第一次调用 callback 的第一个参数。)
例1: var arr = [1,2,3,4];
    var sum = arr.reduce(function(prev,cur,index,array){
        console.log(prev,cur,index);
        return prev+cur;
    });
    console.log(arr,sum);
打印结果:
    1,2,1
    3,3,2
    6,4,3
    [1,2,3,4],10
// 第一次index值是从1开始的,第一次的prev是数组中第一个值,数组长度为4,但是reduce循环3次;

例2: var arr = [1,2,3,4];
    var sum = arr.reduce(function(prev,cur,index,array){
        console.log(prev,cur,index);
        return prev+cur;
    },7);//此处增加初始值
    console.log(arr,sum);
打印结果;
    7 1 0
    8 2 1
    10 3 2
    13 4 3
    [1,2,3,4],17
// 此处index是从0开始的,第一次的prev为是我们设置的初始值7,循环四次;

结论:如果没有设置initialValue初始值,reduce则会从index=1开始执行callback,跳过第一个索引,如果提供initialValue,从索引0开始。如果这个数组为空,要是我们设置了初始值就不会报错.

2. 数组降维

forEach 递归降维

const oldArr = [
  1,
  [
    2, [3],
    [4, 5, 6],
    [7, 8, 9],
    10,
    11,
  ],
  12,
  13,
  14,
  [15, 16, 17],
];

const newArr = [];

const ergodic = (arr) => {
  arr.forEach((item) => {
    if (Array.isArray(item)) {
      ergodic(item);
    } else {
      newArr.push(item);
    }
  })
}

ergodic(oldArr, newArr);

console.log(newArr);
// [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 ]

方式二:

const oldArr = [
  1,
  [
    2, [3],
    [4, 5, 6],
    [7, 8, 9],
    10,
    11,
  ],
  12,
  13,
  14,
  [15, 16, 17],
];

function flatten(arr) {
    return arr.reduce(function(prev,item){
        return prev.concat(Array.isarry(item)?flatten(item):item)
    },[])
}
console.log(flatten(oldArr))

3.Event Loop

这种主线程从 “任务队列” 中读取执行事件,不断循环重复的过程,就被称为 事件循环(Event Loop)

js运行机制
1.所有同步任务都在主线程上执行,形成一个 “执行栈”(execution context stack)。
2.主线程之外,存在一个 “任务队列”(task queue),在走主流程的时候,如果碰到异步任务,那么就在 “任务队列” 中放置这个异步任务。
3.一旦 “执行栈” 中所有同步任务执行完毕,系统就会读取 “任务队列”,看看里面存在哪些事件。那些对应的异步任务,结束等待状态,进入执行栈,开始执行。
4.主线程不断重复上面三个步骤
JavaScript的异步任务
宏任务(Macrotask):script(整体代码)、setTimeout、setInterval、
XMLHttpRequest.prototype.onload、I/O、UI 渲染。
微任务(Microtask):Promise,MutationObserver。
// 位置 1
setTimeout(function () {
  console.log('timeout1');
}, 1000);

// 位置 2
console.log('start');

// 位置 3
Promise.resolve().then(function () {
  // 位置 5
  console.log('promise1');
  // 位置 6
  Promise.resolve().then(function () {
    console.log('promise2');
  });
  // 位置 7
  setTimeout(function () {
    // 位置 8
    Promise.resolve().then(function () {
      console.log('promise3');
    });
    // 位置 9
    console.log('timeout2')
  }, 0);
});

// 位置 4
console.log('done');

1.首先分清宏任务和微任务,先碰到script(整体代码),【位置 1】属于宏任务放到任务队列中,待会执行。
2.【位置2】是script(整体代码)无阻碍,直接执行。
3.【位置 3】属于微任务,暂时标记,走完script(整体代码)之后,优先执行微任务,再执行宏任务。
4.【位置4】是script(整体代码)的无阻碍代码,直接执行。

这样,第一波步骤执行了【位置2】start和【位置4】的done
接着上面我们走完了第一遍代码,然后现在这一步先走 script(整体代码)下的微任务【位置3】 1.碰到【位置 5】无阻碍代码,直接执行。
2.【位置6】是微任务,暂时标记。等执行完【位置3】整体代码后优先执行它。
3.【位置7】是宏任务,加入任务队列。看他和【位置1】谁先执行。
4.执行完【位置3】发现里面有【位置6】微任务直接执行输出。

到这一步已经走完了微任务。接着宏任务,【位置 1】和【位置 7】都被丢到任务队列了,是不是【位置 1】先走呢?

答案;不是! 各个环境都有自己的流程。Chrome控制台打印的话,那就是先【位置 7】,然后是【位置1】。

结果就是:

start
done
promise1
promise2
timeout2
promise3
timeout1

增加练习:

console.log("script start");

setTimeout(function() {
  console.log("setTimeout---0");
}, 0);

setTimeout(function() {
  console.log("setTimeout---200");
  setTimeout(function() {
    console.log("inner-setTimeout---0");
  });
  Promise.resolve().then(function() {
    console.log("promise5");
  });
}, 200);

Promise.resolve()
  .then(function() {
    console.log("promise1");
  })
  .then(function() {
    console.log("promise2");
  });
Promise.resolve().then(function() {
  console.log("promise3
  ");
});
console.log("script end");

答案:
script start
script end
promise1
promise3
promise2
setTimeout---0
setTimeout---200
promise5
inner-setTimeout---0

最后再看一个示例

setTimeout(function() {
  console.log(4);
}, 0);

const promise = new Promise(function executor(resolve) {
  console.log(1);
  for (var i = 0; i < 10000; i++) {
    i == 9999 && resolve();
  }
  console.log(2);
}).then(function() {
  console.log(5);
});

console.log(3);

输出结果:

1
2
3
5
4

解析答案不是 3 1 2 5 4的原因:
promise的特性;

  • promise是有兼容性问题的,node环境下默认支持,还可以下载相应插件来解决兼容性问题
  • promise是有三种状态的,等待态pending / 成功态resolved / 失败态rejected
  • promise的状态是可以转换的,可以从pending -> resolved 或 pending -> rejected,但是resolved不能转换为rejected/pending,rejected不能转换为resolved/pending,简而言之即状态只会更改一次
promise 构造函数的第一个参数是executor
let promise = new Promise(function(resolve,reject){
    console.log('我是会立即执行的');
})
promise.then(()=>{
    //成功的回调
},()=>{
    //失败的回调
})
  • executor默认在new的时候自动执行。
  • 每个promise实例都有then方法
  • then方法中有两个参数,即成功/失败的函数。

4.script 引入方式

1.html静态<script>引入;
2.js动态引入<script>;
3.<script defer> 延迟加载,元素解析完成后加载;
4.<script async> 异步加载,但执行时会阻塞元素渲染;

5.输出以下结果

var a = [0,1,2,3]
console.log(a.push(4))  // 5 
//原因:push方法可向数组的末尾添加一个或多个元素
//,并返回新的长度
console.log(a) // [0,1,2,3,4]

6.输出结果


function asd(count){
    return {
        cal:function(){
            return ++count;
        }
    }
}
var obj = asd(5);
console.log(obj.cal()) // 6
console.log(obj.cal()) // 7
console.log(obj.cal()) // 8

7.统计字符串中出现最多的字母和次数

var str = 'abcdasabdsa';
var obj = {};
for(var i = 0;i<str.length;i++){
    var current = str.charAt(i);//获取当前位置的元素
    if(obj[current]){
        obj[current]++;
    }else{
      obj[current] = 1;

    }
}
console.log(obj)//{a: 4, b: 2, c: 1, d: 2, s: 2}

var maxStr = null;
var max = 0;
for(var j in obj){
    if(obj[j] > max){
        max = obj[j];
        maxStr = j;
    }
}
console.log('出现字符串最多的次数:'+ max)
console.log('出现最多次数的字母:'+ maxStr)

8.格式化金钱,每千分位加逗号

1.
formatPrice('100978');
function formatPrice(str){
    var s = '';
    var count = 0;
    for(var i = str.length -1;i>=0;i--){
        s = str[i]+s;
        count++;
        if(count % 3 == 0 && i != 0){
            s = ','+s;
        }
    }
    console.log(s)
    return s;
}
2.
console.log(format('908887'))
function format (str){
    return str.replace(/(\d)(?=(?:\d{3})+$)/g,'$1,');
}

9.统计数组中出现的次数对象

var arr = [23,7,9,23,7,6,7,8,9];
var result = arr.reduce(function(prev,curr){
     prev[curr] ? prev[curr]++ :(prev[curr]=1)
     return prev
},{})
console.log(result) //{6: 1, 7: 3, 8: 1, 9: 2, 23: 2}