一、传统布局和flex布局的区别
传统布局:主要是基于行和列的二维布局,主要包含普通布局,也就是不布局,默认以文档流的形式至上而下排版;基于float的多列布局,基于table的表格不拒,基于position的定位布局
flex布局: 是将disply设置为flex, 将元素设置为一个容器,容器里面定义了主轴和侧轴,通过设置相应的属性可以让容器里面的元素基于主轴和侧轴居中,结局了传统的传统的垂直居中的问题;第二个就是flex如果设置为水平布局的话,容器里面的元素水平方向是撑满父元素的,通过设置子元素所占比例大小,决定子元素所占的空间的大小;如果是垂直布局的话,容器里面的元素垂直方向是撑满父元素的,通过设置子元素所占比例大小,决定子元素在垂直方向所占的空间的大小
二、说说vue数据双向绑定是怎么实现的,什么时候监听数据变化,什么时候触发数据变化
vue的双向绑定是基于数据劫持实现的,也就是vue初始化的时候,会将data属性通过Object.defineProperty转成get和set; 然后编译模板,会循环每一个dom节点,替换节点上面写的表达式的值,并且会new 一个Watcher,往Dep订阅队列里面添加一个wather,这个watcher就是监听变化的;触发变化有两种,一种是直接在js中更改属性,会触发属性的set方法,从而调用dep的notify方法,然后执行所有watcher的update方法,来更新值;还有一种就是页面中input表单,编译模板的时候,会判断input表单是否有v-model,有的话会监听表单的input方法,当有值变化的时候,会设置vm上面对应的属性的值,从而触发set方法,调用dep的notify方法,从而触发所有的watcher
三、比较两个颜色的相似度
这是一道开放题目,首先将颜色拆分成r/g/b三个值,如果是字符串的颜色如#aabbff或者rgb(255,128,100)可以用正则表达式取出对应的r/g/b值。对于16进制字符串,可以使用parseInt('0xaa')转10进制整数。然后对于两个颜色,可以使用距离 Math.sqrt( (r1-r2) (r1-r2) +(g1-g2)(g1-g2)+(b1-b2)*(b1-b2) )进行比较, 距离近则相似。 当然可以用Math.hypot( r1-r2, g1-t2, b1-b2) 来简化上述运算。
这道题目主要考察学员的知识积累和思考。 首先要知道rgb是颜色的组成。 然后要给出一种可行的比较方法。 最后要考察具体javascript细节函数的运用。
五、什么是函数节流和函数防抖,具体怎么实现
函数截流可以让目标函数在相等的时间窗口内只响应一次,函数防抖让目标函数在高频调用的情况下只触发一次,从而达到限流的目的。
函数防抖的实现:
export.debounce = (fn, delay = 2000) => {
let timer;
return () => {
clearInterVal(timer)
timer = setTimeout(() => {
fn(...arguments)
}, delay)
}
}
使用:
$(document).on('mouvemove', debounce(function(e) {
// 代码
}, 250))
函数节流的实现:
export.throttle = (fn, delay = 2000) {
let lock = false;
return () => {
if(lock) return;
lock = true;
fn(...arguments);
setTimeout(() => {
lock = false;
}, delay)
}
}
使用:
$(document).on('mouvemove',throttle(function(e) {
// 代码
}, 250))
六、请说说什么是XSS?如何攻击?如何防御?
xss 跨站脚本攻击(英: Cross-site-scripting, 通常简称为:xss) 是一种网站应用程序的安全漏洞攻击,是代码注入的一种,它允许恶意使用者将代码注入到网页中
xss 分为三种: 反射型, 存储型和dom-based
如何攻击:xss通过修改html节点或者执行js代码来攻击网站,
例如通过url获取默写参数
http://www.domain.com?name=<script>alert(11)</script>
<div>{{name}}</div>
上述url输入可能会将html改为<div><script>alert(1)</script></div>,这样页面中就凭空多了一段执行性脚本,这种攻击类型是反射性攻击,也可以说是DOM-based攻击。也有另一种场景,比如写了一遍包含攻击代码<script>alert(1)</script>的文章,那么可能浏览文章的用户都会被攻击到。这种攻击类型是存储型攻击,这种攻击打击面更广
如何防御:
最普遍的做法是转义输入输出的内容,对于引号,尖括号,斜杠进行转义
通过转义可以将攻击代码<script>alert(1)</script>变成-> //<script>alert(1)<&##x2f;script> escape('<script>alert(1)</script>')
function escape(str) {
str = str.replace(/&/g, "&");
str = str.replace(/</g, "<");
str = str.replace(/>/g, ">");
str = str.replace(/"/g, "&quto;");
str = str.replace(/'/, "&##39;");
str = str.replace(/`/g, "&##96;");
str = str.replace(///g, "&##x2f;");
return str;
}
当然对于显示富文本来说,不能通过上面的方法来转义所有字符串,因为这样会把需要的格式也过滤掉,这种情况通常采用白名单过滤的办法, 当然也可以通过黑名单过滤,但是考虑到需要需要过滤的标签和标签属性实在太多,更加推荐使用白名单的方式过滤
内容安全策略(csp)是一个额外的安全层,用于检测并削弱某些听定类型的攻击, 用于检测并削弱某些特定的类型的攻击,保罗跨站脚本和数据注入攻击等,无论是数据盗取,网站内容污染还是散发恶意软件,这些攻击都是主要的手段。我们可以通过csp来尽量减少xss攻击,csp本质上也是简历白名单,规定了浏览器只能够执行特定的来源代码。通常可以通过HTTP Header中的Content-Security-Policy来开启CSP只允许加载本站资源
七、CSRF攻击是什么?如何防范?
CSRF的概念:
跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。[1] 跟跨網站指令碼(XSS)相比,XSS 利用的是用户对指定网站的信任,CSRF 利用的是网站对用户网页浏览器的信任。
简单点说,CSRF 就是利用用户的登录态发起恶意请求。
如何攻击:
假设网站中有一个通过 Get 请求提交用户评论的接口,那么攻击者就可以在钓鱼网站中加入一个图片,图片的地址就是评论接口;
如果接口是 Post 提交的,就相对麻烦点,需要用表单来提交接口
如何防御:
防范 CSRF 可以遵循以下几种规则:
Get 请求不对数据进行修改
不让第三方网站访问到用户 Cookie
阻止第三方网站请求接口
请求时附带验证信息,比如验证码或者 token
#SameSite
可以对 Cookie 设置 SameSite 属性。该属性设置 Cookie 不随着跨域请求发送,该属性可以很大程度减少 CSRF 的攻击,但是该属性目前并不是所有浏览器都兼容。
#验证 Referer
对于需要防范 CSRF 的请求,我们可以通过验证 Referer 来判断该请求是否为第三方网站发起的。
#Token
服务器下发一个随机 Token(算法不能复杂),每次发起请求时将 Token 携带上,服务器验证 Token 是否有效。
八、如果发现在某个用户的电脑上,网站的静态资源打不开了,如何确定是CDN的问题还是那个用户机器、浏览器的问题
可以在自己的电脑上面dig一下
dig app.credan.com +noall +answer
这样就可以看到了app.credan.com 的所有的DNS解析出来的ip地址
dig = dns loopup utilyty DNS查询工具
dig 可以看到所有的的ip地址
可以使用curl指定ip地址请求,将上面dig的ip地址都请求一遍
curl https://app.credan.com/assets/zfdback/3.3.16zfeedback.js --resolve 'app.credan.com:443:122.227.164.207'
上面是指定用59.108.138.253请求CDN
如果其中有不通的,那么说明CND有问题,如果都通,就可以初步排查CDN问题
ping是没有用的,ping只是验证从自己的机器到CDN能不能连上,但是只是连了一个CDN的而且很多CDN是禁止ping的
同理,curl也是无用的,因为也只验证自己的机器是否能连上
如果可以在用户的电脑上dig最好
其实最常见的情况是自己的bug, 10个cdn只有9个把静态资源推上去,另外一个404
九、请说说浏览器事件机制中事件触发三个阶段?
我:
事件触发三阶段
事件触发有三个阶段
document 往事件触发处传播,遇到注册的捕获事件会触发
传播到事件触发处时触发注册的事件
从事件触发处往 document 传播,遇到注册的冒泡事件会触发
事件触发一般来说会按照上面的顺序进行,但是也有特例,如果给一个目标节点同时注册冒泡和捕获事件,事件触发会按照注册的顺序执行。
// 以下会先打印冒泡然后是捕获
node.addEventListener('click',(event) =>{
console.log('冒泡')
},false);
node.addEventListener('click',(event) =>{
console.log('捕获 ')
},true)
我:
注册事件
通常我们使用 addEventListener 注册事件,该函数的第三个参数可以是布尔值,也可以是对象。对于布尔值 useCapture 参数来说,该参数默认值为 false 。useCapture 决定了注册的事件是捕获事件还是冒泡事件。对于对象参数来说,可以使用以下几个属性
capture,布尔值,和 useCapture 作用一样
once,布尔值,值为 true 表示该回调只会调用一次,调用后会移除监听
passive,布尔值,表示永远不会调用 preventDefault
一般来说,我们只希望事件只触发在目标上,这时候可以使用 stopPropagation 来阻止事件的进一步传播。通常我们认为 stopPropagation 是用来阻止事件冒泡的,其实该函数也可以阻止捕获事件。stopImmediatePropagation 同样也能实现阻止事件,但是还能阻止该事件目标执行别的注册事件。
node.addEventListener('click',(event) =>{
event.stopImmediatePropagation()
console.log('冒泡')
},false);
// 点击 node 只会执行上面的函数,该函数不会执行
node.addEventListener('click',(event) => {
console.log('捕获 ')
},true)
我:
事件代理
如果一个节点中的子节点是动态生成的,那么子节点需要注册事件的话应该注册在父节点上
<ul id="ul">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
<script>
let ul = document.querySelector('##ul')
ul.addEventListener('click', (event) => {
console.log(event.target);
})
</script>z
我:
事件代理的方式相对于直接给目标注册事件来说,有以下优点
节省内存
不需要给子节点注销事件
十、1. 什么是重绘(Repaint)和回流(Reflow)?2. 哪些动作可能会导致重绘(Repaint)和回流(Reflow)的发生?3. 重绘(Repaint)和回流(Reflow)和Event loop的关系?4. 如何减少重绘(Repaint)和回流(Reflow)?
重绘和回流是渲染步骤中的一小节,但是这两个步骤对于性能影响很大。
1. 重绘是当节点需要更改外观而不会影响布局的,比如改变 color 就叫称为重绘
2. 回流是布局或者几何属性需要改变就称为回流。
回流必定会发生重绘,重绘不一定会引发回流。回流所需的成本比重绘高的多,改变深层次的节点很可能导致父节点的一系列回流。
所以以下几个动作可能会导致性能问题:
- 改变 window 大小
- 改变字体
- 添加或删除样式
- 文字改变
- 定位或者浮动
- 盒模型
很多人不知道的是,重绘和回流其实和 Event loop 有关。
- 当 Event loop 执行完 Microtasks 后,会判断 document 是否需要更新。因为浏览器是 60Hz 的刷新率,每 16ms 才会更新一次。
- 然后判断是否有 resize 或者 scroll ,有的话会去触发事件,所以 resize 和 scroll 事件也是至少 16ms 才会触发一次,并且自带节流功能。
- 判断是否触发了 media query
- 更新动画并且发送事件
- 判断是否有全屏操作事件
- 执行 requestAnimationFrame 回调
- 执行 IntersectionObserver 回调,该方法用于判断元素是否可见,可以用于懒加载上,但是兼容性不好
- 更新界面
- 以上就是一帧中可能会做的事情。如果在一帧中有空闲时间,就会去执行 requestIdleCallback 回调。
少重绘和回流
使用 translate 替代 top
<div class="test"></div>
<style>
.test {
position: absolute;
top: 10px;
width: 100px;
height: 100px;
background: red;
}
</style>
<script>
setTimeout(() => {
// 引起回流
document.querySelector('.test').style.top = '100px'
}, 1000)
</script>
- 使用 visibility 替换 display: none ,因为前者只会引起重绘,后者会引发回流(改变了布局)
- 把 DOM 离线后修改,比如:先把 DOM 给 display:none (有一次 Reflow),然后你修改100次,然后再把它显示出来
- 不要把 DOM 结点的属性值放在一个循环里当成循环里的变量
for(let i = 0; i < 1000; i++) {
// 获取 offsetTop 会导致回流,因为需要去获取正确的值
console.log(document.querySelector('.test').style.offsetTop)
}
- 不要使用 table 布局,可能很小的一个小改动会造成整个 table 的重新布局
- 动画实现的速度的选择,动画速度越快,回流次数越多,也可以选择使用 requestAnimationFrame
- CSS 选择符从右往左匹配查找,避免 DOM 深度过深
- 将频繁运行的动画变为图层,图层能够阻止该节点回流影响别的元素。比如对于 video 标签,浏览器会自动将该节点变为图层。
十一、在hybrid端实现类似原生般流畅的体验,要注意哪些事项
1. hybrid的性能的提升和优化第一站是考验资源加载:
比如说再打开hybrid页面之前可以让客户端在内存中打开,就可以无缝切换;
即在打开app,但是还没有打开h5页面的时候先把网页渲染好,和客户端协商实现离线静态资源加载,本来要访问的文件需要从网络上下载,可以使用相关技术直接打进app,不再走网络
2)动效优化
整体布局遵循范式,不要大范围更新,否则出现闪烁,使用transform能够显卡加速去实现动效更好,使用webkey-transform告诉显卡,某些区域的某些属性时需要使用显卡加速的
3)手势
原生手势和自己实现的手势会有冲突
在ios端滚动没有那么流畅,需要使用冲量滚动,使用webkit-overflow-scrolling使之更加流畅
4)禁用全局复制粘贴(css:user-selection)
除非在input,textarea中
5)禁止tab-highlight
点击高亮属性,在视觉上给人一种非原生的效果
6) 利用原生的功能帮忙事项
比如要实现复制的组件,如time-picker, 前端唤起组件,选择对应的日期后回传给前端
7)准守app UI 准则和规范
material-design
苹果之钱出过一个UI 准则
遵循原生的交互规范
十二、https抓包的原理是什么?平时你用什么工具?如何抓包
https执行过程
1、服务端收到客户端请求后将公钥传回客户端
2、然后客户端验证公钥是否可信(预装来自公正机构的根证书来验证)
3、如果公钥可信,客户端会生成一个密码,用服务端公钥加密后返回服务端
4、服务端接收到由自己公钥加密的密码后,进行解密,然后两端用对称加密的方式传输
5、之后每次客户端发送请求都会生成新的对称加密的密码
抓包原理
1、基于以上抓包工具只有一种方式帮助抓包
2、抓包工具让客户端安装自己的证书,也就是它们伪装成一个https的服务端,当客户端项目标网站发送请求时,https请求先访问到了抓包工具,
3、之后抓包工具使用自己的公钥和私钥与目标网站再建立一个https的通信,于是抓包工具就变成了消息的中转站实现抓包
十三、电商网站A和电影票网站B合作,A的用户,可以通过A网站下单购买电影票,之后跳转跳转到B(不需要登录)去选座位。 如果A、B是同域名,比如a.domain.com,b.domain.com能不能共享cookie?如果不同域如何处理?
方案一 :如果是相同一级域名的话,可以将cookie设置在一级域名下面,那么所有一级域名下的子域名都可以共享cookie 缺点: 1. 首先是有了一级域名的限制,2.所有服务端生成和解析cookie的规则要保持一致
方案二: 如果一级域不同的话,需要一个user系统,只有在该系统可以进行user信息输入和校验,比如密码和用户名; 其他系统需要重定向到该user系统,user授权完毕之后,user系统生成令牌,携带该令牌并且返回其他系统,其他系统拿着该令牌到服务器端去用户系统同校验,拿到用户的相关信息,
缺点: 多个系统都需要共享一个用户登录页面,但是像天猫和淘宝这样的就不会共享登录页面,因为他们有各自的品牌,那么这个问题又变成了前端不通过跳转去拿到另一个系统的登录状态,这就变成了跨域请求的问题,跨域请求推荐使用jsonp,1是没有兼容性问题,2服务端可以直接跨域写入将用户信息写入cookie