前端面试题

153 阅读14分钟

react的setState的原理?setState如何更新的?

  1. 执行setState,内部执行enqueueSetState将当前传入的对象或数组推入队列 2. enqueueSetState执行之前会判断队列是否为空,为空代表第一次往队列添加。这时设置一个微任务(执行清空队列flush
  2. 然后继续执行所有同步代码(其中可能有多个setState,因此循环第一第二步)
  3. 所有同步代码执行完毕,将下一个微任务推入队列flush
  4. 然后flush内部会合并所有队列中的state对象,然后更新对应组件。
  • 为什么setState传入函数就可以同步? 因为Object.assign无法合并函数,函数会先执行,后合并,所以所有函数内部都可以获取到上个state的值

  • 为什么直接修改this.state无效 因为setState本质是通过一个队列机制来实现state更新的。执行setState时,会将需要更新的state合并后放入状态队列,而不会立刻更新state,队列机制可以批量更新state。如果不通过setState而直接修改this.state,那么这个state不会放入状态队列中,下次调用setState时对状态队列进行合并时,会忽略之前直接被修改的state,这样就无法合并state,而已也没有直接更新state

tcp和udp的区别

tcpudp
需要三次握手建立连接不需要建立连接
可靠,丢包会重传不可靠,丢包不会重传
有序无序
无界,通过字节流传输有界,每个包都是单独的
tcp有流量控制(拥塞控制)没有流量控制
传输速度慢传输速度快
包头大,20字节包头小,8字节

react从jsx到真实dom的过程

  1. 使用React.createElement或者jsx编写react组件,实际上所有的jsx代码最后都会转换成React.createElement(...),Babel帮助我们完成了这个转换的过程
  2. createElemnt函数对key、self、ref等特殊的props进行处理,并获取defaultProps对默认props进行赋值,并且对传入的孩子节点进行处理,最终构造成一个虚拟DOM对象
  3. ReactDOM.render将生成好的虚拟DOM渲染到指定容器上,其中采用了批处理、事物等机制并且对特点浏览器进行了性能优化,进行diff算法,为fiber打上tag,最终转换成真实DOM

new做了什么

  1. 在内存中创建一个新对象
  2. 在这个新对象内部的[[Prototype]]特性被赋值为构造函数的prototype属性
  3. 构造函数内部的this被赋值为这个新对象(即this指向新对象)
  4. 执行构造函数内部的代码(给新对象添加属性)
  5. 如果构造函数返回非空对象,则返回该对象;否则,返回刚创建的新对象

XSS攻击和CSRF攻击

XSS攻击(Cross Site Scripting,跨站脚本攻击):是指利用攻击者利用站点的漏洞,在表单提交时,在表单内容中加入一些恶意脚本,当其他正常用户浏览页面,而页面中刚好出现攻击者的恶意脚本时,脚本被执行,从而使得页面遭到破坏,或者用户信息被窃取。

注入方法:

  1. 在HTML中内嵌的文本中,恶意内容以script标签形成注入
  2. 在内联的javascript中,拼接的数据突破了原本的限制(字符串、变量、方法名等)
  3. 在标签属性内,恶意内容包含引号,从而突破属性值的限制,注入其他属性或者标签
  4. 在标签的href、src等属性中,包含javascript:伪协议等可执行代码
  5. onload、onerror、onclick等事件中,注入不受控制代码
  6. 在style属性和标签中,包含类似background-image:url("javascript:...");的代码(新版本浏览器已经可以防范)
  7. 在style属性和标签中,包含类似expression(...)的css表达式代码(新版本浏览器已经可以防范)

xss攻击的分类

  • 存储型XSS:存储型xss的攻击步骤-1)攻击者将恶意代码提交到目标网站的数据库中;2)用户打开目标网站时,网站服务端将恶意代码从数据库取出,拼接在HTML中返回给浏览器;3)用户浏览器接收到响应后解析执行,混在其中的恶意代码也被执行;4)恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。 存储行xss(又被称为持久性xss)攻击常见于带有用户保存数据的网站功能,如论坛发帖、商品评论、用户私信等。它是最危险的一种跨站脚本,相比反射型xss和dom型xss具有更高的隐蔽性,所以危害更大,因为他不需要用户手动触发。任何允许用户存储数据的web程序都可能存在存储型xss漏洞,当攻击者提交一段xss代码后,被服务器端接收并存储,当所有浏览者访问某个页面时都会被xss
  • 反射型XSS:反射型xss的攻击步骤-1)攻击者构造出特殊的URL,其中包含恶意代码;2)用户打开带有恶意代码的URL时,网站服务端将恶意代码从URL中取出,拼接在HTML中返回给浏览器。3)用户浏览器接收到响应后解析执行,混在其中的恶意代码也被执行;4)恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。 反射型xss跟存储型xss的区别是:存储型xss的恶意代码存在数据库里,反射型xss的恶意代码存在URL里。反射型XSS(也被称为非持久性XSS)漏洞常见于通过URL传递参数的功能,如网站搜索、跳转等。由于需要用户主动打开恶意的URL才能生效,攻击者往往会结合多种手段诱导用户点击。POST的内容也可以触发反射型XSS,只不过其触发条件比较苛刻(需要构造表单提交页面,并引导用户点击),所以非常少见
  • DOM型XSS:DOM型XSS的攻击步骤-1)攻击者构造出特殊的URL,其中包含恶意代码。2)用户打开带有恶意代码的URL;3)用户浏览器接收到响应后解析执行,前端js取出URL中的恶意代码并执行。4)恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。 DOM型XSS跟前两种的区别是:DOM型XSS中,取出和执行恶意代码由浏览器端完成,属于前端js自身的安全漏洞,而其他两种都属于服务端的安全漏洞

要防范XSS攻击,需要在服务器端过滤脚本代码,将一些危险的元素和属性去掉或对元素进行HTML实体编码

常用防范方法

  • httpOnly:在cookie中设置httpOnly属性后,js脚本将无法读取到cookie信息
  • 输入过滤:一般是用于对输入格式的检查,例如:油箱、电话号码、用户名、密码等,按照规定的格式输入。不仅仅是前端负责,后端也要做相同的过滤检查。因为攻击者完全可以绕过正常的输入流程,直接利用相关接口向服务器发送设置。
  • 转义HTML:如果拼接HTML是必要的,就需要对引号,尖括号、斜杠进行转义,但这还不是很完善,相对HTML模板各处插入点进行充分的转移,就需要采用合适的转义库。
  • 白名单:对于显示富文本来说,不能通过上面的方法来转义所有字符,因为这样会把需要的格式也过滤掉,这种情况通常采用白名单过滤的办法,当然也可以通过黑名单过滤,但是考虑到需要过滤的标签和标签属性实在太多,更加推荐使用白名单的方式。

CSRF(Cross-site request forgery)即跨站请求伪造,也被称为one-click-attack或者session riding,通常缩写为CSRF或者XSRF,是一种挟制用户在当前已登录的web应用程序执行非本意的操作的攻击方法。如:攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目的。

CSRF的攻击过程:

  1. 用户C浏览并登录信任网站A
  2. 验证通过,在用户C处产生网站A的cookie
  3. 在用户C没有登出网站A的情况下,访问危险网站B
  4. 危险网站B要求访问网站A,发出一个请求request
  5. 根据危险网站B在4.的请求,浏览器带着2.的cookie访问A
  6. 网站A不知道5.发出的请求是危险网站B发出的还是用户C发出的,由于浏览器会自动带上用户C的cookie,所以A会根据用户的权限处理5.的请求,这样危险网站B就达到了模拟用户操作的目的

CSRF攻击的特点:

  • 攻击一般发起在第三方网站,而不是被攻击的网站。
  • 攻击利用受害者在被攻击网站的登录凭证,冒充受害者提交操作,而不是直接窃取数据
  • 整个过程攻击者并不能获取到受害者的登录凭证,仅仅是“冒用”
  • 跨站请求可以用各种方式:图片URL、超链接、CORS、FORM提交等。部分请求方式可以直接嵌入第三方论坛、文章中,难以进行追踪。

CSRF攻击通常是跨域的,因为外域通常更容易被攻击者掌握。但是如果本域下有容易被利用的功能,比如可以发图和链接的论坛和评论区,攻击可以直接在本域下进行,而且这种攻击更加危险。

CSRF和XSS的区别

  • 通常来说CSRF是由XSS实现的,CSRF时常被称为XSRF(CSRF实现的方式还可以是直接通过命令行发起请求等)
  • 本质上讲,XSS是代码注入问题,CSRF是HTTP问题。XSS是内容没有过滤导致浏览器将攻击者的输入当代码执行。CSRF则是因为浏览器在发送HTTP请求时自动带上cookie,而一般网站的session都存在cookie里面(token验证可以避免)

CSRF的防御方式:

  • 验证码:强制用户必须与应用进行交互,才能完成最终请求。此种方式能很好的遏制csrf,但是用户体验比较差。
  • Referer check:请求来源限制,此种方法成本最低,但是并不能保证100%有效,因为服务器并不是什么时候都能获取到Referer,而且低版本的浏览器存在伪造Referer的风险。
  • token:token验证的CSRF防御机制是公认最合适的方案,但是如果网站同时存在XSS漏洞的时候,这个方法也是空谈。
  • 双重cookie
  • samesite cookie
  • 具体方法看前端安全系列之二:如何防止CSRF攻击? - 掘金 (juejin.cn)

react的不可变性

在React中,不可变性指数据一旦被创建,就不能被修改。React推崇使用不可变数据的原则,这意味着在更新数据时,应该创建新的数据对象而不是直接修改现有的数据。

以下是理解React中不可变性原则的几个关键点:

  • 数据一旦被创建就不能被修改:在React中,组件的状态(state)和属性(props)应该被视为不可变的。一旦创建了状态或者属性对象,就不应该直接修改它们的值。这样可以确保组件的数据在更新时是不可变的,从而避免意外的数据改变和副作用。
  • 创建新的数据对象:当需要更新状态或属性时,应该创建新的数据对象。这可以通过使用对象展开运算符、数组的concat、slice等方法,或者使用不可变数据库(如Immutable.js、Immer等)来创建新的数据副本
  • 比较数据变化:React使用Virtual DOM来比较前后两个状态树的差异,并仅更新需要更新的部分。同构使用不可变数据,React可以更高效的进行比较,因为它可以简单的比较对象引用是否相等,而不必逐个比较对象的属性。
  • 性能优化:使用不可变数据可以带来性能上的优势。由于React可以更轻松的比较前后状态的差异,可以减少不必要的重新渲染和组件更新,提高应用的性能和响应性。

不可变性的原则在React中有以下好处:

  • 简单数据变更追踪:由于数据不可变,可以更轻松的追踪数据的变化。这样可以更好的理解代码的行为和数据的流动
  • 避免副作用:可变数据容易引发副作用和难以追踪的bug。通过使用不可变数据,可以避免许多与副作用相关的问题。
  • 方便的历史记录和回滚:不可变数据使得记录和回滚应用状态的历史变得更容易。可以在不改变原始数据的情况下,创建和保存不同时间点的数据快照。

Promise的原理

ajax的原理和步骤

ajax的原理简单来说就是通过XMLHttpRequest对象来向服务器发送异步请求,从服务器获得数据,然后用js来操作DOM而更新页面。

ajax的步骤为:

  1. 创建ajax的核心对象XMLHttpRequest对象
  2. 通过XMLHttpRequest对象的open方法与服务器建立连接
  3. 构建请求所需的数据内容,并通过XMLHttpRequest对象的send方法发送给服务器端
  4. 通过XMLHttpRequest对象提供的onreadystatechange事件来监听服务端与客户端的通信状态
  5. 接收并处理服务端向客户端响应的数据结果
  6. 将处理结果更新到HTML页面中
const request = new XMLHttpRequest()
request.open('POST', 'http://xxx')
request.send()
request.onreadystatechange = function(e) {
    if(request.readystate === 4 && request.status === 200) {
        document.getElementById('.root').innnerHTML = request.responseText
    }
}

readyState:

  • 0: 请求未初始化
  • 1: 服务器连接已建立,已调用open
  • 2: send已被调用,并且头部和状态已经可以获得
  • 3: 下载中;responseText属性已经获得部分数据
  • 4: 下载已完成;responseText属性已经获得全部数据

position: fixed

元素会被移出正常文档流,并不为元素预留空间,而是通过指定元素相对于屏幕视口(viewport)的位置来指定元素位置。元素的位置在屏幕滚动时不会改变。打印时,元素会出现在每页的固定位置。fiexd属性会创建新的层叠上下文。当元素祖先的transform、perspective、filterbackdrop-filter属性非none时,容器由视口改为该祖先

css优化

  • 压缩和合并css文件
  • 减少http请求
  • 使用精简的选择器
  • 优化字体和图片,比如css精灵图
  • 使用现代布局技术,比如flexbox和grid布局
  • 使用浏览器缓存
  • 使用gpu渲染,比如transformer、will-change等
  • 删除不必要的样式
  • 将css拆分为独立模块,按需加载
  • 预加载重要资源,比如preload
  • 优化渲染阻塞