2024前端面试总结—JS篇(文档持续更新中。。。)

1、Event Loop(事件循环)机制

JS是单线程的非阻塞语言

为什么是单线程(如果js是多线程,那么两个线程同时对同一个Dom进行操作,一个增一个删,浏览器该如何执行?)

非阻塞(当代码需要执行一个异步操作,该操作不会立刻返回结果,主线程会挂起这个任务,再异步任务返回结果后再执行相应的回调)

2、原型链

每个函数都有一个属性prototype,这就是原型对象;如果我们拿这个函数通过new构造函数可以创建一个实例对象,这个实例对象自身会有一个指针(proto)指向它的构造函数的原型对象,这样再构造函数和实例对象之间就建立起了连接

使用原型链的作用

  • 避免代码冗余,公共的属性和方法可以放到原型对象中
  • 减少内存占用
  • 继承
  • propt (实例对象指向原型对象的指针,隐式原型,每个对象都有的属性)
  • prototype(构造函数的原型对象,显士原型,函数独有)

    在这里插入图片描述

3、操作数组的方法

索引方法名功能改变原数组返回内容用法
1push()在尾部添加元素返回数组的长度
2unshift()在头部添加元素返回数组的长度
3pop()在尾部删除元素返回删除的元素
4shift()在头部删除元素返回删除的元素
5slice()提取数组的一部分不会提取的新数组slice(开始位置,结束位置)提取内容不包含结束位置
6splice()删除数组的一部分返回删除的元素splice(开始位置,删除个数,插入元素)
7reverse()逆转放置元素位置返回逆转放置的数组
8sort()排序返回排序后的数组arr.sort((a,b)=>{ return a.key-b.key})
9join()将所有元素放入字符串字符串arr.join(‘/’) 什么都不加,用逗号分隔;只有引号是空白;
10for…in遍历数组更适合遍历对象,不建议遍历数组for( let value in arr){console.log(value, arr[value])}
11concat()连接两个数组不会
12forEach()遍历本身不会,如果修改了属性则会(可对数组进行深拷贝)无返回值arr.forEach((元素,索引,当前数组)=> {})
13map()遍历:本身不会,如果修改了属性则会(可对数组进行深拷贝)会返回新数组(需要加return否则是undefined)不会对空数组进行检测arr.map((元素,索引,当前数组)=> {})
14filter()按条件过滤不会新数组(满足条件项)arr.filter((value,index,arr)=>{return value>0})
15some()查找不会boolean如果所有元素都满足判断条件,则返回true,若所有元素都不满足判断条件,则返回falsearr.some(value=> value < 0)
16every()查找不会boolean此方法是将所有元素进行判断返回一个布尔值,如果所有元素都满足判断条件,则返回true,否则为falsearr.every((value,index,arr)=>{return value>0})
17indexOf()查找不会返回数组中某个指定的元素位置Array.indexOf(item,start)[NaN].indexOf(NaN) // -1
18includes查找不会返回一个Boolean[1, 2, 3].includes(2) //true; 返回布尔值,比indexOf更直观,对于NaN校验更准确
19lastIndexOf()查找不会可返回一个指定的元素在数组中最后出现的位置Array.lastIndexOf(item,start)
20fill()(ES6)用一个固定值填充返回新数组arr.fill(value, start, end)start–默认0;end–默认length
21find (ES6)查找不会返回满足条件的第一项(return)arr.find((value, index, arr)=> return value>0){} //两个参数,第二个为回调let param = [‘’].find((item)=>{// 同时检测多个字符串是否在当前内容中 return item==‘2’
22findIndex(ES6)查找不会返回满足条件的第一项的索引(return)arr.find((value, index, arr)=> return value>0){}//两个参数,第二个为回调
23reduce(return)numbers.reduce((preValue,currentValue)=>{return preValue + currentValue})//数组求和

4、数组遍历方法性能比较

  • 方法:通过一个时间函数,执行对应方法n次,计算时长
  • 结果:for循环遍历 < for…of遍历 < forEach遍历 < for…in遍历 < map遍历

5、深拷贝的方法

  • for 循环实现 ( for + push )
  • slice 方法 ( arr.slice(0) )
  • concat 方法 ( arr.concat() )
  • Es6的 … 扩展运算符 ( var […arrNew] = arr )
  • JSON.stringify()JSON.parse() (适用于对象的深拷贝,对象转为字符串后赋值给另一个变量)

6、数组去重的方法

  • for + for
  • for + indexOf
  • Set (Es6)
let arrList = [1,2,4,6,2,7,2]let arrListNew = Array.from(new Set(arrList))console.log(arrList)//[1, 2, 4, 6, 7]
  • filter + indexOf
let arrList = [1,2,4,5,2,1]let arrNew = arrList.filter((item,index,arr)=>{ return arr.indexOf(item)==index;})console.log(arrNew)

7、检验数组的方法(typeOf、instanceOf)

  • typeOf ( 返回一个字符串,如果检测数组返回 ‘object’ )
  • instanceof ( 返回一个布尔值,arr instanceof Array )
  • es5的 isArray (Array.isArray(arr))
  • 验证对象的构造函数 ( arr.constructor === Array
  • 检测对象的原型 ( Object.prototype.toString.call(arr)‘[object Array]’

8、数字精度处理(tiFixed、Number)

  • 简单的四舍五入*((0.1+0.2).toFixed(1);//0.3)有弊端:(2.445).toFixed(2)* IE显示2.45,但是chrome显示2.44
  • Math.round() 函数返回一个数字四舍五入后最接近的整数,但 2.445 * 100=244.49999999999997,不是244.5,Math.round(2.445 * 100) // 244
  • 先toPrecision取固定位数,parseFloat()解析字符串并返回浮点数
  • bigInt()
let test = '9999999999999999';let num = BigInt(test)console.log(num);//9999999999999999nconsole.log(String(num));//9999999999999999

9、This指向问题

  • this出现在全局函数中,指向window
  • this出现在严格模式中,永远不会指向window
  • 当某个函数为对象的某个属性时,在这个函数内部this指向这个对象
  • this出现在构造函数中,指向构造函数新创建的对象
  • 当一个函数被绑定事件处理函数时,this指向被点击的这个元素
  • this出现在箭头函数中时,this和父级作用域的this指向相同
  • 修改this的指向:

    – 使用call、apply、bind修改this指向

    – 使用new关键字改变this指向

10、节流和防抖(针对相应跟不上触发频率这类问题)

  • 节流:设置一个定时器,在固定时间段内多次点击只会执行一次
// 
  • 防抖:在固定时间段连续点击,会清除掉上次点击的定时器重新计时,最终只会执行最后一次的点击
const debounce = (function(){//防抖函数    let time = null;    return function(fn, sec){        clearTimeout(time);        time = setTimeout(fn, sec)    }})()// 滚动事件 window.addEventListener('scroll', ()=>{    debounce(()=>{         console.log(Math.random());     }) });
 fangdou() {      let num = Math.random();      this.times = new Date().getTime();      this.list.push(num);      if (!this.times_old) {        this.listAll.push(num);        console.log(this.list);        this.times_old = this.times;        this.list = [];      } else {        let res = this.times - this.times_old;        if (res > 1000) {          this.listAll.push(this.list[this.list.length - 1]);          console.log(this.list);          if (this.timer) {            clearTimeout(this.timer);          }          this.times_old = this.times;          this.list = [];        } else {          if (this.timer) {            clearTimeout(this.timer);          }          this.timer = setTimeout(() => {            this.listAll.push(num);            console.log(this.list);            this.times_old = this.times;            this.list = [];          }, 1000 - res);        }      }    },

11、垃圾回收机制

  • 垃圾指什么:指的是一些不再使用的内存;
  • 回收指什么:针对不再使用的内存,需要进行释放,以便再次使用;
  • 什么是垃圾回收:在JS中有一套自动的回收机制,通过一些回收算法,找出不再使用的引用的变量或者属性,由JS引擎按照固定周期释放其所占内存;
  • 常见的算法策略:
    • 引用计数算法
      • 思路:记录每个变量使用次数,当被引用时标记 +1,当被其它值覆盖引用标记 -1,变为0时被垃圾回收器收回;
      • 优点:引用计数为0时,发现垃圾立即回收;最大限度减少程序暂停;
      • 缺点:无法回收循环引用的对象;控件开销比较大;
    • 标记清除算法
      • 思路:垃圾回收器在运行时会假设所有对象都是垃圾,全部标记为0;然后从根对象开始遍历,把不是垃圾的标记为1;清除掉所有标记为0的垃圾,回收其内存;然后把所有节点都改为0,等待下一次回收;
      • 优点:实现简单;能够回收循环引用的对象;是V8引擎使用最多的算法;
      • 缺点:在清除对象后剩余对象的内存的位置不变,出现一些内存碎片,需要重新分配;
    • 标记整理算法
      • 在标记结束后将不需要清理的对象向一侧移动,最后清理边界的内存
    • 分代回收算法
      • V8引擎主要使用标记清除算法和分代回收算法;
  • 自动回收什么时候执行:全局变量在关闭页面才会回收,局部变量在调用函数完之后就会回收;
  • 针对闭包:可以通过将内部变量置空null来释放内存;

12、闭包

13、bind、apply、call

(文档持续更新中。。。文中如有错误或者描述不清的地方,欢迎各位大佬指正;旨在巩固前端基础,相互进步!)

本文来自网络,不代表协通编程立场,如若转载,请注明出处:https://net2asp.com/54be3736ad.html