【面试题】2024前端面试知识体系_pxtpc


  • 不适用-对象方法
const obj = {
 name: '哪吒,B站,算法猫叔',
 getName: () => {
  returnthis.name
 }
}
console.log(obj.getName())
复制代码
  • 不适用-原型方法
const obj = {
 name: '哪吒,B站,算法猫叔'
}
obj.__proto__.getName = () => {
 returnthis.name
}
console.log( obj.getName() )
复制代码
  • 不适用-构造函数
constFoo = (name, age) => {
 this.name = name
 this.age = age
}
const f = newFoo('张三', 20)
// 报错 Foo is not a constructor复制代码
  • 不适用-动态上下文中的回调函数
const btn1 = document.getElementById('btn1')
btn1.addEventListener('click', () => {
 // console.log(this === window)this.innerHTMl = 'clicked'
})
复制代码
  • 不适用-Vue生命周期和method : vue组件本质上一个 JS 对象

  • React 组件(非Hooks)本质上是一个 es6 class,class里面适用箭头函数没问题

{
 data() { return { name:  '哪吒,B站:算法猫叔' } },
 methods: {
  getName: () => {
   // 报错 Cannot read properties of undefined (reading 'name')returnthis.name
  },
  // getName() {//  return this.name // 正常// }
 },
 mounted: () => {
  // 报错
 },
 // mounted() {//  正常// }
}
复制代码

JS中for-in和for-of有什么区别

for of 去遍历可以generator

const arr = [10, 20, 30]
for (let val of arr) {
 console.log(val); // 值
}

const str = 'abc'for (let c of str) {
 console.log(c);
}

functionfn() {
 for (let arg ofarguments) {
  console.log(arg)
 }
}
fn(100, 200, 'aaa')

const pList  = document.getElementsByTagName('p')
// querySelectorAll('p')for (let p of pList) {
 console.log(p)
}
复制代码
  • 遍历对象: for … in 可以,for … of 不可以

  • 遍历Map Set:for…of 可以,for…in 不可以

  • 遍历generator:for…of 可以,for … in 不可以

对象,数组,字符串可枚举的,就可以使用for ... in 循环
const obj1 = { x: 100 }
Object.getOwnPropertyDescriptors(obj1)
x:
configurable: trueenumerable: truevalue: 100writeable: true复制代码
  • 可枚举 vs 可迭代

for … in 用于可枚举数据,如对象,数组,字符串,得到key

for … of 用于可迭代数据,如数组,字符串,Map,Set,得到value

for-await-of有什么作用

for await…of 用于遍历多个Promise

functioncreatePromise(val) {
 returnnewPromise((resolve) => {
  setTimeout(() => {
   resolve(val)
  }, 1000)
 })
}

(asyncfunction () {
 const p1 = createPromise(100)
 const p2 = createPromise(200)
 const p3 = createPromise(300)
 // const res1 = await p1// console.log(res1)// const res2 = await p2// console.log(res2)// const res3 = await p3// console.log(res3)const list = [p1, p2, p3]
 // Promise.all(list).then(res => console.log(res))forawait (let res of list) {
  console.log(res)
 }
})()
复制代码

offsetHeight - scrollHeight - clientHeight区别

盒子模型: width, height, padding, border, margin, box-sizing

offsetHeight offsetWidth : border + padding + content

clientHeight clientWidth: padding + content

scrollHeight scrollWidth: padding + 实际内容尺寸

HTMLCollection和NodeList有什么区

  • DOM是一颗树,所有节点都是Node

  • Node是Element的基类

  • Element是其他HTML元素的基类,如HTMLDivElement

const p1 = document.getElementById('p1')
classNode {}

// documentclassDocumentextendsNode {}
classDocumentFragmentextendsNode {}

// 文本和注释classCharacterDataextendsNode {}
classCommentextendsCharacterData {}
classTextextendsCharacterData {}

// elemclassElementextendsNode {}
classHTMLElementextendsElement {}
classHTMLDivElementextendsHTMLElement {}
classHTMLInputElementextendsHTMLElement {}
复制代码
  • HTMLCollection 是 Element 的集合

  • NodeList 是 Node 集合

<p id="p1">
 <b>node</b> vs <em>element</em>
</p>

<script>const p1 = document.getElementById('p1')
 console.log(p1.children)
 
 console.log(p1.childNodes)
 // [b,text,em,comment]</script>复制代码

划重点:

  • 获取 Node 和 Element 的返回结果可能不一样

  • 如 elem.childNodes 和 elem.children 不一样

  • 前者包含Text和Comment节点,后者不会

类数组 变成 数组

const arr1 = Array.from(list)
const arr2 = Array.prototype.slice.call(list)
const arr3 = [...list]
复制代码

Vue中computed和watch有什么区别

  • computed 用于计算产生新的数据

  • watch 用于监听现有数据

watch: {
 name(newValue, oldValue) {
  console.log('watch name', newValue, oldValue)
 }
},
computed: {
 userInfo() {
  returnthis.name + this.city
 }
}
复制代码

computed有缓存 watch没有缓存

Vue组件通讯有几种方式

props和$emit

$parent

自定义事件

$refs

$attr

provide/inject

vuex

---

$attrs $listeners

vue3 移除 $listeners

上一级没有接收到的

props: ['x'], // $attrsemits: ['getX'], // $listenersObject.keys(this.$attrs)

<l3 v-bind="$attrs"></l3>

dom结点: inheritAttrs: false

---

this.$parentthis.$refsprovide: {
 info: 'aaa'
}

provide() {
 return {
  info: computed(() =>this.name)
 }
}

---

父子组件

上下级组件(跨多级)通讯

全局组件
复制代码

Vuex中action和mutation有什么区别

mutation: 原子操作,必须同步代码

action: 可包含多个mutation;可包含异步代码

JS严格模式有什么特点

'use strict'// 全局开启functionfn() {
 'use strict'// 某个函数开启
}
复制代码
  • 全局变量必须先声明

  • 禁止使用 with

  • 创建eval作用域

  • 禁止this指向window

  • 函数参数不能重名

JS内存垃圾回收用什么算法

垃圾回收 GC

什么是垃圾回收?

functionfn1() {
 const a = 'aa'console.log(a)
 
 const obj = { x: 100 }
 console.log(obj)
}
fn1()
复制代码
functionfn2() {
 const obj = { x: 100 }
 window.obj = obj
}
fn2()


functiongetDataFns() {
 const data = {} // 闭包return {
  get(key) {
   return data[key]
  },
  set(key, value) {
   data[key] = value
  }
 }
}
const { get, set } = getDataFns()
set('x', 100)
get('x')
复制代码
引用计数(之前)

// 对象被 a 引用let a = { x: 100 }
let a1 = a
a = 10
a1 = null// 循环引用functionfn3() {
 const obj1 = {}
 const obj2 = {}
 obj1.a = obj2
 obj2.a = obj1
}
fn3()

// ie6-7 内存泄漏的 bugvar div1 = document.getElementById('div1')
div1.a = div1
div1.someBigData = {}

标记清除(现代)
// JS 根 window复制代码

JS闭包是内存泄漏吗

闭包的数据是不可以被垃圾回收的

如何检测JS内存泄漏

检测内存变化

const arr = []
for (let i = 0; i < 10 * 10000; i++) {
 arr.push(i)
}

functionbind() {
 // 模拟一个比较大的数据const obj = {
  str: JSON.stringify(arr) // 简单的拷贝
 }
 window.addEventListener('resize', () => {
  console.log(obj)
 })
}

let n = 0functionstart() {
 setTimeout(() => {
  bind()
  n++
  
  // 执行 50 次if (n < 50) {
   start()
  } else {
   alert('done')
  }
 }, 200)
}

document.getElementById('btn1').addEventListener('click', () => {
 start()
})
复制代码

JS内存泄漏的场景有哪些

  1. 被全局变量,函数引用,组件销毁时未清除

  2. 被全局事件,定时器引用,组件销毁时未清除

  3. 被自定义事件引用,组件销毁时未清除

JS内存泄漏的场景有哪些-扩展-WeakMap和Weak

// 标记清除算法const data = {}
functionfn1() {
 const obj = { x: 100 }
 data.obj = obj
}
fn1()
复制代码
const map = newMap()
functionfn1() {
 const obj = { x: 100 }
 map.set('a', obj)
}
fn1()
复制代码
// WeakMap WeakSet 弱引用
<script>
 const wMap = newWeakMap(); // 弱引用functionfn1() {
  const obj = { x: 100 }
  wMap.set(obj, 100) // WeakMap的key,只能是引用类型
 }
 fn1()
 // WeakSet
</script>
复制代码

Ajax-Fetch-Axios三者有什么区别

  1. Ajax(Asynchronous Javascript and XML),一种技术统称

  2. Fetch,一个具体的原生API 浏览器原生API,用于网络请求 和XMLHttpRequest一个级别 Fetch语法更加简洁,易用,支持Promise

  3. Axios,是一个第三方库 最常用的网络请求lib 内部可用XMLHttpRequest和Fetch来实现

  4. lib(库)和API(原生的函数)的区别

  5. fetch 和 XMLHttpRequest 全局的API

用XMLHttpRequest实现Ajax

functionajax1(url, sucessFn) {
 const xhr = newXMLHttpRequest();
 xhr.open("GET", url, false);
 xhr.onreadystatechange = function () {
  // 这里的函数异步执行if (xhr.readyState == 4) {
   if (xhr.status == 200) {
    successFn(xhr.responseText);
   }
  }
 }
 xhr.send(null);
}

functionajax2(url) {
 returnfetch(url).then(res => res.json());
}
复制代码

请描述TPC三次握手和四次挥手

建立TCP连接


  1. 先建立连接(确保双方都有收发消息的能力)

  2. 再传输内容(如发送给一个get请求)

  3. 网络连接是TCP协议,传输内容是HTTP协议

  4. SYN SYN+ACK ACK

四次挥手-关闭连接


1.FIN ->
2.ACK <-
3.FIN <-
4.ACK ->
复制代码

HTTP跨域时为何要发送options请求

跨域请求


  1. 浏览器同源策略

  2. 同源策略一般限制Ajax网络请求,不能跨域请求server

  3. 不会限制

JSONP


// www.aaa.com网页
<script>
 window.onSuccess = function(data) {
  console.log(data)
 }
</script>
<scriptsrc="https://www.bbb.com/api/getData"></script>// https://www.bbb.com... 返回了一段字符串'onSuccess({ errno: 0, data: {} })'复制代码
// CORS 配置允许跨域(服务端)
response.setHeader("Access-Control-Allow-Origin", "http://localhost:8011") // 或者"*"
response.setHeader("Access-Control-Allow-Headers", "X-Requested-With")
response.setHeader("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS")
response.setHeader("Access-Control-Allow-Credentials", "true") // 允许跨域接收 cookie复制代码

options请求,是跨域请求之前的预检查;浏览器自行发起的,无需我们干预,不会影响实际的功能

浏览器和nodejs事件循环(EventLoop)有什么

单线程和异步


  1. JS是单线程的(无论在浏览器还是nodejs)

  2. 浏览器中JS执行和DOM渲染共用一个线程

  3. 异步 宏任务 和 微任务 宏任务,如 setTimeout setInterval 网络请求 微任务,如 promise async / await 微任务在下一轮DOM渲染之前执行,宏任务在之后执行 微任务: MutationObserver 监听DOM树的变化,Mutation observer 是用于代替 Mutation events 作为观察DOM树结构发生变化时,做出相应处理的API MutationObserver接口提供了监视对DOM树所做更改的能力。它被设计为旧的Mutation Events功能的替代品,该功能是DOM3 Events规范的一部分。

const p = document.createElement('p')
p.innerHTML = 'new paragraph'document.body.appendChild(p)

const list = document.getElementsByTagName('p')
console.log('length---', listh.length)

console.log('start')
// 渲染之后setTimeout(() => {
 const list = document.getElementsByTagName('p')
 console.log('length on timeout---', list.length) // 2alert('阻塞 timeout')
})
// 渲染之前Promise.resolve().then(() => {
 const list = document.getElementsByTagName('p')
 console.log('length on promise.then---', list.length) // 2alert('阻塞 promise')
})
console.log('end')
复制代码
// 同步任务 -> 异步任务 -> 宏任务// 微任务要比宏任务要快// Event Loop

<script>
 console.log('start')
 setTimeout(() => {
  console.log('timeout')
 })
 Promise.resolve().then(() => {
  console.log('promise then')
 ))
 console.log('end')

 // ajax(url, fn) // 300ms// Event Loop 继续监听// 宏任务 MarcoTask Queue// () => {//   console.log('timeout')// }// fn// DOM 渲染// 微任务 MicroTask Queue// () => {//   console.log('promise then')// }
</script>
复制代码

Nodejs异步


  1. Nodejs同样使用ES语法,也是单线程,也需要异步

  2. 异步任务也分:宏任务+微任务

  3. 但是,它的宏任务和微任务,分不同类型,有不同优先级

虚拟DOM(vdom)真的很快吗


  1. vdom: Virtual DOM,虚拟DOM 用JS对象模拟DOM节点数据

  2. 组件化 数据视图分离,数据驱动视图 只关注业务数据,而不用再关心DOM变化

  3. vdom并不快,js直接操作dom才是最快的 但”数据驱动视图“要有合适的技术方案,不能全部dom重建 vdom就是目前最合适的技术方案(并不是因为它快,而是合适)

遍历一个数组用for和forEach哪个更快


  • for更快

  • forEach每次都要创建一个函数来调用,而for不会创建函数

  • 函数需要独立的作用域,会有额外的开销

nodejs如何开启多进程,进程如何通讯-进程和线程的


进程 process vs 线程 thread 进程,OS 进行资源分配和调度的最小单位,有独立内存空间 线程,OS 进行运算调度的最小单位,共享进程内存空间 JS是单线程的,但可以开启多进程执行,如WebWorker js 不可以开启一个线程

为何需要多进程?

  1. 多核CPU,更适合处理多进程

  2. 内存较大,多个进程才能更好的利用(单进程有内存上限)

  3. 总之,“压榨”机器资源,更快,更节省 单个进程内存2G左右

nodejs如何开启多进程

// console.info(process.pid)const http = require('http')

const server = http.createServer()
server.listen(3000, () => {
 console.log('localhost: 3000')
})

console.info(process.pid)

// WebWorker 进程// forkconst http = require('http')
const server = http.createServer((req, res) => {
 if (req.url === '/get-sum') {
   console.info('主进程 id', process.id)
   
   res.end('hello')
 }
})
server.listen(3000, () => {
 console.info('localhost: 3000')
})

// cluster 进程复制代码
// 子进程,计算functiongetSum() {
 let sum = 0for (let i = 0; i < 10000; i++) {
  sum += i
 }
 return sum
}

process.on('message', data => {
 console.log('子进程 id', process.pid)
 console.log(‘子进程接受到的信息:', data)

 const sum = getSum()
 // 发送消息给主进程
 process.send(sum)
})
复制代码
const http = require('http')
const fork = require('child_process').forkconst server = http.createServer((req, res) => {
 if (req.url === '/get-sum') {
  console.info('主进程 id', process.pid)

   // 开启子进程const  computeProcess = fork('./compute.js')
  computeProcess.send('开始计算')

  computeProcess.on('message', data => {
    console.info('主进程接受到的信息:', data)
    res.end('sum is' + data)
  })

  computeProcess.on('close', () => {
    console.info('子进程因报错而退出')
    computeProcess.kill()
    res.end('error')
  })
 }
})

server.listen(3000, () => {
 console.info('localhost: 3000')
})
复制代码
const http = require('http')
const cpuCoreLength = require('os').cpus().lengthconst cluster = require('cluster')

if (cluster.isMaster) {
 for (let i = 0; i < cpuCoreLength; i++) {
  cluster.fork() // 开启子进程
 }
 cluster.on('exit', worker => {
  console.log('子进程退出')
  cluster.fork() // 进程守护
 })
} else {
 // 多个子进程会共享一个 TCP 连接,提供一份网络服务const server = http.createServer((req, res) => {
  res.writeHead(200)
  res.end('done')
 })
 server.listen(3000)
}
复制代码

开启子进程 child_process.fork 和 cluster.fork 使用 send 和 on 传递消息

请描述js-bridge的实现原理

  1. JS无法直接调用 native API

  2. 需要通过一些特定的“格式”来调用

  3. JS Bridge的常见实现方式

  4. 注册全局API

  5. URL Scheme

// 封装 JS-bridgeconst sdk = {
 invoke(url, data = {}, onSuccess, onError) {
   const iframe = document.createElement('iframe')
   iframe.style.visibility = 'hidden'document.body.appendChild(iframe)
   
   iframe.onload = () => {
    const content = iframe1.contentWindow.document.body.innerHTML
   }
 }
}
复制代码

requestIdleCallback和request

由React fiber引起的关注

  1. 组建树转换为链表,可分段渲染

  2. 渲染时可以暂停,去执行其他高优任务,空闲时再继续渲染

  3. 如何判断空闲? - requestIdleCallback

区别

  1. requestAnimationFrame 每次渲染完都会执行,高优

  2. requestIdleCallback 空闲时才执行,低优

<p>requestAnimationFrame</p>
<buttonid="btn1">change</button><divid="box"></div><script>const box = document.getElementById('box')
document.getElementById('btn1').addEventListener('click', () => {
 let curWidth = 100const maxWidth = 400functionaddWidth() {
  curWidth = curWidth + 3
  box.style.width = `${curWidth}px`if (curWidth < maxWidth) {
   window.requestIdleCallback(addWidth) // 时间不用自己控制
  }
 }
})
</script>复制代码
start
end
timeout
requestAnimationFrame
requestIdleCallback

window.onload = () => {

 console.info('start')
 setTimeout(() => {
  console.info('timeout')
 })
 // 宏任务,顺序交换也一样// 高优window.requestAnimationFrame(() => {
  console.info('requestAnimationFrame')
 })
 // 低优window.requestIdleCallback(() => {
  console.info('requestIdleCallback')
 })

 console.info('end')
}
复制代码

Vue每个生命周期都做了什么

  • beforeCreate 创建一个空白的Vue实例 data method 尚未被初始化,不可使用

  • created vue实例初始化完成,完成响应式绑定 data method都已经初始化完成,可调用 尚未开始渲染模板

  • beforeMount 编译模版,调用render生成vdom 还没有开始渲染DOM

$el null element没有

  • mounted 完成DOM渲染 组件创建完成 开始由“创建阶段”进入“运行阶段”

  • beforeUpdate data发生变化之后 准备更新DOM(尚未更新DOM)

  • updated data发生变化,且DOM更新完成 (不要在updated中修改data,可能会导致死循环)

  • beforeUnmount 组件进入销毁阶段(尚未销毁,可正常使用) 可移除,解绑一些全局事件,自定义事件

  • unmounted 组件被销毁了 所有子组件也都被销毁了

  • keep-alive组件 onActivated 缓存组件被激活 onDeactivated 缓存组件被隐藏

<keep-alive>
 <Child1v-if="num === 1"></Child1><Child2v-else></Child2>
</keep-alive>

// Child1 2created() {
 console.log() // keep-alive 中只创建
}
activated() {}
deactivated() {}

// 创建一次被缓存复制代码
child1 created
child1 activated
child2 created
child1 deactivated
child2 activated
child2 deactivated
child1 activated
复制代码
  • vue什么时候操作DOM比较合适 mounted和updated都不能保证子组件全部挂载完成 使用$nextTick渲染DOM

只有nextTick操作DOM才是最安全的

$nextTick
mounted() {
 this.$nextTick(function () {
  // 仅在整个视图都被渲染之后才会运行的代码
 })
}
复制代码
  • ajax 应该在那个生命周期? 有两个选择:created 和 mounted 推荐:mounted

  • vue3 Composition API 生命周期有何区别? 用setup代替了beforeCreate和created 使用Hooks函数的形式,如mounted改为onMounted()

import { onUpdated, onMounted } from'vue'exportdefault {
 setup() {
  onMounted(() => {
 
  })
  onUpdated(() => {
  
  })
 }
}
复制代码

Vue2和Vue3和React三者的diff算法有什么

介绍diff算法 diff算法很早就有

tree diff优化 只比较同一层级,不跨级比较 tag 不同则删掉重建(不再去比较内部的细节) 子节点通过key区分(key的重要性)

vue3最长递增子序列 vue2 双端比较 React 仅右移

Vue-router的MemoryHistory是什么

Hash, WebHistory, MemoryHistory( v4 之前叫做 abstract history)

移动端H5点击有300ms延迟,该如何解决

FastClick原理 监听touchend事件(touchstart touchend会先于click触发) 使用自定义DOM事件模拟一个click事件 把默认的click事件(300ms之后触发)禁止掉

最后

文章到这里就结束了,如果觉得对你有帮助可以点个赞哦

ated
child2 created
child1 deactivated
child2 activated
child2 deactivated
child1 activated
复制代码


* vue什么时候操作DOM比较合适 mounted和updated都不能保证子组件全部挂载完成 使用$nextTick渲染DOM


只有nextTick操作DOM才是最安全的



KaTeX parse error: Expected '}', got 'EOF' at end of input: …nted() { this.nextTick(function () {
// 仅在整个视图都被渲染之后才会运行的代码
})
}
复制代码


* ajax 应该在那个生命周期? 有两个选择:created 和 mounted 推荐:mounted


* vue3 Composition API 生命周期有何区别? 用setup代替了beforeCreate和created 使用Hooks函数的形式,如mounted改为onMounted()



import { onUpdated, onMounted } from’vue’exportdefault {
setup() {
onMounted(() => {

})
onUpdated(() => {

})
}
}
复制代码


## Vue2和Vue3和React三者的diff算法有什么


介绍diff算法 diff算法很早就有


tree diff优化 只比较同一层级,不跨级比较 tag 不同则删掉重建(不再去比较内部的细节) 子节点通过key区分(key的重要性)


vue3最长递增子序列 vue2 双端比较 React 仅右移


## Vue-router的MemoryHistory是什么


Hash, WebHistory, MemoryHistory( v4 之前叫做 abstract history)


## 移动端H5点击有300ms延迟,该如何解决


FastClick原理 监听touchend事件(touchstart touchend会先于click触发) 使用自定义DOM事件模拟一个click事件 把默认的click事件(300ms之后触发)禁止掉




### 最后

**文章到这里就结束了,如果觉得对你有帮助可以点个赞哦**



[外链图片转存中...(img-oT551lx8-1720114894056)]

  • 23
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值