前端面试题总结01

前端面试题总结01

一、http 状态码301 302 303 307 308之间的区别

301状态码:

​ 301转向,也叫301重定向或是301跳转,他表示客户端请求的资源被永久移动到了一个新的URL。浏览器会自动重定向到新的URL,并且搜索引擎会更新索引来放映这一变化,并且未来的请求都应该被转向到新的URL中。

302状态码:

​ 302重定向代表暂时性重定向。当服务器返回302时,他表示客户端请求的资源暂时被移动一个不同的URL中了。浏览器会重定向到一个新的URL中,但是不会更新索引,因为这是个临时的转移,在未来某个时候请求还是会使用原始的URL。

303状态码:

​ 303重定向也表示暂时性重定向,要求客户端使用GET请求获取新的资源。这个状态码意味着服务器已经创建了一个新的资源,客户端应该使用GET请求获取它。通常用于POST请求后的重定向,以防止客户端重复提交POST请求。

307状态码:

​ 307也表示暂时性重定向,类似于302,但是不同于302的是,307要求客户端的请求方式不变,如果原始请求方式是POST,那么重定向的请求也应该是POST请求。

308状态码:

​ 同301状态码,为永久重定向,但是区别在于,308要求重定向之后的请求方式不变。

二、301和302对于seo来说那个更好

301对seo更加友好。

301永久重定向和302临时重定向对用户来说最终看到的效果是一样的,但是对搜索引擎却不是一样的。当收到301状态码时,搜索引擎只需要重新拉取新URL的资源就行,而不用考虑旧URL的资源。但是如果收到的是302状态码重定向时,搜索引擎理论上也是会只抓取目标URL的资源,但是实际上302临时重定向会引起网络劫持的问题。

网络劫持:如果内容质量较差的网站A做了302临时重定向到内容质量较高的网站B,客户端请求网站A会得到网站B的资源,这样在不知不觉中,网站B就在为网站A做贡献,网站A的搜索排行提高。

三、跨域是什么,如何解决

违反浏览器的 同源策略(域名相同,端口相同,协议相同) 就会产生跨域。

解决跨域的方法:

1.document.domain解决主域相同,子域不同的跨域场景

浏览器是通过document.domain来判断两个页面是否同源的,所以只需要设置为相同的document.domain两个页面就可以共享cookie了。

1
2
//两个页面都设置为同一个
document.domain='xxxx.com'

2.window.postMessage()解决使用iframe下的跨域问题

1
2
3
4
5
6
7
8
9
10
//父窗口打开一个子窗口向子窗口发消息
var openWindow=window.open('http://a.com','title');
openWindow.postMessage('传递的消息',"http://a.com");
//子窗口接受消息
window.addEventListener('message',function(event){
//...逻辑
// event.origin 可以用来验证消息发送者的源
// event.data 包含了发送的消息
// event.source 是发送消息的窗口的引用
},false);

3.JSONP

由于<script/>标签拥有不受同源策略影响的特性,所以利用这一点JSONP可以用来解决跨域。

1
2
3
4
5
6
7
8
9
10
11
//原生写法
<script src='http://a.com?callback=dosomething'></script>
//向服务器http://a.com发送一个请求,查询请求的字符串有一个callback参数,用来指定回调参数的名字
//
//处理服务器回调的数据
<script>
function dosomething(res){
//服务器回调返回的数据
console.log(res);
}
</script>
1
2
3
4
5
6
7
8
//ajax写法
$.ajax({
url:'http://a.com/login',
type:"get",//只支持get请求
dataType:'jsonp',
jsonpCallback:'dosomething',//自定义回调函数的函数名
data:{}
})

4.CORS

– 普通的跨域请求:需要在服务端设置Access-Control-Allow-Origin

– 带cookie的跨域,需要前后端都进行设置

前端设置:

1
2
3
4
5
6
7
8
9
10
11
12
//原生写法
var xhr=new XMLHttpRequest();
//设置cookie
xhr.withCredentials=true;
xhr.open('post','http://a.com/login',true);
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xhr.send('user=admin')
xhr.onreadystatechange=function(){
if(xhr.readyState==4&&xhr.status==200){
//...处理逻辑
}
}
1
2
3
4
5
6
7
8
9
10
//ajax写法
$.ajax({
url:"http://a.com/login",
type:'get',
data:{},
xhrFields:{
withCredentials:true//设置是否携带cookie
},
crossDomain:true//会让请求头包含跨域的额外信息,但不会包含cookie
})
1
2
//axios写法
axios.defaults.withCredentials=true

5.webpack本地代理

Vue在vue.config.js中添加代理

1
2
3
4
5
6
7
8
9
10
11
12
//vue.config.js
devServer:{
proxy:{
'/api':{//代理
target:"http://a.com",//服务器域名或ip
changeOrigin:true,//是否开启跨域
pathRewrite:{
'^/api':""//把设置的拦截地址替换为空字符串
}
}
}
}

6.Nginx代理

​ 在打包上线之后进行nginx反向代理

四、jsonp有什么缺点

  1. 服务端必须要支持JSON数据格式,否则该方法不能解决跨域。
  2. 安全性无法保障,JSONP存在安全风险,因为它是完全信任服务器返回的数据的,这导致JSONP容易受到恶意脚本的攻击。
  3. 无法抛出错误。由于<script/>标签无法抓取和捕获错误,这导致出现报错很难进行调试。
  4. 只支持get请求的跨域问题,非常不灵活。

五、图片base64和外链的应用场景,各自的优缺点

图片base4:

​ 应用场景:将图片转换为base64之后,可以将其直接嵌入HTML,CSS或是JS中,不需要额外再发送HTTP请求。

​ 优点:

​ 1.减少了HTTP请求,有利于提高页面的加载速度。

​ 2.减少服务器的请求和压力

​ 缺点:

​ 1.base64编码之后的图片的文件地址会增加,对于越大型图片,base64编码之后的字符串越多,页面体积就 会越大。

​ 2.由于文件是写入页面中的,每次修改都需求修改整个文件。

外链:

​ 应用场景:大多数图片是采用外链形式的,这些图片都是存储在服务器中。

​ 优点:

​ 1.外链图片不会增加文件大小。

​ 2.更新图片时只需要修改服务器地址或是直接在服务器修改,不需要修改整个文件。

​ 缺点:

​ 1.增加了HTTP请求,可能会影响页面的加载速度。

​ 2.对于图片资源较多的应用,会额外增加HTTP请求的次数,再次拖慢页面加载的速度。

总结:对于大图片,适合使用外链引用;对于体积小且数量多的图片,适合采用base64的形式引用。

六、http缓存机制

七、https的握手过程

八、Set/Map的区别

set和map都是常见的数据结构,他们的区别是:

Set:

​ 1. Set集合中每个元素都是唯一的,且集合中的元素没有特定的顺序(按照插入的顺序)。

​ 2. Set集合常用于数据的去重

1
2
3
4
5
6
7
8
//js中set的常见用法
//创建一个Set
let mySet=new Set();
mySet.add(1);
mySet.add(2);
mySet.add(3);
mySet.add(1);//不会被插入
console.log(mySet);//Set(3) {1,2,3}

Map:

1. Map是一种键值对的集合,其中键是唯一的,但是值可以重复。
2. 任何数据类型都可以组成一个键值对。
1
2
3
4
5
6
7
8
9

//js中Map的常见用法
let myMap=new Map();
myMap.set('name','小明');
myMap.set('age',10);
myMap.set('sex','男');
myMap.set('name','小方');//此时name值就变为了小方
console.log(myMap);//Map(3) {'name' => '小方', 'age' => 10, 'sex' => '男'}

九、react hook的局限性

hook钩子函数的局限性:

1
2
3
4
5
6
7
1. 只能在react函数组件的顶层使用,不能在循环或其他条件语句中使用。
2. hook只能在函数组件中使用,不能在类组件中使用。
3. 自定义的hook可能会导致重复渲染,影响性能。
4. hook中的`useEffect`可能会导致多个组件之间的副作用交织。
5. hook中的`useState`在处理复杂对象或是数组时,可能会导致页面的破坏性更新。
6. 当页面中的`useEffect``useState`使用过多时,会难以调试和维护。
7. 严格模式下,hook会受到限制,例如,自定义的hook必须要以'use'开头/hook的执行顺序必须保持稳定/hook的副作用操作会被严格监控。

十、setState和hook的区别

setState hook
用法 在类式组件中使用 在函数式组件中使用
调用位置 setState作为一个方法,可以在生命周期或是事件处理函数中进行调用 不能在条件语句中进行调用,只能在函数式组件大的顶部调用
状态更新的影响 组件会重新渲染 组件会重新渲染
代码组织 setState可以分散在各个不用的位置,组织上比较混乱 在顶层使用,代码组织上更加紧凑

十一、Symbol是什么,一般用来做什么

Symbol是ES6中引入的一种新的基本数据类型(字符串String,数字Number,布尔值true/false,空值null,未定义undefined,Symbol,大数bigInt),它的特点是:

1
2
3
1.Symbol的值唯一且不变的。//最主要特点
2.Symbol的值不能与其他数据进行运算。
3.Symbol定义的对象属性不能使用for...in来循环来获取,但是可以使用Reflect.ownKeys(obj)得到。(Reflect.ownKeys()返回一个数组,内容是传入对象的属性的键)

Symbol的基本用法

1
2
3
4
5
6
7
8
let sy1=Symbol('这是一个描述');
console.log(sy1);//Symbol('这是一个描述')
typeof(sy1);//symbol

//即便是相同描述的Symbol返回的值也不相同
let sy2=Symbol('这是一个描述');
sy1==sy2; //false
sy1===sy2; //false

Symbol基本用法

Symbol本身的使用场景较少:

  1. 由于每一个Symbol的值都不相同,可以作为对象的属性名来使用,这样可以防止属性名重复

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    let sy=Symbol('key1');

    //作为对象的属性名:
    //写法一
    let syObject={};
    syObject[sy]="value";
    console.log(syObject);//{Symbol(key1):'value'}

    //写法二
    let syObject={
    [sy]:'value'
    }
    console.log(syObject);//{Symbol(key1):'value'}

    //写法三
    let syObject={}
    Object.defineProperty(syObject,sy,{value:"value"});
    console.log(syObject);//{Symbol(key1):'value'}
  2. 定义常量

    使用const定义的字符串不能保证常量是独特的,可能会引发一些问题:

    const定义的字符串不能保证唯一性

但是const定义的Symbol却始终是唯一的,这样可以保证常量的唯一性:

const定义的Symbol常量是唯一的

十三、csrf是什么,如何防范

是什么:

csrf(cross-site request forgery )跨站请求伪造,攻击者通过引诱用户点击带有恶意攻击的图片,表单或是链接等内容,对网站发起带有用户已认证的身份的攻击。

如何防范:

1
2
3
4
5
1.每次请求时都携带一个随机的令牌(Token),由于攻击者无法伪造有效的令牌,所以只需要校验令牌的有效性,拒绝无效的令牌就可以避免csrf攻击。
2.Referer校验。在处理请求时,校验请求的Referer头部信息,确保请求的来源是合法的,由于Referer头部信息是浏览器自动发送的,攻击者无法伪造,所以也可以避免csrf攻击。
3.SameSite Cookie,最新的防范csrf的方法。在设置Cookie时,指定CookieSame Site的属性是Strict或是Lax,以限制Cookie的跨站访问
---Strict:只允许同站点访问,禁止任何跨站访问
---Lax:允许一定程序的跨站访问(同时也导致SameSite Cookie并不能完全的解决csrf攻击)

十四、sql注入是什么,如何防范

sql注入是一种常见的网咯安全攻击,攻击者执行未授权的sql语句对数据库进行操作,通常发生在需要用户输入的地方,如登录注册表单,搜索框等。

例如:

1
2
//获取用户输入的用户名和密码进行验证
SELECT * FROM user WHERE username='input_username' AND password='input_password'

如果用户输入的用户名为'forge_username'OR 1=1,那么程序执行的就是:

1
SELECT * FROM user WHERE username='forge_username' OR 1=1 AND password='input_password'

由于1=1是恒成立的,所以即便是密码随意输入,也可以直接登录到程序中去。

如何防范:

  1. 使用参数化查询。用户输入的参数作为参数传递给后端进行sql查询,而不是直接插入到sql中。
  2. 使用存储过程。存储过程可以预编译sql语句并存储在数据库中,避免直接执行动态的sql语句。
  3. 减少用户的权限。尽量赋予用户最小的数据库操作权限。
  4. 避免向用户暴露数据库的结构。处理错误信息时不要包含数据库的结构信息。
  5. 使用ORM框架。ORM(对象关系映射)可以帮助开发者直接编写sql语句,减少sql注入的可能性。
  6. 规范sql语句的编写,避免直接拼接用户输入的数据。

十五、react调用setState之后会发生什么

1
2
3
4
5
//setState执行之后会发生的事情:
第一:触发组件重新渲染。react会比较新旧状态,然后确定是否需要更新组件的视图。
第二:调用render方法。如果视图需要更新,那么react就会需要调用render方法。
第三:更新虚拟DOM。react会将新的DOM树跟之前的进行比较,找出需要更新的部分。
第四:更新真实DOM。将需要更新的部分应用到真实DOM中,用户界面会放映出最新的状态。

十六、nodejs事件循环机制

十七、pm2的原理,有哪些模式

十八、移动端一个元素的拖动如何实现和优化

暂置

元素拖拽库

十九、描述链表的反转如何实现,复杂度是多少

实现一个反转链表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//一个链表的结构
class LinkNode{
constructor(value,next=null){
this.value=value;
this.next=next;
}
}
//反转一个链表
function reverseLinked(head){
let prv=null;
let curr=head;
let next=null;
while(curr!==null){
next=curr.next;
curr.next=prev;
prev=curr;
curr=next;
}
return prev;//新的头结点
}

时间复杂度:顺序执行O(n)

空间复杂度:只需要几个额外的变量,所以是O(1)

二十、实现instanceOf

二十一、实现一个对象被for of遍历

二十二、实现链表的添加,删除。复杂度是多少


前端面试题总结01
https://chen77.top/2024/01/03/interview/前端面试题总结01/
作者
小陈
发布于
2024年1月3日
许可协议