部分答案整理ing......,建议常回来看看,说不定答案就整理好了
写在前面:暑假我(二本,科班,无实习经验)准备半个多月,前前后后共面试了8家公司,找到一家还不错的实习(base 成都,配macbook pro ➕DELL显o示器,🈶️很多零食水果,不加班,导师一对一),目前也在准备秋招。
遇到的题目不算难,算法较少,我对标的大部分是中厂,和网易雷火
拖了半个月的硬实力终于整理好了(因为白天在上班,回家就开始摆烂,最近迷上了🥣英雄联盟手游)
软实力点击下方
2022的暑假,历时半个月面试n次后找到满意的实习之软实力(前端实习,中大厂) - 掘金 (juejin.cn)
正文开始
硬实力很明显就是面试题,面试题很多,网上的集合也特别多,我这儿分享几个我常用的面试题集合和网站
我的背题路线是根据2的面试题合集和掘金上一些面试题合集文章来背基础题,✔自己会做总结和自己的理解,结合牛客刷一些简单算法和单选多选题,没事就看看山月大佬的博客和网站。
- 我的语雀面试题知识库链接 www.yuque.com/docs/share/… 《js》
www.yuque.com/docs/share/… 《html、css、网络、Git面试题》
www.yuque.com/docs/share/… 《vue》
里面是我整理的常考的面试题和很多资源,文章末也有对应的掘金链接
- 这篇也写的很好,我经常看 做了一份前端面试复习计划,保熟~ - 掘金 (juejin.cn)
30 道 Vue 面试题,内含详细讲解(涵盖入门到精通,自测 Vue 掌握程度)
- 山月大佬的面试题网站,里面的题算比较高精尖的,但被问到回答出来绝对加分(亲测有效) 前端常见面试题总结 | 大厂面试题每日一题 (shanyue.tech)
4.牛客 牛客网-找工作神器|笔试题库|面试经验|实习招聘内推,求职就业一站解决_牛客网 (nowcoder.com)
以下,是我和朋友出去面试前端实习遇到的题目总结(内含部分网易雷火笔试题,部分答案不确定,暂无解析)
后面的数字是出现次数💯,加了⭐说明被问过很多次
强烈建议看到题目,先自己想一哈,再看答案
So wo 贴心的➕了解析折叠框,👍赞我一下不过分吧
html
H5语义化的作用 2️⃣
解析
如 header footer section 等
- 让⼈更容易读懂(增加代码可读性)。
- 让搜索引擎更容易读懂,有助于爬⾍抓取更多的有效信息,爬⾍依赖于标签来确定上下⽂和各个关键字的权重(SEO)。
- 在没有 CSS 样式下,⻚⾯也能呈现出很好地内容结构、代码结构。
CSS
1.defer和async的区别 1️⃣
解析
• script :会阻碍 HTML 解析,只有下载好并执⾏完脚本才会继续解析 HTML。
• async script :解析 HTML 过程中进⾏脚本的异步下载,下载成功⽴⻢执⾏,有可能会阻断 HTML 的解析。
• defer script:完全不会阻碍 HTML 的解析,解析完成之后再按照顺序执⾏脚本。
2.css的继承元素 2️⃣
解析
1、字体系列属性
- font:组合字体
- font-family:规定元素的字体系列
- font-weight:设置字体的粗细
- font-size:设置字体的尺寸
- font-style:定义字体的风格
- font-variant:设置小型大写字母的字体显示文本,这意味着所有的小写字母均会被转换为
- 大写,但是所有使用小型大写字体的字母与其余文本相比,其字体尺寸更小。
- font-stretch:允许你使文字变宽或变窄。所有主流浏览器都不支持。
- font-size-adjust:为某个元素规定一个 aspect 值,字体的小写字母 "x" 的高度与
- "font-size" 高度之间的比率被称为一个字体的 aspect 值。这样就可以保持首选字体的 x-height。
2、文本系列属性
- text-indent:文本缩进
- text-align:文本水平对齐
- line-height:行高
- word-spacing:增加或减少单词间的空白(即字间隔)
- letter-spacing:增加或减少字符间的空白(字符间距)
- text-transform:控制文本大小写
- direction:规定文本的书写方向
- color:文本颜色
3、元素可见性:visibility
4、表格布局属性:
caption-side、border-collapse、border-spacing、empty-cells、table-layout
5、列表属性: list-style-type、list-style-image、list-style-position、list-style
6、生成内容属性: quotes
7、光标属性: cursor
8、页面样式属性: page、page-break-inside、windows、orphans
9、声音样式属性:
speak、speak-punctuation、speak-numeral、speak-header、speech-rate、volume、voice-family、pitch、pitch-range、stress、richness、、azimuth、elevation
3.写5个css隐藏元素的属性(网易雷火笔试) 1️⃣
解析
1 opacity:0;
2 display:none;
3 visibility: hidden;
4
position : absolute;
top : -9999px ;
left : -9999px ;
5 overflow:hidden
4.CSS两栏布局 2️⃣
5.CSS三栏布局 ⭐
解析
1.Grid
.grid-container {
display: grid;
grid-template-columns: 1fr 1fr 1fr(fraction);
gap: 1rem;
}
2.flex
.flex-container {
display: flex;
flex-wrap: wrap;
// gap: 1rem;
.item {
flex: 0 0 calc(100% / 3);
/* flex : 1; */
}
}
6.flex实现 三栏布局,要求每栏中间间隔10px 1️⃣
解析
justify-content:space-evenly;
7.flex布局有哪些属性,flex:1是什么意思 ⭐
解析
<https://www.ruanyifeng.com/blog/2015/07/flex-grammar.html> 参考阮一峰讲的flex布局
**flex: 1 ,它具体包含了以下的意思:**
- **flex-grow: 1** :该属性默认为 0 ,如果存在剩余空间,元素也不放⼤。设置为 1 代表会放⼤。
- **flex-shrink: 1** :该属性默认为 1 ,如果空间不⾜,元素缩⼩。
- **flex-basis: 0%** :该属性定义在分配多余空间之前,元素占据的主轴空间。浏览器就是根据这个属性来计算 是否有多余空间的。默认值为 auto ,即项⽬本身⼤⼩。设置为 0% 之后,因为有 flex-grow 和 flex-shrink 的设置会⾃动放⼤或缩⼩。在做两栏布局时,如果右边的⾃适应元素 flex-basis 设为 auto 的话,其本身⼤⼩将会是 0 。
8.动画 2️⃣
CSS动画简介 - 阮一峰的网络日志 (ruanyifeng.com)
9.垂直居中 ⭐
解析
1. 利⽤绝对定位,设置 left: 50% 和 top: 50% 现将⼦元素左上⻆移到⽗元素中⼼位置,然后再通 过 translate 来调整⼦元素的中⼼点到⽗元素的中⼼。该⽅法可以**不定宽⾼**。.father { position: relative; }
.son {
position: absolute;
left: 50%; top: 50%;
transform: translate(-50%, -50%);
}
-
利⽤ flex ,最经典最⽅便的⼀种了,不⽤解释,定不定宽⾼⽆所谓的。
.father {
display: flex;
justify-content: center;
align-items: center;
}
-
grid网格,不设置宽高
.father{
display: grid;
align-items: center;
justify-items: center;
}
4.不设置宽高,原理我暂时没搞明白
.father{
display:flex;
}
.son{
margin:auto;
}
-
利⽤绝对定位,⼦元素所有⽅向都为 0 ,将 margin 设置为 auto ,由于宽⾼固定,对应⽅向实现 平分,该⽅法必须盒⼦有宽⾼。
.father { position: relative; }
.son {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0px;
margin: auto;
height: 100px;
width: 100px;
}
-
利⽤绝对定位,设置 left: 50% 和 top: 50% 现将⼦元素左上⻆移到⽗元素中⼼位置,然后再通过 margin-left 和 margin-top 以⼦元素⾃⼰的⼀半宽⾼进⾏负值赋值。该⽅法必须定宽⾼。
.father { position: relative; }
.son {
position: absolute;
left: 50%;
top: 50%;
width: 200px;
height: 200px;
margin-left: -100px;
margin-top: -100px;
}
10.清除浮动 ⭐
解析
浮动会导致父元素高度塌陷,并且兄弟元素也会变为浮动 1.clear:both 1.1 在兄弟元素+clear:both
1.2 通过给父元素:after伪元素
.parent:after{
content:'';
height:0;
clear:both;
display:block;
}
1.3 加一个子元素添加clear
2.利用BFC
给父元素变成BFC overflow:auto
11.transform 1️⃣
常用translate位移,rotate旋转
CSS transform 属性 (w3school.com.cn)
12.position的absolute和relative的参考点 2️⃣
解析
绝对定位position参考有定位属性的父元素,相对定位relative参考元素原来的位置,详细大家搜下其他的文章讲的很详细13.行、块元素 2️⃣
解析
⾏内元素 inline:不能设置宽⾼,多个元素共享⼀⾏,占满的时候会换⾏
span 、input 、textarea 、label 、select、p、button
块级元素block:
可以设置宽⾼,⼀个元素占满⼀整⾏
h1/h2/h3/h4/h5、div、ul、li、table
inline-block:
img
可以设置宽⾼,多个元素共享⼀⾏,占满的时候会换
JS/TS
1.事件循环 event loop ⭐
这篇文章很赞
这一次,彻底弄懂 JavaScript 执行机制 - 掘金 (juejin.cn)
1.1 什么是事件循环,说一下怎么循环的?
解析
我们都知道 Js 是单线程,但是⼀些⾼耗时操作就带来了进程阻塞问题。为了解决这个问题,Js 有两种任务 的执⾏模式:同步模式(Synchronous)和异步模式(Asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入”任务队列”(task queue)的任务,只有”任务队列”通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
-
同步和异步任务分别进入不同的执行"场所",同步的进入主线程,异步的进入Event Table并注册函数。
-
当指定的事情完成时,Event Table会将这个函数移入Event Queue。
-
主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行。
-
上述过程会不断重复,也就是常说的Event Loop(事件循环)。
event loop是js的执行机制
1 判断宏任务队列是否为空
◦ 不空 --> 执⾏最早进⼊队列的任务 --> 执⾏下⼀步
◦ 空 --> 执⾏下⼀步
2 判断微任务队列是否为空
◦ 不空 --> 执⾏最早进⼊队列的任务 --> 继续检查微任务队列空不空
◦ 空 --> 执⾏下⼀步
因为⾸次执⾏宏队列中会有 script(整体代码块)任务,所以实际上就是 Js 解析完成后,在异步任务中,会先 执⾏完所有的微任务,这⾥也是很多⾯试题喜欢考察的。需要注意的是,新创建的微任务会⽴即进⼊微任务队 列排队执⾏,不需要等待下⼀次轮回。
1.2 宏、微任务有哪些?
解析
在异步模式下,创建异步任务主要分为宏任务与微任务两种。ES6 规范中,宏任务(Macrotask) 称为 Task, 微任务(Microtask) 称为 Jobs。宏任务是由宿主(浏览器、Node)发起的,⽽ 微任务由 JS ⾃身发起。
| 宏任务 | 微任务 |
|---|---|
| setTimeout | promise(then catch finally) |
| setInterval | process。nextTick() |
| I/O,事件队列 | queueMicrotask |
| setImmediate(Node环境) | MutationObserver |
| messageChannel | requestAnimationrame |
| script代码块 |
1.3 async和await和promise的输出顺序(网易雷火笔试有道类似的)
async function async1(){
console.log('async1 start')
await async2()
console.log('async1 end')
}
async function async2(){
console.log('async2')
}
console.log('script start')
setTimeout(function(){
console.log('setTimeout')
},0)
async1();
new Promise(function(resolve){
console.log('promise1')
resolve();
}).then(function(){
console.log('promise2')
})
console.log('script end')
答案
// script start
// async1 start
// async2
// promise1
// script end
// async1 end
// promise2
// setTimeout
当遇到await关键字的时候,异步函数的执行被暂停,**async函数中剩余的代码会在微任务中**运行而不是一个常规(宏)任务!
1.4 输出顺序
console.log('1');
setTimeout(function() {
console.log('2');
process.nextTick(function() {
console.log('3');
})
new Promise(function(resolve) {
console.log('4');
resolve();
}).then(function() {
console.log('5')
})
})
process.nextTick(function() {
console.log('6');
})
new Promise(function(resolve) {
console.log('7');
resolve();
}).then(function() {
console.log('8')
})
setTimeout(function() {
console.log('9');
process.nextTick(function() {
console.log('10');
})
new Promise(function(resolve) {
console.log('11');
resolve();
}).then(function() {
console.log('12')
})
})
解析
这里要⚠️注意:
1.`new Promise` 属于同步任务,所以会直接执行,里面的then才属于微任务
2.两个wetTimeout属于两个不同的宏任务,第一个宏任务里面全部执行完才执行第二个
1.5 微任务执行过程中,创建了新的微任务会怎么执行
解析
会在这次微任务执行完后立即执行新创建的微任务
2.this指向 ⭐
一般都是笔试题会有,选择题或问答题的形式
JS 中 this 指向问题 - 掘金 (juejin.cn)
3.let var 用for循环输出⭐
for (var i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i);
}, 1000);
}
for (let i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i);
}, 1000);
}
解析
// 3 3 3 // 0 1 2 因为let的作用域 饮用阮一峰老师ES6书中的解释2. let 和 const 命令 - let 命令 - 《阮一峰 ECMAScript 6 (ES6) 标准入门教程 第三版》 - 书栈网 · BookStack
3.let const 和 var 的区别 ⭐
康康阮一峰老师的书📖就懂了
[2. let 和 const 命令 - let 命令 - 《阮一峰 ECMAScript 6 (ES6) 标准入门教程 第三版》 - 书栈网 · BookStack](www.bookstack.cn/read/es6-3r…
还有个问题:const在什么你能被改变,答案:为对象时,因为用的是引用地址
4.=== 和 == 的输出问题 2️⃣
NaN===NaN吗? 答案:NAN不等于任何值,包括自己
建议百度
5.数据类型(8种)⭐
解析
在 JS 中共有 8 种数据类型,分别为: Undefined 、 Null 、 Boolean 、 Number 、 String 、 Object 、 Symbol 、 BigInt 。-
值类型是直接存储在栈(stack) 中的简单数据段,占据空间⼩、⼤⼩固定,属于被频繁使⽤数据, 所以放⼊栈中存储;会被自动清理,可以改变原始值;
-
引⽤类型(Object)存储在堆(heap) 中的对象,占据空间⼤、⼤⼩不固定。如果存储在栈中,将会影响程序 运⾏的性能;不会被清理,不能改变原始值,因为引用地址
其中 Symbol 和 BigInt 是 ES6 新增的数据类型,可能会被单独问:
• Symbol 代表独⼀⽆⼆的值,最⼤的⽤法是⽤来定义对象的唯⼀属性名。
• BigInt 可以表示任意⼤⼩的整数。
6.基本数据类型引出的堆和栈的问题
6.1 堆和栈哪个能改变原始值
解析
栈会改变原始值,堆不会6.2 堆和栈哪个能被自动清除
解析
栈会被自动清理,堆不会7.判断基本数据类型和引用数据类型 1️⃣
解析
typeof:能判断所有值类型,函数。不可对 null、Object、Array进⾏精确判断,因为都返回 object 。instanceof:能判断对象类型,不能判断Boolean、Number、String,
判断该对象上是否有构造函数的原型。object.proto === constructor.prototype (object实例对象,constructor构造函数) 举个🌰:
function C(){} //构造函数
const o = new C() //实例对象
console.log(o intanceof C) //true
//o.__proto__ === C.prototype
Object.prototype.toString.call():所有原始数据类型都是能判断的,还有 Error 对象,Date 对象等。
在⾯试中有⼀个经常被问的问题就是:如何判断变量是否为数组?
Array.isArray(arr); // true
arr.__proto__ === Array.prototype; // true
arr instanceof Array; // true
Object.prototype.toString.call(arr); // "[object Array]"
8.防抖节流(网易雷火笔试手撕 )⭐
解析
debounce防抖 将多次⾼频操作优化为只在最后⼀次执⾏,通常使⽤的场景是:⽤户输⼊,只需再输⼊完成后做⼀次输⼊校验即可。
function debounce(fn,delay){
var timer = null
return function(){
if(timer){
clearTimeout(timer)
}
var arg = arguments[0]
timer = setTimeout(function(){
fn(arg)
},delay)
}
}
function show(ev){
console.log(ev)
}
document.onwheel = debounce(show,1000)
throttle节流 每隔⼀段时间后执⾏⼀次,也就是降低频率,将⾼频操作优化成低频操作,通常使⽤场景: 滚动 条事件 或者 resize 事件,通常每隔 100~500 ms执⾏⼀次即可。
如果重复执行事件,会在第一次执行事件后指定时间
//我们设置一个定时器,再触发事件的时候,如果定时器存在,就不执行,直到定时器执行,然后执行函数,清空定时器,这样就可以设置下个定时器。
// 定时器实现
function throttle(func, wait) {
var timeout;
var previous = 0;
return function() {
context = this;
args = arguments;
if (!timeout) {
timeout = setTimeout(function(){
timeout = null;
func.apply(context, args)
}, wait)
}
}
}
function show(e){
console.log(e)
}
document.onwheel = throttle(show,1000)
9.深浅拷贝 ⭐
解析
/**
* 深拷贝关注点:
* 1. JavaScript内置对象的复制: Set、Map、Date、Regex等
* 2. 循环引用问题
* @param {*} object
* @returns
**/
function deepClone(target, map = new WeakMap()) {
if (typeof target === 'object') {
let cloneTarget = Array.isArray(target) ? [] : {};
if (map.get(target)) {
return map.get(target);
}
map.set(target, cloneTarget);
for (const key in target) {
cloneTarget[key] = deepClone(target[key], map);
}
return cloneTarget;
} else {
return target;
}
};
/**
* 浅拷贝
*/
function clone(target){
let result={};
return Object.assign(result,target)
}
any number string null undefined 数组[] 枚举enum never void
10.localStorage sessionStorage和cookie的区别 ⭐
解析
#### localStorage sessionStorage的区别• HTML5 专⻔为存储来设计的,最⼤可存 5M。
• API 简单易⽤, setItem getItem。
• 不会随着 http 请求被发送到服务端。 它们的区别:
• localStorage 数据会永久存储,除⾮代码删除或⼿动删除。
• sessionStorage 数据只存在于当前会话,浏览器关闭则清空。
cookie
• 本身⽤于浏览器和 server 通讯。
是保存在客户端的,⼀般由后端设置值,可以设置过期时间 储存⼤⼩只有4K。⼀般⽤来保存⽤户的
• 被“借⽤”到本地存储来的。
• 可⽤ document.cookie = '...' 来修改。 其缺点:
• 存储⼤⼩限制为 4KB。
• http 请求时需要发送到服务端,增加请求数量。
• 只能⽤ document.cookie = '...' 来修改,太过简陋
• 在http下cookie是明⽂传输的, 较不安全
cookie属性
http-only:不能被客户端更改访问,防⽌XSS攻击(保证cookie安全性的操作) Secure:只允许在https下传输
Max-age: cookie⽣成后失效的秒数
expire: cookie的最⻓有效时间,若不设置则cookie⽣命期与会话期相同
11.Promise ⭐
11.1 promise的理解 ⭐
解析
https://es6.ruanyifeng.com/#docs/promise1 简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
(1)对象的状态不受外界影响。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。
2 Promise 会有三种状态
-
Pending 等待
-
Fulfilled 完成
-
Rejected 失败
3 状态只能由 Pending --> Fulfilled 或者 Pending --> Rejected,且⼀但发⽣改变便不可⼆次修改;
4 Promise 中使⽤ resolve 和 reject 两个函数来更改状态;
5 then ⽅法内部做但事情就是状态判断
◦ 如果状态是成功,调⽤成功回调函数
◦ 如果状态是失败,调⽤失败回调函数。
11.2 promise.then和链式调用(不用then链式调用可以用啥实现链式调用) 1️⃣
解析
采用链式的then,可以指定一组按照次序调用的回调函数。这时,前一个回调函数,有可能返回的还是一个Promise对象(即有异步操作),这时后一个回调函数,就会等待该Promise对象的状态发生变化,才会被调用。
还可以用await和async实现链式调用
11.3 promise.all 1️⃣
解析
用于将多个 Promise 实例,包装成一个新的 Promise 实例 const p = Promise.all([p1, p2, p3]);
上面代码中,Promise.all()方法接受一个数组作为参数,p1、p2、p3都是 Promise 实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。另外,Promise.all()方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。
12. Token的理解 1️⃣
解析
服务端生成的加密字符串,当用户第一次使用账号密码成功进行登录后,服务器便生成一个Token及Token失效时间并将此返回给客户端,若成功登陆,以后客户端只需在有效时间内带上这个Token前来请求数据即可,无需再次带上用户名和密码。token 也称作令牌,由uid+time+sign[+固定参数] token 的认证方式类似于临时的证书签名, 并且是一种服务端无状态的认证方式, 非常适合于 REST API 的场景. 所谓无状态就是服务端并不会保存身份认证相关的数据。
特点
- Token具有随机性、不可预测性、时效性、无状态、跨域等特点。
- Token完全由应用管理,所以它可以避开同源策略
- Token可以避免CSRF攻击
- Token可以是无状态的,可以在多个服务间共享
- Token是在服务端产生的。如果前端使用用户名/密码向服务端请求认证,服务端认证成功,那么在服务端会返回Token给前端。前端可以在每次请求的时候带上Token证明自己的合法地位。如果这个Token在服务端持久化(比如存入数据库),那它就是一个永久的身份令牌。
token组成
- uid: 用户唯一身份标识
- time: 当前时间的时间戳
- sign: 签名, 使用 hash/encrypt 压缩成定长的十六进制字符串,以防止第三方恶意拼接
- 固定参数(可选): 将一些常用的固定参数加入到 token 中是为了避免重复查库
🤓token的过期时间
为了解决在操作过程不让用户感到Token失效的问题,有一种方案是在服务器端保存Token状态,用户每次操作都会自动刷新(推迟)Token的过期时间。为了提升效率、减少消耗,会把Token的过期时间保存在缓存或者内存中。
另一种方案是使用RefreshToken,它可以避免频繁的读写操作。这种方案中,服务端无需刷新Token的过期时间,一旦Token过期,就反馈给前端,前端使用RefreshToken申请一个全新Token继续使用。
存放
token在客户端一般存放于localStorage,cookie,或sessionStorage中。在服务器一般存于数据库中
token认证流程
token 的认证流程与cookie很相似
- 用户登录,成功后服务器返回Token给客户端。
- 客户端收到数据后保存在客户端
- 客户端再次访问服务器,将token放入headers中
- 服务器端采用filter过滤器校验。校验成功则返回请求数据,校验失败则返回错误码
token可以抵抗csrf,cookie+session不行
因为form 发起的 POST 请求并不受到浏览器同源策略的限制,因此可以任意地使用其他域的 Cookie 向其他域发送 POST 请求,形成 CSRF 攻击。在post请求的瞬间,cookie会被浏览器自动添加到请求头中。但token不同,token是开发者为了防范[CSRF]或XSRF(Cross-site request forgery跨站请求伪造)而特别设计的令牌,浏览器不会自动添加到headers里,攻击者也无法访问用户的token,所以提交的表单无法通过服务器过滤,也就无法形成攻击。
13. get和post的区别 2️⃣
解析
1. 冪等/不冪等(可缓存/不可缓存) get请求是冪等的,所以get请求的数据是可以缓存的\ post请求是不冪等的,查询查询对数据是有副作⽤ 的,是不可缓存 2. 传参 get传参,参数是在url中的 准确的说get传参也可以放到body中,只不过不推荐使⽤\ post传参,参数是在请求体中 准确的说post传参也可以放到url中,只不过不推荐使用 3. 安全性 get较不安全 post较为安全 准确的说两者都不安全,都是明⽂传输的,在路过公⽹的时候都会被访问到, 不管是url还是 header还是 body,都会被访问到,要想做到安全,就需要使⽤ https 4. 参数长度 get参数⻓度有限,是较⼩的;准确来说,get在url传参的时候是很⼩ 的; post传参⻓度不受限制5.发送数据 post传参发送两个请求包,⼀个是请求头,⼀个是请求体,请求头 发送后服务器进⾏验证,要是验证通过 的话就会给客户端发送⼀个100-continue 的状态码,然后就会发送请求体
6.字符编码:get在url上传输的时候只允许ASCII编码
14. window.location的输出 1️⃣(网易雷火笔试)
window.location - Web API 接口参考 | MDN (mozilla.org)
15. set和map的区别 1️⃣(网易雷火笔试)
解析
应⽤场景Set⽤于数据重组,Map⽤于数据储存,都可以for...of 遍历Set:
(1)成员不能重复 、Set的值是唯⼀的可以做数组去重
(2)只有键值没有键名
Map:
(1)本质上是健值对的集合
(2)可以遍历,可以跟各种数据格式转换
16. 原型链和原型的理解 1️⃣
解析
原型:每⼀个 JavaScript 对象(null 除外)在创建的时候就会与之关联另⼀个对象,这个对象就是 我们所说的原型,每⼀个对象都会从原型"继承"属性,其实就是 prototype 对象。• 原型链:由相互关联的原型组成的链状结构就是原型链。
17. await语法糖封装了什么,async和await 1️⃣
解析
Async 是 Generator 的一个语法糖。
async 对应的是 * 。
await 对应的是 yield 。
async/await 自动进行了 Generator 的流程控制。
18. 事件代理 1️⃣
解析
JavaScript高级程序设计: 事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。
事件委托的原理
事件委托也叫事件委派,就是利用 DOM 的冒泡事件流,注册最少的监听器,实现对 DOM 节点的所有子元素进行事件群控。
为什么要使用事件委托
一般来讲,如果一个元素需要注册事件,那我们会直接为此元素注册事件处理程序。那如果有更多的元素,比如一百个,甚至更多;比如我们需要为一百个 li 元素注册想同的点击事件,那就要用循环遍历,注册一百个事件处理程序。在 JS 中,添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能,因为需要不断的与 DOM 节点进行交互,访问 DOM 的次数越多,引起浏览器重绘与重排的次数也就越多,就会延长整个页面的交互就绪时间;同时,对象越多,内容占用就越大。如果要用事件委托,就会将所有的操作放到 JS 程序里面,与 DOM 的操作就只需要交互一次,从而提高性能。
事件委托优点
- 减少DOM操作,提高性能
- 随时可以添加子元素,添加的子元素会自动有相应的处理事件
19. 写一个函数能找到DOM中有指定class的节点(不能使用原生的getClassName和queryAll)1️⃣
还没研究明白
20. 垃圾回收机制 1️⃣
解析
两种垃圾回收策略
• 标记清除:标记阶段即为所有活动对象做上标记,清除阶段则把没有标记(也就是⾮活动对象)销毁。
• 引⽤计数:它把对象是否不再需要简化定义为对象有没有其他对象引⽤到它。如果没有引⽤指向该对象 (引⽤计数为 0),对象将被垃圾回收机制回收。
标记清除的缺点
• 内存碎⽚化,空闲内存块是不连续的,容易出现很多空闲内存块,还可能会出现分配所需内存过⼤的对 象时找不到合适的块。
• 分配速度慢,因为即便是使⽤ First-fit 策略,其操作仍是⼀个 O(n) 的操作,最坏情况是每次都要遍历到 最后,同时因为碎⽚化,⼤对象的分配效率会更慢。
解决以上的缺点可以使⽤ 标记整理(Mark-Compact)算法 ,标记结束后,标记整理算法会将活着的对 象(即不需要清理的对象)向内存的⼀端移动,最后清理掉边界的内存
## 引⽤计数的缺点
• 需要⼀个计数器,所占内存空间⼤,因为我们也不知道被引⽤数量的上限。
• 解决不了循环引⽤导致的⽆法回收问题。
v8中的垃圾回收机制
-
Scavenge,工作在新生代,把from space中的存活对象移至to space -
Mark-Sweep,标记清除。新生代的某些对象由于过度活跃会被移至老生代,此时对老生代中活对象进行标记,并清理死对象 -
Mark-Compact,标记整理。
分代式垃圾回收
新生代
新生代对象是通过一个名为 Scavenge 的算法进行垃圾回收,在 Scavenge算法 的具体实现中,主要采用了一种复制式的方法即 Cheney算法
Cheney算法 中将堆内存一分为二,一个是处于使用状态的空间我们暂且称之为 使用区,一个是处于闲置状态的空间我们称之为 空闲区
21. dom添加节点 1️⃣
解析
any number string null undefined 数组[] 枚举enum never void
22. js继承机制 1️⃣
解析
any number string null undefined 数组[] 枚举enum never void
23. ts的类
解析
any number string null undefined 数组[] 枚举enum never void
24. ts中interface和type的关系 1️⃣
解析
interface和type差别不是很大
type:与接口不同,类型别名还可以用于其他类型,如基本类型(原始值)、联合类型、元组
25. 在webSocket中使用token
解析
1.2.通过query参数传输
26. token过期怎么办
解析
采用refresh'Token的方式对token过期进行处理算法和正则
1.在字符串中找到最长的回文串
2.利用先序遍历和中序遍历推导出后序遍历
3.判断回文数
回文数就指正序(从左向右)和倒序(从右向左)读都是一样的整数。例如,121 是回文,而 123 不是。
解析
var isPalindrome = function (x) {
if (x < 0) {
return false
}
//join将数组转化为字符串 split字符串转为数组
//parseInt() 函数解析字符串并返回整数。
//转为字符串 分割,反转,变为字符串
var x2 = parseInt(x.toString().split('').reverse().join(''))
return x2 === x ? true : false
}
isPalindrome(121)
console.log(isPalindrome(121))
4. 用正则表达式写颜色16进制的匹配
^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$
5. 正则的匹配方法
6. settimeout实现setinterval
解析
function setTimeToInterval(fn, delay, times) {
if (!times) {
return
}
setTimeout(() => {
fn()
setTimeToInterval(fn, delay, --times)
}, delay)
}
框架 (vue和react)
1. vue的生命周期
解析
2. vue中v-if和v-show的区别
解析
v-if 是**真正**的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建;也是**惰性的**:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 的 “display” 属性进行切换。
所以,v-if 适用于在运行时很少改变条件,不需要频繁切换条件的场景;v-show 则适用于需要非常频繁切换条件的场景。
3. vue中的diff算法
解析
我们先根据真实DOM生成一颗virtual DOM,当virtual DOM某个节点的数据改变后会生成一个新的Vnode,然后Vnode和oldVnode作对比,发现有不一样的地方就直接修改在真实的DOM上,然后使oldVnode的值为Vnode。diff的过程就是调用名为patch的函数,比较新旧节点,一边比较一边给真实的DOM打补丁。
在采取diff算法比较新旧节点的时候,比较只会在同层级进行, 不会跨层级比较。
Diff算法是一种对比算法。对比两者是旧虚拟DOM和新虚拟DOM,对比出是哪个虚拟节点更改了,找出这个虚拟节点,并只更新这个虚拟节点所对应的真实节点,而不用更新其他数据没发生改变的节点,实现精准地更新真实DOM,进而提高效率。
新旧虚拟DOM对比的时候,Diff算法比较只会在同层级进行, 不会跨层级比较。 所以Diff算法是:深度优先算法。 时间复杂度:O(n)
当数据改变时,会触发setter,并且通过Dep.notify去通知所有订阅者Watcher,订阅者们就会调用patch方法,给真实DOM打补丁,更新相应的视图
4. vue中响应原理
解析
vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属 性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。4 个步骤:
实现一个监听器 Observer:对数据对象进行遍历,包括子属性对象的属性,利用 Object.defineProperty() 对属性都加上 setter 和 getter。这样的话,给这个对象的某个值赋值,就会触发 setter,那么就能监听到了数据变化。
实现一个解析器 Compile:解析 Vue 模板指令,将模板中的变量都替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,调用更新函数进行数据更新。
实现一个订阅者 Watcher:Watcher 订阅者是 Observer 和 Compile 之间通信的桥梁 ,主要的任务是订阅 Observer 中的属性值变化的消息,当收到属性值变化的消息时,触发解析器 Compile 中对应的更新函数。
实现一个订阅器 Dep:订阅器采用 发布-订阅 设计模式,用来收集订阅者 Watcher,对监听器 Observer 和 订阅者 Watcher 进行统一管理。
5. MVVM设计模式
参考文章: 设计模式
解析
如上图所示:MVVM模式是在MVP模式的基础上进⾏了改良,将Presenter改良成ViewModel(抽象视图):
• ViewModel:内部集成了Binder(Data-binding Engine,数据绑定引擎),在MVP中派发器View或Model的更新都 需要通过Presenter⼿动设置,⽽Binder则会实现View和Model的双向绑定,从⽽实现View或Model的⾃动更新。
• View:可组件化,例如⽬前各种流⾏的UI组件框架,View的变化会通过Binder⾃动更新相应的Model。
• Model:Model的变化会被Binder监听(仍然是通过观察者模式),⼀旦监听到变化,Binder就会⾃动实现视图的更新。
好处:
• 提升了可维护性,解决了MVP⼤量的⼿动同步的问题,提供双向绑定机制。
• 简化了测试,同步逻辑是交由Binder处理,View跟着Model同时变更,所以只需要保证Model的正确性,View就正确。
额外的问题
• 产⽣性能问题,对于简单的应⽤会造成额外的性能消耗。
• 对于复杂的应⽤,视图状态较多,视图状态的维护成本增加,ViewModel构建和维护成本⾼。
对前端开发⽽⾔MVVM是⾮常好的⼀种设计模式。在浏览器中,路由层可以将控制权交由适当的ViewModel,后者⼜可以更新并响应持续的View,并且通过⼀些⼩修改MVVM模式可以很好的运⾏在服务器端,其中的原因就在于Model与 View已经完全没有了依赖关系(通过View与Model的去耦合,可以允许短暂View与持续View的并存),这允许View经 由给定的ViewModel进⾏渲染。
⽬前流⾏的框架Vue、React以及Angular都是MVVM设计模式的⼀种实现,并且都可以实现服务端渲染。需要注意⽬前 的Web前端开发和传统Model2需要模板引擎渲染的⽅式不同,通过Node启动服务进⾏⻚⾯渲染,并且通过代理的⽅式 转发请求后端数据,完全可以从后端的苦海中脱离,这样⼀来也可以⼤⼤的解放Web前端的⽣产⼒。
6. 观察者模式和发布订阅模式
参考文章:观察者模式 vs 发布订阅模式,千万不要再混淆了 - 掘金
解析
观察者模式
观察者模式是使⽤⼀个subject⽬标对象维持⼀系列依赖于它的observer观察者对象,将有关状态的任何变更 ⾃动通知给这⼀系列观察者对象。当subject⽬标对象需要告诉观察者发⽣了什么事情时,它会向观察者对象 们⼴播⼀个通知。
- 目标对象 Subject:
- 维护观察者列表 observerList ———— 维护拥有订阅权限的弟子列表
- 定义添加观察者的方法 ———— 提供弟子购买订阅权限的功能
- 当自身发生变化后,通过调用自己的 notify 方法依次通知每个观察者执行 update 方法 ———— 发布对应任务后通知有订阅权限的弟子
- 观察者 Observer 需要实现 update 方法,供目标对象调用。update方法中可以执行自定义的业务逻辑 ———— 弟子们需要定义接收任务通知后的方法,例如去抢任务或任务不适合,继续等待下一个任务
发布/订阅模式
发布者 Publisher ,事件调度中心 Event Channel ,订阅者 Subscriber 。
发布/订阅模式使⽤⼀个事件通道,这个通道介于订阅者和发布者之间,该设计模式允许代码定义应⽤程序的特定事件,这些事件可以传递⾃定义参数,⾃定义参数包含订阅者需要的信息,采⽤事件通道可以避免发布者和订阅者之间产⽣依赖关系。
两者的区别
- 观察者模式:允许观察者实例对象(订阅者)执⾏适当的事 件处理程序来注册和接收⽬标实例对象(发布者)发出的通 知(即在观察者实例对象上注册update⽅法),使订阅者和发布者之间产⽣了依赖关系,且没有事件通道。不存在封装约束的单⼀对象,⽬标对象和观察者对象必须合作才能维持约束。 观察者对象向订阅它们的对象发布其感兴趣的事件。通信只能是单向的。
- 发布/订阅模式:单⼀⽬标通常有很多观察者,有时⼀个⽬标的观察者是另⼀个观察者的⽬标。通信可以实现双向。该模式存在不稳定性,发布者⽆法感知订阅者的状态。
7. VUE传参
解析
Vue 组件间通信是面试常考的知识点之一,这题有点类似于开放题,你回答出越多方法当然越加分,表明你对 Vue 掌握的越熟练。Vue 组件间通信只要指以下 3 类通信:父子组件通信、隔代组件通信、兄弟组件通信,下面我们分别介绍每种通信方式且会说明此种方法可适用于哪类组件间通信。(1)props / $emit 适用 父子组件通信
这种方法是 Vue 组件的基础,相信大部分同学耳闻能详,所以此处就不举例展开介绍。
(2)ref 与 $parent / $children 适用 父子组件通信
ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例$parent/$children:访问父 / 子实例
(3)EventBus ($emit / $on) 适用于 父子、隔代、兄弟组件通信
这种方法通过一个空的 Vue 实例作为中央事件总线(事件中心),用它来触发事件和监听事件,从而实现任何组件间的通信,包括父子、隔代、兄弟组件。
(4)$attrs/$listeners 适用于 隔代组件通信
$attrs:包含了父作用域中不被 prop 所识别 (且获取) 的特性绑定 ( class 和 style 除外 )。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 ( class 和 style 除外 ),并且可以通过v-bind="$attrs"传入内部组件。通常配合 inheritAttrs 选项一起使用。$listeners:包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过v-on="$listeners"传入内部组件
(5)provide / inject 适用于 隔代组件通信
祖先组件中通过 provider 来提供变量,然后在子孙组件中通过 inject 来注入变量。 provide / inject API 主要解决了跨级组件间的通信问题,不过它的使用场景,主要是子组件获取上级组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系。
(6)Vuex 适用于 父子、隔代、兄弟组件通信
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。每一个 Vuex 应用的核心就是 store(仓库)。“store” 基本上就是一个容器,它包含着你的应用中大部分的状态 ( state )。
- Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
- 改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化。
8. vue的route路由
【Q455】React/Vue 中的 router 实现原理如何 | react,vue,dom高频面试题 | 大厂面试题每日一题
解析
本质都是通过监听url的变化。有hash和history两种模式。hash通过监测#号后的哈希值,通过**hashChange**事件监听,跳转。history通过pushState和replaceState(修改当前历史记录实体)改变urlhash只能用字符串类型
hash只能改变#后值
hash#后的不会显示,hash值不显示
hash兼容性好
history可以通过PAI用多种类型
history可以随意更改同源的url
history每条记录都会计入历史记录
history需要服务器配置
hash
只在前端操作,不会影响到url
- 通过 location.hash 跳转路由
- 通过 hashchange event 监听路由变化通过
history API
history需要服务器配置,刷新会发送http请求,容易发送404
node可以配置插件:connect-history-api-fallback解决404问题
- 通过 history.pushState() 跳转路由(向当前浏览器会话的历史堆栈中添加一个状态(state))
- 通过 popstate event 监听路由变化,但无法监听到 history.pushState() 时的路由变化
9. vuex的理解
解析
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。每一个 Vuex 应用的核心就是 store(仓库)。“store” 基本上就是一个容器,它包含着你的应用中大部分的状态 ( state )。(1)Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
(2)改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化。
主要包括以下几个模块:
- State:定义了应用状态的数据结构,可以在这里设置默认的初始状态。
- Getter:允许组件从 Store 中获取数据,mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性。
- Mutation:是唯一更改 store 中状态的方法,且必须是同步函数。
- Action:用于提交 mutation,而不是直接变更状态,可以包含任意异步操作。
- Module:允许将单一的 Store 拆分为多个 store 且同时保存在单一的状态树中。
10. react的生命周期
react官网有比较准确的
11. vue父组件套两层子组件,更新父组件,分别触发子组件什么生命周期钩子
解析
渲染:父beforeCreate--父created--父mounted--子beforeCreate--子created--子beforeCMount-子mounted--父mounted
子组件更新过程:
父beforeUpdate--子beforeUpdate--子updated--父updated
销毁过程
父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed
12. react中useEffect的return发送在什么时候
解析
在下一次依赖值改变触发副作用之前网络、Git和其他
1.tcp三次握手和四次挥手
解析
1 第⼀次握⼿:建⽴连接时,客户端发送syn包(syn=j)到服务器,并进⼊SYN_SENT状态,等待服 务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。
2 第⼆次握⼿:服务器(TCP连接成功)状态,完成三次握⼿
- 客户端进程发出连接释放报⽂,并且停⽌发送数据。释放数据报⽂⾸部,FIN=1,其序列号为seq=u(等于前⾯已经传送过来的数据的最后⼀个字节的序号加1),此时,客户端进⼊FIN-WAIT-1(终⽌等待1)状态。 TCP规定, FIN报⽂段即使不携带数据,也要消耗⼀个序号。
- 服务器收到连接释放报⽂,发出确认报⽂,ACK=1,ack=u+1,并且带上⾃⼰的序列号seq=v,此时,服务端就进 ⼊了CLOSE-WAIT(关闭等待) 状态。TCP服务器通知⾼层的应⽤进程,客户端向服务器的⽅向就释放了,这时 候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要 持续⼀段时间,也就是整个CLOSE-WAIT状态持续的时间。
- 客户端收到服务器的确认请求后,此时,客户端就进⼊FIN-WAIT-2(终⽌等待2)状态,等待服务器发送连接释 放报⽂(在这之前还需要接受服务器发送的最后的数据)。
- 服务器将最后的数据发送完毕后,就向客户端发送连接释放报⽂,FIN=1,ack=u+1,由于在半关闭状态,服务器 很可能⼜发送了⼀些数据,假定此时的序列号为seq=w,此时,服务器就进⼊了LAST-ACK(最后确认)状态,等待客户端的确认。
- 客户端收到服务器的连接释放报⽂后,必须发出确认,ACK=1,ack=w+1,⽽⾃⼰的序列号是seq=u+1,此时,客 户端就进⼊了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗∗MSL(最⻓报⽂段寿 命)的时间后,当客户端撤销相应的TCB后,才进⼊CLOSED状态。
- 服务器只要收到了客户端发出的确认,⽴即进⼊CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可 以看到,服务器结束TCP连接的时间要⽐客户端早⼀些。
2. XSS攻击
解析
跨站脚本攻击XSS(Cross Site Scripting),恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页面时,嵌入Web里面的Script代码会被执行,从而达到恶意攻击用户的目的。XSS攻击针对的是用户层面的攻击!XSS分为:存储型(持久) 、反射型(不持久) 、DOM型XSS
3. CSRF攻击
解析
攻击者通过伪造用户的浏览器的请求,向访问一个用户自己曾经认证访问过的网站发送出去,使目标网站接收并误以为是用户的真实操作而去执行命令4. http状态码
解析
> 1.1 状态码分类-
1xx - 服务器收到请求
-
2xx - 请求成功,如 200
-
3xx - 重定向
-
4xx - 客户端错误,如 404。
-
5xx - 服务端错误,如 500。
1.2 常⻅状态码
-
200 - 成功。
-
301 - 永久重定向(配合 location,浏览器⾃动处理)
-
302 - 临时重定向(配合 location,浏览器⾃动处理)
-
304 - 资源未被修改
-
403 - 没权限
-
404 - 资源未找到
-
500 - 服务器错误
-
502 - 网关无响应
-
504 - ⽹关超时
1.3 关于协议和规范
- 状态码都是约定出来的。
- 要求⼤家都跟着执⾏。
- 不要违反规范,例如 IE 浏览器
5. git想切换分支但不想commit用哪个命令
解析
好像是 git rebase git rebase和git merge都是合并分支, rebase 不会产生额外的 commit, 而 merge 会把这两个分支的遗漏 commit 记录重新创建一个commit保存起来。比较臃肿,所以尽量不 要用 merge6. 加密算法
解析
md5已经被破解RSA非对称加密算法
getRSApass (password) {
let jse = new JSEncrypt()
//公钥
var publicString = '-----BEGIN PUBLIC KEY-----\n' +
'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcRie+DklCiZyRTCniB/o6kPRk\n' +
'rRO57+cejRRrOOmoPDOrbQlOumGsNsThsShor3sgareTUiLLIdNeoV0hrTHqsFy7\n' +
'zBFL7QDnvEaI5eYwttesOp4D7y5EM0BU2lKg7L+9FbrNgILGs6PwR97quLozmvoP\n' +
'RSbr/J/E/+PNki5HMwIDAQAB\n' +
'-----END PUBLIC KEY-----'
jse.setPublicKey(publicString)
// 加密内容
let encrypted = jse.encrypt(password)
return encrypted
}