2024知识点查漏补缺

2024/9/1 前端

# 前言

最近想跳槽了,问就是工资太低- -。所以记录一下面试中可能遇到的以及自己不太了解的题,巩固一下老知识和学习新知识。

内容为空的后续会补上,也会更新新的题目。

# 跨域、CORS是什么?

网站之间互相请求时协议、域名和端口有一个不一样则称之为跨域。

cors(跨域资源共享)是一种策略,一般在跨域的情况下是不允许资源共享的。

一般需要通过后端或配置服务器解决,设置access-control-allow-origin来指定允许跨域的网站。或者通过jsonp的方式来进行跨域请求。

jsonp通常是利用标签中src或者href的属性来进行跨站请求的,一般请求返回结果为可执行的函数名,其中带有从后端携带过来的参数。如 xxx/xxx?callback=fn,返回结果为fn('hello'),则会自动执行该函数(前提是该函数在网站中存在)

还有html5新增postMessage,可以解决不同窗口以及嵌套iframe中的跨域问题,从而进行消息传递。

# 闭包

# 原型链

# XSS攻击

跨站脚本攻击。脚本执行是重点,分3种。

反射型:通过诱导你点击某个链接,该链接是正常访问某个网站的链接(可能还是官方链接),但链接中包含恶意代码,如果页面中刚好对链接中的某些部分进行展示,那么恶意代码就有可能被嵌入到页面中,也就给了js脚本执行的机会。

常见的例子是搜索页面,当你搜索某些关键词之后,url中会包含关键词,搜查的结果页面中通常也包含关键词。如果关键词包含恶意代码且没有被过滤掉,那么就会被执行。

存储型:通过提交数据将恶意代码保存到服务器的数据库中,当其他人的页面展示这条数据的时候,恶意代码就会被执行。

常见的例子是评论区,如果提交了包含恶意代码的评论,且没有被过滤就保存到了服务器,当其他人访问这个评论区的时候,恶意代码就会被执行。

DOM型:需要有两个条件,一个是需要有可以用来注入脚本的方法,另一个是需要有可以被注入的属性或者值。与其他类型的区别就是修改了原本页面的dom节点。

常见的例子是,使用了innerHTML来注入时,使用的字符串中包含了恶意代码,通过修改dom的属性来触发脚本。

document.querySelector("#content").innerHTML("<img src='/xxx/xxx/" + num + ".jpg />")
1

那么num就可以提前结束src,然后编写onerror属性来触发js事件,如

document.querySelector("#content").innerHTML("<img src='/xxx/xxx/" + "xx' onerror='alert()' class=" + ".jpg />")
1

num可能出现在url中。

# SQL注入

sql注入指的是,后端在进行数据库查询的时候,查询语句中附带了用户提交的字段,例如用户名等等。那么用户的字段即可参与到sql查询中去,修改查询语句。例子如下:

select * from user where username = #{userName} and password = #{password};

如果userName为'zhangsan -- ',即可注释掉后面的代码,只需要账号名就能查询到该用户的信息。
甚至,即使你不知道账号名,把userName修改为 'xxx or 1=1 -- ',由于1=1为真,导致where条件为真,也能查到所有信息。
1
2
3
4

# CSRF攻击

跨站请求伪造攻击。主要依赖浏览器在请求时自动带上cookie的机制。黑客在不知道你的cookie的情况下,伪装成你对你的个人信息进行套取和修改。 常见的例子是,你登录了x网站(黑客知道这个网站,并且知道接口的地址),并且cookie未过期。当你点击了黑客的链接后或者打开黑客html网站后,浏览器跨站请求x网站的接口,此时会把你未过期的cookie带上,让服务器误以为是你本人。

这种攻击可以通过后端对cookie设置samesite为strict(不允许跨站携带cookie),或者加上secure属性(只有https请求可以跨站携带cookie)。 也可以设置origin或者referer属性,甄别请求来源。 也可以利用cors来防范。

# 浏览器事件循环

首先了解JavaScript是单线程的机制,为了防止代码阻塞,把代码分为同步代码异步代码

同步代码交给JS引擎去执行,而异步代码先交给宿主环境(浏览器/node)。

同步代码会放到执行栈中,宿主环境会在时机成熟时将异步代码(任务)推送到任务队列

当执行栈里面的同步代码执行完成时,会检查任务队列是否有异步任务,如果有就加入到执行栈中。如此反复执行即是事件循环。

而异步任务中又分宏任务和微任务

宏任务(宿主环境)有setTimeout、setInterval、setImmediate、script脚本等,微任务有Promise.then() catch()、Async/Await、process.nextTick(node)等等。 需要注意的是创建Promise这个过程是同步任务,而非异步。

宏任务和微任务也对应宏任务队列和微任务队列。

上面提到当执行栈里面的同步代码执行完成时,会检查任务队列是否有异步任务,这时会优先检查微任务队列,并且按顺序执行其中的代码,如果期间产生了新的微任务,也会加入到微任务队列中被执行

直到微任务队列清空之后,才去检查宏任务队列,然后按顺序执行。

例子1:

console.log(1)
setTimeout(() => {
  console.log(2)
}, 0)
const p = new Promise((resolve, reject) => {
  console.log(3)
  resolve(4)
  console.log(5)
})
p.then(res => {
  console.log(res)
})
console.log(6)
1
2
3
4
5
6
7
8
9
10
11
12
13

根据上面的分析可得,输出的顺序为1 3 5 6 4 2。

例子2:

console.log(1)
const p1 = new Promise((resolve, reject) => {
  console.log(2)
  resolve(3)
})
setTimeout(() => {
  console.log(4)
  p1.then(res => {
    console.log(res)
  })
  console.log(5)
}, 0)
const p2 = new Promise((resolve, reject) => {
  console.log(6)
  resolve(7)
  console.log(8)
})
p2.then(res => {
  console.log(res)
})
console.log(9)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

根据上面分析可得,输出的顺序为 1 2 6 8 9 7 4 5 3。

# Webpack

流程:初始化 -> 编译 -> 输出

初始化是合并和读取配置。

编译过程:通过入口文件,读取文件内容,对不同文件类型通过loader进行转换,然后构建ast语法树(利用babel),找出文件之间的依赖关系(import、require),打包成一个个chunk,最后输出。

loader在其中负责代码的转换。plugin则贯穿整个流程,可以在编译的生命周期中做各种事情。

chunk:一些互相引用的文件共同打包成一个文件就是一个chunk。

# loader和plugin有什么区别

loader能力有限,只负责代码的转换,例如less-loader只负责将less转换成css。而plugin能够介入到整个打包编译的过程中,在生命周期中拥有完整的文件访问权,可以做很多事情。

# plugin是如何实现的?

plugin本质是一个对象,该对象含有apply属性,是一个函数,可以接受compiler参数。

而complier本质也是一个对象,在整个生命周期只会初始化一次。

在compiler内部钩子中,还有一个compilation对象,当文件发生改变时,触发钩子重新初始化compilation,以做到对文件的修改。

# Vite打包配置兼容es6+新特性

虽然ie浏览器已经被淘汰了,大部分浏览器也已经兼容es6语法,但耐不住语法更新快呀。所以有些浏览器还不支持新特性,但我们在项目中又想用,就可以通过配置vite来兼容。

vite.config.js文件中有自带的属性可以去配置兼容浏览器,主要是legacyPlugin方法,传入配置参数,可以指定是否兼容ie,以及转化指定的es6语法中的方法。大概配置如下:

export default ({ mode }) => defineConfig({
  base: './',
  plugins: [
    vue(),
    // 浏览器兼容问题配置
    legacyPlugin({
      targets: ['defaults', 'not IE 11'],
      additionalLegacyPolyfills: ['regenerator-runtime/runtime'],
      renderLegacyChunks: true,
      polyfills: [
        'es.symbol',
        'es.promise',
        'es.promise.finally',
        'es/map',
        'es/set',
        'es.array.filter',
        'es.array.for-each',
        'es.array.flat-map',
        'es.array.at',
        'es.object.define-properties',
        'es.object.define-property',
        'es.object.get-own-property-descriptor',
        'es.object.get-own-property-descriptors',
        'es.object.keys',
        'es.object.to-string',
        'web.dom-collections.for-each',
        'esnext.global-this',
        'esnext.string.match-all'
      ]
    })
  ]
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

最后打包结果会多出兼容版本的,名称中带有legacy的js、css文件,在需要的时候引用。没错,除了js还能兼容css。

Last Updated: 2024/9/4 15:42:44