实习
17期-MHJ
工作地点:
工作性质:
部门:待定
一面:2020.10
一面
跨域,解决方案
CORS
为什么JSONP可以实现跨域
XSS攻击和CSRF攻击
为什么要去匹配&符号
如果攻击者输入了script标签的话,怎么做
原型,prototype,constructor,proto
构造函数
箭头函数
没有自己的arguments那怎么拿到arguments
盒模型
H5新增
flex有哪些属性
css选择器优先级
get和post区别
尤其在数据包发送的区别
let,const,var
防抖和节流
数组常见API
cookie,sessionStorage,localStorage
缓存(强缓存和协商缓存)
协商缓存的响应首部字段是什么
时间复杂度
17期
工作地点:
工作性质:
部门:待定
遇到不会的,先跟面试官说思考一下,再委婉的说没了解到
一面
css画一个三角形
border(具体自己实现一下哈)
css画等边三角形
同样用border,画个菱形,截一半
cookie和localStorage的区别
cookie,sessionStorage,localStorage的区别:都是保存在浏览器端,都是同源的sessionStorage随当前窗口而关闭,localStorage和cookie 在所有同源窗口中都是共享的;cookie,cookie用来存储sessionid作为唯一标识用户最合适cookie数据不能超过4k,因为每次http请求都会携带
cookie和session的区别 cookie存放在浏览器,session存放在session;session比较安全;考虑安全应该应该用session,考虑服务器性能应该用cookie
CSRF攻击是啥,如何防范
CSRF/XSRF:跨站请求伪造;伪装成受信任用户的请求来利用受信任的网站;防御:检查Referer字段,该字段标明请求来源于哪个地址,我们可以拒绝一切非本站发出的请求,避免CSRF的跨站特性;通过token或者验证码来检测用户提交
上面的防御是否安全,如果黑客连上面的防御也能伪造呢(这个问题我同样也答不上)
cookie可以设置哪些字段
name,value
domain,访问此cookie的域名(baidu.com为顶级域名,www.baidu.com为二级域名)
path,可以访问此cookie的页面路径
expires / max-Age
size 此cookie的大小
http字段 httpOnly
secure 是否只能通过https来传递次
说一下协商缓存
协商缓存相关字段有Last-Modified (精度是秒的级别,也就是说1秒内更改资源的话,该字段不起作用,所以有了etag)/ If-Modified-Since(缓存过期并且资源已修改才会返回,200;最常见的应用场景是来更新没有特定 ETag 标签的缓存实体),Etag / If-None-Match(上一次设置Etag的值)
https为什么安全,怎么做到安全,又有什么缺点
https: 在http下加入了ssl层,建立信息安全通道,采用非对称加密;加密传输协议;端口443
https原理:
web服务器需要先建立ssl连接
服务器收到客户端的https url请求后,将包含公钥的证书返回给客户端
建立会话秘钥,通过网站的公钥来加密会话秘钥
web服务器通过私钥来解开会话秘钥,通过会话秘钥加密与客户端之间的通信
https协议缺点:
握手阶段时间比http长
缓存没有http高效,增加数据开销
ssl证书需要成本,且不能在同一个ip上绑定多个域名
http2.0特性内容安全,基于https的 二进制格式,传输信息分割为更小的消息和帧,采用二进制编码,让协议有更多的扩展性,比如用帧来传输数据和指令 多路复用,增强了长连接,request请求可以随机的混杂在一起;支持流的优先级,告诉服务端优先传输哪些资源
传输速度会不会比1.0快
会,而且快了很多
减少了网络延迟
通过二进制分帧实现低延迟和高吞吐量
前端优化
降低请求数 合并资源,减少http请求,minify和gzip压缩,webp,lazyload
提高请求速度 预解析dns,减少域名数,并行加载,cdn分发
渲染 JS/CSS优化,加载顺序,服务端渲染
缓存 http缓存请求,离线缓存manifast,离线数据缓存localStorage
vue的响应式原理,对数组和对象怎么实现
非数组
请说一下响应式数据的理解
对象内部通过defineReactive方法,使用Object.defineProperty将属性进行劫持,并且只会劫持已经存在的属性,对于数组则是通过重写数组方法来实现数组的响应式
并且只能是数组常用的方法(push,pop,shift,unshift,sort,splice,reverse),对于直接通过下标或者数组长度修改数组并不会产生响应式,或者用$set(数组,下标,更新后的值),$set(对象,属性名,更新后的值)来增加对象属性,直接添加的话不会被defineProperty劫持到(因为初始化data的时候就对数据进行响应式劫持,后续增加的属性不会被劫持到)
对象有多层次时使用递归对每一层进行响应式劫持,而vue3中响应式实现使用的是proxy
每个属性都有自己的dep属性,用来存放它所依赖的watcher,当属性变化时,会通知到依赖的每个watcher去执行
性能方面
对象层级越深,性能会越差
不需要响应的数据可以不用放到data中
可以用Object.freeze()来冻结对象
const data = { count: 1 }; // 获取属性时,暂时存放当前依赖 let acitve = null; // 每个属性都有自己的依赖集dep,当属性变化时,执行自己的dep中所有的依赖 const dep = []; // data属性的数据劫持,只会劫持已经存在的属性 function defineProperty (obj) { for (const prop in obj) { let value = obj[prop]; Object.defineProperty(obj, prop, { get() { // 获取属性时,判断当前属性有无依赖,有的话就添加到依赖集dep中 if (active) { dep.push(acitve); } return value; }, set(newValue) { value = newValue; // 当属性变化时,执行当前属性的所有依赖 dep.forEach(watcher => watcher()); } }); } } defineProperty(data); // 监听属性变化的依赖 const wathcer = (fn) => { // 将依赖函数保存到active中,为了获取数据时能存到dep中 active = fn; fn(); // active设为null,可能有的属性不需要依赖 active = null; }; // count属性变化时,重新设置app.innerHtml的值 watcher(() => { // 这个就是count的依赖,当后续更改count时就需要为app.innerHtml重新赋值 app.innerHTML = data.count; });
响应数组
数组响应式
重写数组7个会改变原数组的方法,只有用这7种方法才会触发数组对应的watcher进行更新
$set()核心内部用的是splice方法
为什么不用definedProperty 如果数组的项太多,很浪费性能
const data = { arr: [1, 2, 3] }; const arrayOrigin = Array.protptype; const arrayMethods = Object.create(arrayOrigin); // 不是深拷贝 function definedReactive(obj) { for (const prop in obj) { let value = obj[prop]; if (a.constructor === Array) { arrayReactive(value); } else // 非数组响应式用defineProperty } } function arrayReactive(arr) { [‘pop’, ‘push’, ‘shift’, ‘unshift’, ‘splice’, ‘sort’, ‘reverse’].forEach(method => { arrayMehods[method] = function (…args) { // 函数劫持后(即执行原生的数组方法) arrayOrigin[method].apply(this, args); // 再执行自己的函数 render(); } }); arr.proto = arrayMethods; } function render () { app.innerHTML = data.arr; } render(); data.arr.push(4);
Vue.$set()
对于数组,是用重写的splice来实现
对于对象,就是对新增的属性或者修改的属性,重新进行一次defineReactive()
模板渲染(能答出大概流程和with语法就好了,还要了解虚拟dom)(有余力的可以把diff算法也说一下)
通过vue-template-compiler包,先将代码解析成AST语法树
优化代码,对静态节点进行标记
生成代码字符串,通过with + new Functoin 实现生成render方法,render执行后生成的是虚拟dom
1.通过vue-template-compiler包,将代码生成ast语法树,对代码进行优化,标记静态节点(如
2.将ast语法树生成代码字符串,通过with + new Function()实现生成render函数,render执行后生成一个虚拟dom(本质就是一个js对象)
- with(vm) {}这样在内部就可以直接使用_c,_v,_s,和data中的属性 with(this){return _c(‘div’,[_v(“zf”)])} this就是vm
从虚拟dom到页面的真实渲染,通过_updateComponent包的vm._update函数传入vnode,利用patch方法生成真实dom节点并渲染到页面
初次渲染时生成的真实dom结构渲染到容器中,re-render时,利用diff算法比对新旧节点的差异,生成需要更新的真实dom,渲染到容器对应的位置
附加分
vue的diff算法是平级(父级比完比儿子,儿子比完比孙子)比较,不考虑跨级比较(即不考虑父亲和儿子的比对);内部采用深度递归的方式+双指针的方式进行比较
先比较是否是相同节点(主要比较key和标签名)
相同节点则比较属性,并复用老节点
比较儿子节点,考虑老节点和新儿子节点的情况
优化比较:先比较头头,尾尾,头尾,尾头
比对查找进行复用
核心:使用key,key相同直接复用;找不到key则创建元素,多的就删除(vue2,vue3,react都是这样)
12.讲一下虚拟dom
虚拟dom就是用js对象来描述真实dom,是真实dom的抽象,因为直接操作dom的话会带来性能消耗,所以通过diff算法来对比差异进行更新dom,可以减少对真实dom的操作;并且虚拟dom不依赖真实平台环境,可以实现跨平台使用。
虚拟dom的实现就是普通对象包含tag,data,children等属性对真实节点的描述本质就是在js和dom之间的一个缓存
跨域(还有关于跨域的其他问题,忘记了。。。)
跨域请求资源
文件,css文件,jpg,png等,都允许被跨域,src属性的资源也允许被跨域,href的大部分资源都允许被跨域算跨域请求的资源:后端接口的数据、其他域的cookie、其他域的缓存跨域行为发生在哪里:即使跨域了,请求也可以发出,服务器也可以收到请求并且正常处理,然后返回数据,浏览器也能正常接收数据,接收到之后,根据同源策略,检查当前域和请求的域是否相同,如果不同则为跨域,返回数据就不会传递给我们的代码解决跨域:jsonp(需要后端配合)、后端设置Access-Control-Allow-Origin属性以支持跨域;后端不配合时:iframe(只能显示,不能操作)、通过反向代理,比如vue的proxy虚拟代理,在本地模拟一个代理服务器
webpack编译原理
初始化
读取配置文件,合并配置对象
编译
检查模块文件是否有记录,有则用记录的,没有则继续
读取文件内容
构建ast语法树
记录依赖,并存入dependencies依赖集中
替换依赖函数
将转换后的模块代码保存起来(每个模块代码对应一个唯一的模块id)
递归加载依赖集中的模块
输出
生成相应的资源文件
webpack性能优化
构建性能
减少模块解析,如一些没有依赖的模块,比如jquery,lodash
配置module.noParse,被匹配到的模块不会解析,如
module: {
noParse: /jquery/
}
优化loader性能,如lodash,jquery不需要转换,所以他们不需要loader
热替换,降低代码改动到页面呈现的时间
devServe: {
hot: true
}
传输性能
减少打包后的js代码传输到浏览器的时间,即压缩打包体积或者分块打包
分包
手动分包将公共模块单独打包出来
自动分包,配置合理的分包策略,webpack内部是使用SplitChunksPlugin进行分包的
单模块体积优化,代码压缩(UglifyJsPlugin),tree-shaking(消除模块中未引用的依赖和代码)
运行性能
书写高性能代码(一般在项目完成后进行此优化)
webpack热更新原理,底层实现(主要是我简历写了熟悉webpack,问的有点深,懵逼了)
我只答了缓存
欲了解的自己百度一下hh
class和原型继承的区别
这个我考虑了一下说没有区别,就是代码简洁了
百度一下好像也是没有实质的区别,望补充
讲一下ajax
就讲自己的理解吧,自由发挥
讲一下闭包
应用
自执行函数
自己发挥hh
坏处
内存泄漏
js的垃圾回收机制
标记
清除
如何解决内存泄漏,大型项目又咋办
控制台工具有个memory还是performance来着
自己百度一下哈
事件委托
通过哪个属性来获取目标对象
委托对象的target属性
二面
如何禁用缓存
cache-control的no-store(顺便讲一下no-store和no-cache的区别)
meta标签的content属性设置为no-cache
他们两者的优先级谁更高(这个我答不出了,网上暂时还没找到)
vue2和vue3的响应式处理,有什么区别,从哪些方面进行了优化
先讲vue2响应式的缺点
vue3用proxy代理对象,具体大家百度哈
这个问题连续两个公司的二面都问到,要关注vue3的变化
如何在jquery上扩展插件
jQuery.extend, jQuery.fn.extend
内部如何实现(原理,这个我不知道了,以下是百度内容)
通过jQuery.extend扩展jQuery时,方法被添加到了jQuery构造函数中,而当我们通过jQuery.fn.extend扩展jQuery时,方法被添加到了jQuery原型中
有没有阅读过框架源码
说有,他可能就要继续问你
我说以前可能有,但是应该忘了([狗头]hhh)
问项目(占了一半二面的时间)
哪个项目最得意,为什么
项目还能做什么优化
从性能考虑,构建性能,传输性能,运行性能
自己根据自己的项目来说
做项目遇到什么难题,怎么解决
尽量说,不要说没有
项目有什么亮点
尽量说,不要说没有
从项目里抽一个技术栈来问
屏幕共享做算法题
不要慌,一般会给10几20分钟
先理解题意,不懂马上问面试官,面试官是希望你做出来的,所以不会刁难你
如果能写出来,再跟面试官交流能否继续优化一下,可以考虑时间复杂度和空间复杂度
为什么v-for要带key
讲一下key的作用,巴拉巴拉你们懂的
用数组索引作为key好不好,为什么
不好,如果数组涉及删除或者乱序,会影响渲染结果
了解diff的讲一下diff中key的好处
先对比标签和key值,如果一样直接复用老节点,提高效率
如何做通信,比如聊天室,两人互发消息,让我给个方案
思考了一下,确实不会
给个数字,判断它的二进制有没有相邻位,如5是101,没有相邻位,返回false;6是110,有相邻位,返回true
最简单做法是转二进制然后逐位判断,转二进制可用toString(2),这个api只能转数字类型的数字,不能转字符串类型的数字
更优算法—位运算
能想到位运算应该就算通过了
利用num & 1得到num的最后一位二进制为0或者1,依次判断
补充:& 1能用来判断奇偶数;| 0和& -1能用来向下取整(详细见一大点中的位运算)
模拟场景,我是黑客,面试官是用户,我如何进行XSS攻击
我答了XSS两种类型,存储型和反射型,从这两个类型去思考,一个是利用网站漏洞去注入脚本,一个是诱导用户点击到其他网站
具体可以看一大点的XSS攻击(一大点真的有用)(一大点真的有用)(一大点真的有用)
node可以做大型服务器吗,为什么
看袁老师node课第一章
用express还是koa
继续追问中间件(讲中间件的原理)
有没有自己封装过中间件,有(袁老师node课express中间件课)
用node写过哪些接口,登录验证是怎么做的
别问,问就是袁老师的node课(狗头)
