腾讯云智面经总结
BFC
- 触发BFC
- 浮动float
- 非静态定位position为absolute或fixed
- display为inline-block、table-cell、table-caption、flow-root、flex 或 inline-flex 元素的直接子元素、grid 或 inline-grid 元素的直接子元素
- overflow不为visible
- contain 值为 layout、content 或 paint 的元素
- BFC特性
- 内部box会在垂直方向,一个接一个地放置。
- Box垂直方向的距离由margin决定,在一个BFC中,两个相邻的块级盒子的垂直外边距会产生折叠。
- 在BFC中,每一个盒子的左外边缘(margin-left)会触碰到容器的左边缘(border-left)(对于从右到左的格式来说,则触碰到右边缘)
- 形成了BFC的区域不会与float box重叠
- 计算BFC高度时,浮动元素也参与计算
XSS/CSRF
XSS, 即为(Cross Site Scripting), 中文名为跨站脚本
当渲染 DOM 树的过程成发生了不在预期内执行的 JS 代码时,就发生了 XSS 攻击。 大多数 XSS 攻击的主要方式是嵌入一段远程或者第三方域上的 JS 代码
防御:
示例代码
document.write("123")
CSRF(Cross Site Request Forgery,跨站请求伪造)
- 在受害者访问一个网站时,其 Cookie 还没有过期的情 况下,攻击者伪造一个链接地址发送受害者并欺骗让其点击,从而形成 CSRF 攻击
防御思路:
XSS防御思路对输入(和 URL 参数)进行过滤,对输出进行编码
防御 CSRF 攻击主要有三种策略:
- 验证 HTTP Referer 字段;
- 在请求地址中添加 token 并 验证;
- 在 HTTP 头中自定义属性并验证
重绘重排
- 定义
- 重绘:DOM 的变化影响到了预算内宿的几何属性比如宽高,浏览器重新计算元素的几何属性, 其他元素的几何属性也会受到影响,浏览器需要重新构造渲染树,这个过程称之为重排,
- 重排:浏览器将受到影响的部分重新绘制在屏幕上 的过程称为重绘。
- 原因
- 添加或者删除可见的 DOM 元素
- 元素尺寸位置的改变 浏览器页面初始化,
- 浏览器窗口大小发生改变,重排一定导致重绘,重绘不一定导致重排,
- 优化方法
- 不在布局信息改变时做 DOM 查询
- 减少发生操作(合并多次对
DOM
和样式的修改、或者将样式事先设计好,动态去改变class
) - 脱离文档流(绝对定位、)
- 避免多层内联样式
- 平滑度换取速度、避免TABLE布局、CSS3硬件加速、调试
ES6新特性
let和const关键字、解构赋值、箭头函数、模块导入导出、Promise、symbol、Map和Set类型、class类
支持异步的循环方法
哪些循环方法能支持异步 哪种循环支持等待异步结果返回
- for...of
- promise.all + map
- 传统for循环
- reduce
- generator
事件冒泡,事件捕获 事件代理
- 事件冒泡就是:当某元素执行某一种类型事件,那么从该元素起逐级向外层的元素检测是否存在与本身同样的事件。这一个过程,就叫做事件冒泡
- 事件捕获:事件捕获刚好就和事件冒泡反过来。当元素被触发事件时候,从该元素的根节点开始逐级向里寻找同类型事件。这个过程,就被称为事件捕获
- 顺序:先进行事件捕获 => 再到目标本身 => 最后再进行事件冒泡
- 事件代理/事件委托/event delegation: 事件代理就是利用事件冒泡或事件捕获的机制把一系列的内层元素事件绑定到外层元素。(这也就意味着子元素本身将不用注册自己的事件)
- 作用:事件代理的作用就是:避免大量事件注册
- 如何阻止:event.stopPropagation( )
事件循环
在此之前,我们先了解下宏任务和微任务。
- 宏任务
- 事件触发的回调函数,例如
DOM Events
、I/O
、requestAnimationFrame
setTimeout
、setInterval
的回调函数- 一段新程序或子程序被直接执行时(比如从一个控制台,或在一个
<script>
元素中运行代码)。
- 事件触发的回调函数,例如
- 微任务
- promises:
Promise.then
、Promise.catch
、Promise.finally
- MutationObserver:提供了监视对 DOM 树所做更改的能力。
- queueMicrotask:将回调加入微任务队列。
- process.nextTick:Node独有
- 执行时机:一个需要异步执行的函数,执行时机是在主函数执行结束之后、当前宏任务结束之前
- promises:
执行机制:
- 执行一个宏任务,如果遇到微任务就将它放到微任务的事件队列中
- 当前宏任务执行完成后,会查看微任务的事件队列,然后将里面的所有微任务依次执行完
微任务的执行效率高还是宏任务的执行效率高?
虚拟DOM优缺点
优点
Virtual DOM
在牺牲(牺牲很关键)部分性能的前提下,增加了可维护性,这也是很多框架的通性。- 实现了对
DOM
的集中化操作,在数据改变时先对虚拟DOM
进行修改,再反映到真实的DOM
,用最小的代价来更新DOM
,提高效率。 - 打开了函数式
UI
编程的大门。 - 可以渲染到
DOM
以外的端,使得框架跨平台,比如ReactNative
,React VR
等。 - 可以更好的实现
SSR
,同构渲染等。 - 组件的高度抽象化。
缺点
- 首次渲染大量
DOM
时,由于多了一层虚拟DOM
的计算,会比innerHTML
插入慢。 - 虚拟
DOM
需要在内存中的维护一份DOM
的副本,多占用了部分内存。 - 如果虚拟
DOM
大量更改,这是合适的。但是单一的、频繁的更新的话,虚拟DOM
将会花费更多的时间处理计算的工作。所以如果你有一个DOM
节点相对较少页面,用虚拟DOM
,它实际上有可能会更慢,但对于大多数单页面应用,这应该都会更快。
vue2、vue3的区别
更好的ts支持
Vue2 响应式原理基础是 Object.defineProperty;Vue3 响应式原理基础是 Proxy。
- object.defineProperty来劫持数据的setter和getter方法,对象改变需要借助api去深度监听
- Proxy来实现数据劫持,删除了一些api($on,$once,$off) fiter等,优化了Block tree,solt,diff 算法)(变化的主要原因:无法监听对象或数组新增、删除的元素。)
vue3支持在template中写多个根
生命周期方面(名字变化多了一个on)
异步组件(Suspense)
- Vue3 提供 Suspense 组件,允许程序在等待异步组件加载完成前渲染兜底的内容,如 loading ,使用户的体验更平滑。使用它,需在模板中声明,并包括两个命名插槽:default 和 fallback。Suspense 确保加载完异步内容时显示默认插槽,并将 fallback 插槽用作加载状态。
Teleport(移出app之外渲染,如dialog)
diff算法优化:patchFlag 帮助 diff 时区分静态节点,以及不同类型的动态节点。一定程度地减少节点本身及其属性的比对。
打包优化:Tree-shaking:模块打包 webpack、rollup 等中的概念
template里使用data里的数据为什么不用加this
因为vue在解析template时使用了with (this),改变了template中的顶层作用域
手写call、apply、bind
call
Function.prototype.call1 = function(){
// 初始化
const [context,...args] = [...arguments]
// 在传入的对象上设置属性为待执行函数
context.fn = this
// 执行函数
const res= context.fn(args)
// 删除属性
delete context.fn
// 返回执行结果
return res
}
apply
定义: 调用一个具有给定 this 值的函数,及以一个数组的形式提供的参数。
Function.prototype.apply1 = function (context, args) {
// 给传入的对象添加属性,值为当前函数
context.fn = this;
// 判断第二个参数是否存在,不存在直接执行,否则拼接参数执行
let res = !args ? context.fn() : context.fn(...args)
// 删除新增属性
delete context.fn
return res
}
bind
定义:创建一个新的函数,在 bind 被调用时,这个新函数的 this 被指定为 bind()的第一个参数,而其余参数将作为新函数的参数,供调用时使用。
Function.prototype.bind1 = function (context) {
// 将当前函数的this存放起来
var _self = this
// 绑定bind传入的参数,从第二个开始
var args = Array.prototype.slice.call(arguments,1);
// 声明一个空的构造函数
function fNOP(){}
var fBound = function(){
// 绑定bind返回新的函数,执行所带的参数
const bindArgs = Array.prototype.slice.apply(arguments)
// 合并数组
args.push.apply(args.bindArgs)
// 普通函数 this指向window
// 作为构造函数,this指向实例
return _self.apply(this instanceof fNOP ? this : context,args)
}
if(this.prototype){
// 修改返回函数的prototype为绑定函数的prototype,实例就可以继承绑定函数的原型中的值
fNOP.prototype = this.prototype
}
fBound.prototype = new fNOP();
return fBound;
}
参考
https://juejin.cn/post/7234341843580174393