本文记录了我学习过程中整理的前端相关的知识点,以摘抄为主,绝大部分非原创。未能全部都标明出处,在此致歉

前言

为什么选择前端

前端和后端,我选择将前端作为我的主要技术栈。这和我个人的学习习惯有关。

我喜欢学以致用,对于一门尚未掌握的技术,我倾向于先看文档看个百分之二三十,有个大体的了解后,就开始动手去做。但后端的微服务等技术,我缺乏实际的实践环境,没法实践去应用,学起来就感觉很虚。

但前端不太一样。在我自己的项目中,为了实现更快的响应时间、更实用美观的界面,我有充分的动力去学习新的技术,然后将其运用,这形成了一个正反馈的过程。比如说我去年用webassembly写了一个Game of Life,当我对代码进行优化后,我确实能看到帧数肉眼可见地提升了。

为什么要记八股

最近在准备找实习,网上的八股光看也不太能记得住,还得是自己整理记录下。

我之前有点认为记八股是一种应试行为,有点抵触。但有天晚上我排查EuDs63/postkid出现的一个问题,为了完全搞懂,我就自发地去搜React的生命周期。

这时候我意识到八股的那些问题,其实不少是蛮常见的问题。要写好代码确实得去知道。

面试官视角下的技术面——为什么要“背八股”_牛客网

如果被问八股,要学会自己主动去延伸,进而在一定程度上把握面试的主动权。

安全

xss攻击

  • Cross-Site Scripting(跨站脚本攻击)简称 XSS,是一种代码注入攻击。攻击者通过在目标网站上注入恶意脚本,使之在用户的浏览器上运行。利用这些恶意脚本,攻击者可获取用户的敏感信息如 Cookie、SessionID 等,进而危害数据安全。
  • 三种类型:
    类型存储区插入点
    存储型 XSS后端数据库HTML
    反射型 XSSURLHTML
    DOM 型 XSS后端数据库/前端存储/URLJavaScript
  • DOM 型 XSS 跟前两种 XSS 的区别:DOM 型 XSS 攻击中,取出和执行恶意代码由浏览器端完成,属于前端 JavaScript 自身的安全漏洞,而其他两种 XSS 都属于服务端的安全漏洞。
  • 防范
    1. 阻止攻击者提交恶意代码
      • 输入过滤: 道高一尺魔高一丈,难
      • 输入长度限制
    2. 防止浏览器执行恶意代码
      • 预防存储型和反射型 XSS 攻击
        • 改成纯前端渲染,把代码和数据分隔开。
        • 对 HTML 做充分转义
      • 预防 DOM 型 XSS 攻击
    3. 利用 CSP 来抵御或者削弱 XSS 攻击,一个 CSP 兼容的浏览器将会仅执行从白名单域获取到的脚本文件,忽略所有的其他脚本
    4. 对关键 Cookie 设置 http-only 属性
  • 参考:

JavaScript Prototype 污染攻击

CSRF

  • CSRF(Cross-site request forgery)跨站请求伪造:攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目的。

  • 特点:

    • CSRF(通常)发生在第三方域名。
    • CSRF攻击者不能获取到Cookie等信息,只是使用
  • 防护策略

    • 阻止不明外域的访问
      • 同源检测
        • 使用Origin Header确定来源域名
        • 使用Referer Header确定来源域名
        • 如果直接在本域发起攻击,同源策略无法达到防护的作用
      • Samesite Cookie
    • 提交时要求附加本域才能获取的信息
      • CSRF Token
        • 我们可以要求所有的用户请求都携带一个CSRF攻击者无法获取到的Token。服务器通过校验请求是否携带正确的Token,来把正常的请求和攻击的请求区分开,也可以防范CSRF的攻击
      • 双重Cookie验证
        • 难以做到子域名的隔离
  • 参考:


Html

表单数据校验 - 学习 Web 开发 | MDN

锚点

  • 示例
<a href="#javascript深入之重新认识箭头函数的this" aria-hidden="true" class="header-anchor">#</a>

HTML5语义化

  • title v.s. h1
  • strong v.s. b

浏览器

浏览器一帧都会干些什么?

  1. 接受输入事件
  2. 执行事件回调
  3. 开始一帧
  4. 执行 RAF (RequestAnimationFrame)
  5. 页面布局,样式计算
  6. 绘制渲染
  7. 执行 RIC (RequestIdelCallback)

浏览器引擎的工作原理

浏览器事件循环

输入URL到页面渲染的过程

浏览器缓存(强缓存,协商缓存)具体字段头是哪些,有何区别

  • 什么是浏览器缓存?

    当我们访问一个网站时,会加载各种资源,如 HTML文档、JS、CSS、图片等。浏览器会将一些不经常变的资源保存在本地,这样下次访问相同网站时,就直接从本地加载资源,并不通过请求服务器,这就是浏览器缓存

  • 根据位置分类

    • memory cache:主要用来缓存有 preloader 相关指令的资源;关闭tab页后就释放
    • disk cache
  • Response Header中的相关属性

    1. Expires
    • HTTP/1
    1. Cache-Control
    • HTTP/1.1
    • 优先级比 Expires 要高
    • 值:public / private / no-store / no-cache / max-age=60
    • no-cache 告诉浏览器要使用缓存文件,但是每次需要跟服务器确认是最新文件以后才能用,一般使用 Etag 或者 Last-Modified 字段来控制缓存
    1. Last-Modified / If-Modified-Since
      • HTTP/1
      • 浏览器第一次访问资源,服务器会 Response Header 里添加 Last-Modified 的值
      • 浏览器在下一次请求这个资源的时候,检测到有 Last-Modified 这个 Header。浏览器就会在 Request 中加上 If-Modified-Since,If-Modified-Since 的值就是 Last-Modified 的值
    2. ETag / If-None-Match
      • ETag由服务器生成,三种方式:基于内容 / 基于版本 / 自定义生成
      • 浏览器在下一次加载资源向服务器发送请求时,会将上一次返回的 Etag值放到request header 里的 If-None-Match 里
      • ETag 的优先级要高于 Last-Modified
  • 强缓存

    • 不会向服务器发送请求,直接从缓存中读取资源
    • 通过 Expires 和 Cache-Control 来实现的
  • 协商缓存

    • 在强缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识来决定是否使用缓存
    • 利用的是【Last-Modified,If-Modified-Since】和【ETag、If-None-Match】这两对 Header 来管理
  • 场景:发版,要求无视缓存

    • 每次对应静态文件里有内容改动的时候,自动加一段 hash 到静态文件名里
  • 用户行为

    • F5 刷新: 因浏览器而异
    • Ctrl + F5 强制刷新的时候,会暂时禁用强缓存和协商缓存
  • 后端配置

    • setHeader之类
    • Nginx 配置
  • 参考

同源页面

如果两个 URL 的协议、端口(如果有指定的话)和主机都相同的话,则这两个 URL 是同源的。

  • 举例:
    • http://store.company.com/dir/page.htmlhttp://store.company.com/dir2/other.html 同源
    • http://store.company.com/dir/page.htmlhttp://news.company.com/dir/other.html不同源,因为主机不同
  • 当一个网页加载的资源(如脚本、样式表、图片等)来自于与当前页面不同的域名、协议或端口时,就称为跨域请求。
  • 参考:

跨域问题的解决

  1. 代理
    • 原理:同源策略只受限于浏览器访问服务器,对于服务器访问服务器并没有限制的特点。中间服务器做了一个请求转发的功能
    • 实现:
  2. CORS
    • CORS 跨源资源共享(Cross-Origin Resource Sharing)。
    • 总体思路是:如果浏览器要跨域访问服务器的资源,需要获得服务器的允许
    • 三种请求
      1. 简单请求
      2. 需要预检的请求
      3. 附带身份凭证的请求
    • 服务器通过响应headerAccess-Control-Allow-Origin进行控制

预检请求 OPTIONS

  • 为什么需要预检请求
    • 安全性:同源政策只会挡回应,不会挡请求,所以假如某个恶意攻击者发送DELETE 的请求,同源政策不会挡下这个请求(如果该请求后有回应,回应的部分才会挡下),换句话说如果没有多一层过滤,恶意攻击者任意发DELETE 请求,就可能任意删掉服务器端的资源。有了预检请求,等于是多一层过滤,当预检请求通过了,才会对服务器发送真正的请求
    • 相容性:如果浏览器发送一个服务器端没支援的请求,可能导致服务器端出问题。这时预检请求会是一道防护,先确保服务器端有支援,才真正发请求
  • Access-Control-Allow-Origin:和简单请求一样,表示允许的源
  • Access-Control-Allow-Methods:表示允许的后续真实的请求方法
  • Access-Control-Allow-Headers:表示允许改动的请求头
  • Access-Control-Max-Age :给定了该预检请求可供缓存的时间长短,单位为秒
  • 参考

Cookie,sessionStorage和localStorage

Cookie、sessionStorage和localStorage都是用于在客户端存储数据的机制,但它们在功能和使用方式上有一些重要的差异:

  1. Cookie

    • Cookie是最古老和最基本的客户端存储机制之一。
    • Cookie是由服务器发送到用户浏览器的小型文本文件,存储在用户的计算机上。
    • 每次发送HTTP请求时,浏览器都会将相应的Cookie发送回服务器。
    • Cookie通常用于存储用户偏好设置、跟踪用户行为等信息。
    • Cookie有大小限制(通常为几KB)。
    • 可以通过设置Cookie的过期时间来控制Cookie的生命周期。
  2. sessionStorage

    • sessionStorage是HTML5引入的Web存储机制之一,用于在浏览器中临时存储会话数据。
    • sessionStorage中存储的数据仅在当前会话期间有效,当用户关闭浏览器标签页或窗口时会被清除
    • sessionStorage中存储的数据仅限于当前页面或同源页面之间共享,不同页面之间的sessionStorage数据不会共享。
  3. localStorage

    • localStorage也是HTML5引入的Web存储机制之一,用于在浏览器中持久存储数据。
    • localStorage中存储的数据在用户关闭浏览器后仍然保留,直到用户显式删除它们。
    • localStorage中存储的数据也只限于同源页面之间共享,不同源页面之间的localStorage数据不会共享。

主要差异总结如下:

IndexedDB

sessionStorage

sessionStorage中你所说的不能在所有同源窗⼝中共享是什么意思?多个tal栏不可以共享?浏览器同源策略是什么?会话级别的储存⽅式的会话是什么意思?

缓存除了indexDB、service worker、localStorage外还知道别的不(面试官提了个memory cache)

什么情况下用post和get

讲一讲get和post的区别?

script标签中的defer和async的区别?

SEO

兼容

  • 例:
addEventListener("paste", (event) => {
  event.preventDefault();
  //兼容不同浏览器中获取剪贴板数据的方式
  let paste = (event.clipboardData || window.clipboardData).getData("text");
  paste = paste.toUpperCase();
  const selection = window.getSelection();
  if (!selection.rangeCount) return; //检查是否存在文本范围
  selection.deleteFromDocument();
  selection.getRangeAt(0).insertNode(document.createTextNode(paste));
  selection.collapseToEnd();
});

网络

TCP/IP五层模型

TCP

http 缓存机制

安全协议

http 和 https 区别

https 加/解密

https 攻击方式

DNS解析过程

三次握手与四次挥手

tcp和udp的区别

就是要你懂网络–一个网络包的旅程 | plantegg

HTTP 的状态码

  • 分类:
    • 1 表示消息
    • 2 表示成功
    • 3 表示重定向
    • 4 表示请求错误
    • 5 表示服务器错误
  • 常见
    • 200: 服务器已成功处理了客户端的请求,并且已返回所请求的资源
    • 206: 服务器成功处理了部分请求,一般用来做断点续传,或者是视频文件等大文件的加载
    • 301: 请求的网页已永久移动到新位置,常用于域名更换
    • 302: 临时重定向不会缓存,常用于未登陆的用户访问用户中心重定向到登录页面
    • 304: 自从上次请求后,请求的网页未修改过。服务器返回此响应时,不会返回网页内容。
    • 401: 请求要求身份验证
    • 404: 服务器找不到请求的网页
    • 405: 禁用请求中指定的方法
    • 500: 服务器内部错误
    • 502: 连接超时错误
  • 参考

轮询、长轮询(Long polling)、WebSocket

  • 轮询:定期向服务器发出请求
  • 长轮询过程
    1. 请求发送到服务器。
    2. 服务器在有消息之前不会关闭连接。
    3. 当消息出现时 —— 服务器将对其请求作出响应。
    4. 浏览器立即发出一个新的请求。
  • WebSocket提供了一种在浏览器和服务器之间建立持久连接来交换数据的方法。数据可以作为“数据包”在两个方向上传递,而无需中断连接也无需额外的 HTTP 请求。
  • 参考

列举一些使用tcp和udp的应用层协议,http(tcp)、websocket(tcp)、http3(udp),为啥http3会用udp

如果线上某个页面不显示了,可能是哪些问题(dns劫持,但我不太了解这个)

cdn原理


TypeScript

interface v.s. type

  • An interface can be named in an extends or implements clause, but a type alias for an object type literal cannot.
  • An interface can have multiple merged declarations, but a type alias for an object type literal cannot.
  • 参考Typescript 中的 interface 和 type 到底有什么区别 - 掘金
  • 可以互相拓展
    // interface extends type
    type Name = { 
      name: string; 
    }
    interface User extends Name { 
      age: number; 
    }
    
    // type extends interface
    interface Name { 
      name: string; 
    }
    type User = Name & { 
      age: number; 
    }
    
  • interface 能够声明合并
    interface User {
      name: string
      age: number
    }
    interface User {
      sex: string
    }
    
    /*
    User 接口为 {
      name: string
      age: number
      sex: string 
    }
    */
    
  • 用interface描述数据结构
  • 用type描述类型关系

联合类型(Union Types)

类型守卫

  • 作用:确保所使用的类型均可以正常使用,从而针对不同类型,使用不同的业务处理。
  • 示例:
function evaluatePrice(vehicle: Vehicle) {
  switch(vehicle.vType) {
    case "car":
      return vehicle.transmission * EVALUATION_FACTOR;
    case "truck":
      return vehicle.capacity * EVALUATION_FACTOR;
    case "motorcycle":
      return vehicle.make * EVALUATION_FACTOR;
  }
}

交叉类型

  • 参考TypeScript类型守卫、联合类型、交叉类型 - 古兰精 - 博客园
  • 通过 & 运算符可以将现有的多种类型叠加到一起成为一种类型
  • 同名基础类型属性的合并: 需要判断是否可能存在,不存在则为never
  • 同名非基础类型属性的合并:示例:
    interface D { d: boolean; }
    interface E { e: string; }
    interface F { f: number; }
    
    interface A { x: D; }
    interface B { x: E; }
    interface C { x: F; }
    
    type ABC = A & B & C;
    
    let abc: ABC = {
      x: {
        d: true,
        e: '***',
        f: 666
      }
    };
    

泛型


杂项

SVG

  • 全称: Scalable Vector Graphics(可缩放矢量图形)
  • 介于DOM和Canvas之间,既提供了图形的绘制能力,又提供了元素的DOM交互能力
  • 特点
    • SVG不存在回流这种布局问题,最多也就是重绘。但是DOM的动画就可能导致回流。
    • SVG是矢量图形,而Canvas绘制的是位图
    • 当屏幕尺寸越大时,SVG的渲染速度差异不大,但是Canvas的渲染时长明显增加
    • 当绘制对象过多时,SVG的渲染时长指数增加,Canvas保持稳定增长
    • Canvas不支持DOM事件
  • 参考

Ajax

  • 5 states: 0. UNSENT
    1. OPENED
    2. HEADERS_RECEIVED
    3. LOADING
    4. DONE

AXIOS

Babel

webpack

REST API

设计模式

防抖和节流

  • 防抖:在触发频率高的事件中,执行耗费性能的操作,连续操作后只有最后一次生效
    //自己实现debounce
    function debounce(func,wait=0){
      let timeId = null; //为什么不在内部声明id?因为我如果在内部声明,每一次触发事件就会有一个新的变量产生
      return function(...args){
        const self=this;
        if(timeId){
          clearTimeout(timeId);
        }
        timeId=setTimeout(()=>{
          func.apply(self,args);
        },wait)
      };
    }
    
  • 节流:在触发频率高的事件中,执行耗费性能操作,连续触发,单位时间内只有一次生效
    function throttle(func,wait=0){
      let timeId;
      return function(...args){
        const self=this;
        if(!timeId){
          func.apply(self,args);
          timeId = setTimeout(()=>{
            timeId = undefined;
          },delay);
        }
      };
    }
    
  • 参考

滚屏性能优化

  • touchstarttouchmove事件的passive选项设置为ture
    • 原理: touchstarttouchmovecancelable的。事件处理程序中可能会调用preventDefault(),所以需要等待事件处理程序结束再滚动。
    • 注: 大部分浏览器(Safari 和 Internet Explorer 除外)将文档级节点 Window、Document 和 Document.body 上的 wheel、mousewheel、touchstart 和 touchmove 事件的 passive 默认值更改为 true。
  • 参考:

package.json

  • 版本
    • 每个版本号都形如:1.2.3,有三部分组成,依次叫主版本号、次版本号、修订号;
      1. 当新版本无法兼容基于前一版本的代码时,则提高主版本号;
      2. 当新版本新增了功能和特性,但仍兼容前一版本的代码时,则提高次版本号;
      3. 当新版本仅仅修正了漏洞或者增强了效率,仍然兼容前一版本代码,则提高修订号;
    • ^ 兼容某个大版本。如:^1.1.2 ,表示>=1.1.2 <2.0.0
    • ~ 兼容某个次版本。如:~1.1.2,表示>=1.1.2 <1.2.0
  • package-lock.json里面定义的是某个包的具体版本,以及包之间的层叠关系
  • package-lock.json 需要提交到仓库吗
    • 应用: 可以保证项目中成员、运维部署成员或者是 CI 系统, 在执行 npm install后, 保证在不同的节点能得到完全一致的依赖安装的内容,减少bug的出现
    • 给外部环境用的库: 在不使用 package-lock.json的情况下,就可以复用主项目已经加载过的包,减少依赖重复和体积
  • 参考:详解package.json和package-lock.json - 掘金

什么是懒加载?什么是按需加载?

怎么做到组件的按需引入,我提到利用treeshaking

SSR 渲染的原理

JWT (Json Web Token)

见[进一步学习jwt]

首屏优化

说一说useState和Hooks的执行顺序

项目中的分片上传,如何实现的?

如何优化解决虚拟滚动中滚速过快情况下的白屏问题

瀑布流

如何实现的长列表? 瀑布流 如何实现的长列表? 你是如何判断谁是底部元素的? 如果一次只请求10条数据,前端只展示了5条数据,如何判断底部元素的交叉状态?

响应式

git merge和 git rebase的区别

策略模式

脱离文档流和不脱离文档流会有什么不同的表现

rem

你知道eventBus吗?

rollup/vite 等构建工具;

面试题:React实现一个Dialog模板_react dialog-CSDN博客

html5新特性

实现es6中的flatten()

实现个栈(用了好几种方法实现,包括最原始的单链表),还讲了讲symbol等乱七八糟的东西

看你用到了Object.prototype.toString()方法,能给我介绍一下JavaScript中的Prototype吗?为什么不用Object.toString()或者Array.prototype.toString()

jsBridge原理

设计模式,以及用过哪些设计模式(这太多了,什么单例、观察者、发布订阅、中间(职责链)模式、原型模式等等)

js的for in和for of区别,如何把一个对象变成可迭代对象(实现[Symbol.iteractor]属性)

js异步(答得比较多,而且自己对协程也有些许研究,然后就从异步非阻塞io、事件循环等一直展开说了)

前端优化相关(平常也就是一些通用优化比如离线化、缓存之类的)

如果app里面实现个页面,react native和纯webview哪个更好

场景题:线上的某个页面加载慢,如何优化

webpack、vite、rollup适用场景

less/sass解决了什么问题(模块化,当时忘了这个点)

简单介绍了一下SSR,然后为什么不用SPA,这个当然得回答首页白屏而且会造成SEO问题

JS类型判断,这个很简单,写了typeof, instanceof, Object.toString.call ,然后说了一下用typeof能检测8种值,es5的string,boolean,number,function,object,undefined es6的symbol,以及最新的bigint

函数式编程,我首先介绍了一下纯函数,函数的副作用,然后说了curry的实现

偏函数

Proxy对象能拦截什么

axios原理

jss

参考