2023年前端面试高频八股文(一)

△ 338 次 手写题库

△ 200 次 Vue 中双向数据绑定的实现原理是怎样的?

Vue2

  • new Vue() 首先执行初始化,对 data 执行响应化处理,这个过程发生 Observe 中
  • 同时对模板执行编译,找到其中动态绑定的数据,从 data 中获取并初始化视图,这个过程发生在 Compile 中
  • 同时定义⼀个更新函数和 Watcher,将来对应数据变化时 Watcher 会调用更新函数
  • 由于 data 的某个 key 在⼀个视图中可能出现多次,所以每个 key 都需要⼀个管家 Dep 来管理多个 Watcher
  • 将来 data 中数据⼀旦发生变化,会首先找到对应的 Dep,通知所有 Watcher 执行更新函数

点击显示代码👇

js 复制代码
Object.defineProperty(obj, key, {
  enumerable: true,
  configurable: true,
  get: function reactiveGetter() {
    // ...
    if (Dep.target) {
      // 收集依赖
      dep.depend();
    }
    return value;
  },
  set: function reactiveSetter(newVal) {
    // ...
    // 通知视图更新
    dep.notify();
  },
});

Vue3

改用 ES6 的 Proxy 解决以前使用 Object.defineProperty 所存在的一些问题

  • 对象新增属性为什么不更新 - $set
  • 数组变异 - 手动 observer,重写数组的方法

△ 188 次 什么是闭包,什么是立即执行函数,它的作用是什么?简单说一下闭包的使用场景

闭包指可以从内部函数访问外部函数的作用域

立即执行函数是一个在定义时就会立即执行的 JavaScript 函数

立即执行函数的作用

  • 不必为函数命名,避免了污染全局变量
  • IIFE 内部形成了一个单独的作用域,可以封装一些外部无法读取的私有变量

闭包的使用场景

  • 节流防抖、柯里化
  • 立即执行函数

△ 186 次 简述浏览器的渲染过程,重绘和重排在渲染过程中的哪一部分?

  • 浏览器解析 URL 获取协议,主机,端口, path
  • 浏览器获取主机 IP 地址
  • 建立 TCP 连接,然后发送 HTTP 请求
  • 服务器将响应报文通过 TCP 连接发送回浏览器,浏览器接收 HTTP 响应,根据资源类型决定如何处理
  • 根据 HTML 解析出 DOM 树
  • 根据 CSS 解析生成 CSS 规则树
  • 结合 DOM 树和 CSS 规则树,生成渲染树
  • 根据渲染树计算每一个节点的信息
  • 根据计算好的信息绘制页面

重绘和重排

回流时,渲染流程会重新走一遍。重绘时,会重新计算样式,跳过中间步骤直接生成绘制列表。可见,重绘不一定导致回流,但回流一定发生了重绘。

△ 182 次 简述 diff 算法的实现机制和使用场景

diff 同层对比

新旧虚拟 DOM 对比的时候,diff 算法比较只会在同层级进行,不会跨层级比较。所以 diff 算法是:深度优先算法、时间复杂度:O(n)

diff 对比流程

当数据改变时,会触发 setter,并且通过 Dep.notify 去通知所有订阅者 Watcher,订阅者们就会调用 patch 方法,给真实 DOM 打补丁,更新相应的视图

patch 方法

patch 对比当前同层的虚拟节点是否为同一种类型的标签:

  • 是:继续执行 patchVnode 方法进行深层比对
  • 不是:没必要比对了,直接整个节点替换成新虚拟节点

sameVnode 会比较 key 值、标签名、是否为注释节点、是否定义了 data 和当标签为 input 时,type 必须相同

patchVnode 方法

主要判断:

  • 如果 newVnode 和 oldVnode 是同一个对象,则 return
  • 如果 newVnode 和 oldVnode 是文本节点,且文本不同,则将 el 中文本更新为 newVnode 的文本
  • 如果 newVnode 和 oldVnode 都有子节点,且不同,则对比子节点
  • 如果 oldVnode 有子节点而 newVnode 没有,则删除 el 的子节点
  • 如果 oldVnode 没有子节点而 newVnode 有,则将 newVnode 的子节点真实化之后添加到 el

updateChildren 方法

子节点不完全一致,则调用 updateChildren,while 循环主要处理了以下五种情景:

  • oldStart 和 newStart 使用 sameVnode 方法进行比较,sameVnode(oldStart, newStart)
  • oldStart 和 newEnd 使用 sameVnode 方法进行比较,sameVnode(oldStart, newEnd)
  • oldEnd 和 newStart 使用 sameVnode 方法进行比较,sameVnode(oldEnd, newStart)
  • oldEnd 和 newEnd 使用 sameVnode 方法进行比较,sameVnode(oldEnd, newEnd)
  • 如果以上逻辑都匹配不到,再把所有旧子节点的 key 做一个映射到旧节点下标的 key -> index 表,然后用新 vnode 的 key 去找出在旧节点中可以复用的位置

Vue3.0 diff

  • PatchFlag。Vue3.0 对于不参与更新的元素,做静态标记并提示,只会被创建一次,在渲染时直接复用
  • cacheHandlers。事件侦听器缓存
  • 最长递增子序列

△ 178 次 简述 Javascript 中的防抖与节流的原理并尝试实现

点击显示代码👇

js 复制代码
// 防抖
function debounce(fn, wait) {
  let timeout = null;
  return function () {
    let context = this;
    const args = arguments;
    if (timeout) clearTimeout(timeout);
    timeout = setTimeout(() => {
      fn.apply(context, args);
    }, wait);
  };
}

// 节流
function throttle(fn, wait) {
  let pre = new Date();
  return function () {
    let context = this;
    let args = arguments;
    let now = new Date();
    if (now - pre >= wait) {
      fn.apply(context, args);
      pre = now;
    }
  };
}

△ 172 次 promise 有哪些状态?简述 promise.all 的实现原理

Promise 状态

  • 待定(pending):初始状态,既没有被兑现,也没有被拒绝。
  • 已兑现(fulfilled):意味着操作成功完成。
  • 已拒绝(rejected):意味着操作失败。

promise.all 的实现原理

点击显示代码👇

js 复制代码
function myPromiseAll(promises) {
  return new Promise(function (resolve, reject) {
    if (!isArray(promises)) {
      return reject(new TypeError("arguments must be an array"));
    }
    var resolvedCounter = 0;
    var promiseNum = promises.length;
    var resolvedValues = new Array(promiseNum);
    for (var i = 0; i < promiseNum; i++) {
      (function (i) {
        Promise.resolve(promises[i]).then(
          function (value) {
            resolvedCounter++;
            resolvedValues[i] = value;
            if (resolvedCounter === promiseNum) {
              return resolve(resolvedValues);
            }
          },
          function (reason) {
            return reject(reason);
          }
        );
      })(i);
    }
  });
}

△ 166 次 简述 CSS 盒模型

在 CSS 中,盒子模型可以分成:

  • W3C 标准盒子模型 box-sizing: content-box
  • IE 怪异盒子模型 box-sizing: border-box

标准盒子模型

  • 盒子总宽度 = width + padding + border + margin
  • 盒子总高度 = height + padding + border + margin

width/height 只是内容高度,不包含 padding 和 border 值

IE 怪异盒子模型

  • 盒子总宽度 = width + margin;
  • 盒子总高度 = height + margin;

width/height 包含了 padding 和 border 值

△ 142 次 简述 Javascript 原型以及原型链

原型

实例的 proto 指向构造函数的 prototype

原型链

  • constructor 指向构造函数,每个对象的 proto 指向创建它的构造函数的 prototype,⽽构造函数的 prototype 也有 proto 指向他的⽗辈或者是 Object,当查找⼀个对象中不存在的属性时,会去它的 proto、proto 中的 proto 中进⾏寻找,直到找到或者是 null 为⽌
  • instanceof 判断对象的 proto 和构造函数的 prototype 是不是同⼀个地址
  • Object.setPrototypeOf 改变对象的 proto

△ 138 次 简述什么是 XSS 攻击以及 CSRF 攻击?

XSS 跨站脚本攻击

  1. 可能是写⼀个死循环、获取 cookie 登录
  2. 监听⽤户⾏为
  3. 修改 DOM 伪造登录表单
  4. 页⾯⽣成浮窗⼴告

XSS 防范

  • 对输⼊转码过滤

  • 利⽤ CSP 浏览器内容安全策略,核⼼就是服务器决定浏览器加载哪些资源,功能:

    1. 限制其他域下的资源加载
    2. 禁⽌向其它域提交数据
    3. 提供上报机制
  • HttpOnly HttpOnly 类型的 cookie 阻⽌ JS 对其的访问(标记或授权对话) 阻⽌ XSS 攻击:服务器对脚本进⾏过滤或转码,利⽤ CSP 策略,使⽤ HttpOnly;

CSRF-跨站伪造请求(钓鱼)

攻击者诱导受害者进⼊第三⽅⽹站,在第三⽅⽹站中,向被攻击⽹站发送跨站请求。利⽤受害者在被攻击⽹站已经 获取的注册凭证(⽐如 cookie) ,绕过后台的⽤户验证,因此可以冒充⽤户对被攻击的⽹站执⾏某项操作。

CSRF 防范

  • SameSite SameSite 可以设置为三个值,Strict、Lax 和 None。 a. 在 Strict 模式下,浏览器完全禁⽌第三⽅请求携带 Cookie。⽐如请求 sanyuan.com ⽹站只能在 sanyuan.com 域名当 中请求才能携带 Cookie,在其他⽹站请求都不能。 b. 在 Lax 模式,宽松⼀点,但是只能在 get ⽅法提交表单况或者 a 标签发送 get 请求的情况下可以携带 Cookie,其 他情况均不能。 c. 在 None 模式下,也就是默认模式,请求会⾃动携带上 Cookie。

  • 验证来源站点

    请求头中的 origin 和 referer origin 只包含域名信息,referer 包含具体的 URL 路径。

  • CSRF Token

    利⽤ token(后端⽣成的⼀个唯⼀登陆态,传给前端保存)每次前端请求都会带 token,后端检验通过才同意请求。 敏感操作需要确认 敏感信息的 cookie 只能有较短的⽣命周期

  • 安全框架

    如 Spring Security。

△ 134 次 CSS 的选择器优先级是怎样?

选择器 格式 优先级权重
id 选择器 #id 100
类选择器 .classname 10
属性选择器 a[ref = "eee"] 10
伪类选择器 li:last-child 10
标签选择器 div 1
伪元素选择器 li:after 1
相邻兄弟选择器 h1 + p 0
⼦选择器 ul > li 0
后代选择器 li a 0
通配符选择器 * 0
相关推荐
风清扬_jd4 分钟前
Chromium 中JavaScript Fetch API接口c++代码实现(二)
javascript·c++·chrome
丁总学Java20 分钟前
微信小程序-npm支持-如何使用npm包
前端·微信小程序·npm·node.js
It'sMyGo29 分钟前
Javascript数组研究09_Array.prototype[Symbol.unscopables]
开发语言·javascript·原型模式
懒羊羊大王呀30 分钟前
CSS——属性值计算
前端·css
睡觉然后上课40 分钟前
c基础面试题
c语言·开发语言·c++·面试
李是啥也不会1 小时前
数组的概念
javascript
无咎.lsy1 小时前
vue之vuex的使用及举例
前端·javascript·vue.js
fishmemory7sec1 小时前
Electron 主进程与渲染进程、预加载preload.js
前端·javascript·electron
fishmemory7sec1 小时前
Electron 使⽤ electron-builder 打包应用
前端·javascript·electron
豆豆2 小时前
为什么用PageAdmin CMS建设网站?
服务器·开发语言·前端·php·软件构建