BFC BFC指的块级格式化上下文,意思就是独立的布局环境,bfc内部的元素布局与外部互不影响。解决外边距合并、高度塌陷、浮动遮盖的问题。
visibility:hidden能继承不能点击、display:none不能继承不能点击,opacity:0不能继承能点击;
居中为何使用transform 因为transform是合成属性,会创建独立的合成层,不会触发重排重绘操作。而margin会触发重排操作,性能开销更大。
sticky是相对于最近能滚动的父级元素定位,不脱离文档流。
设置自适应大小的正方形 通过width、height设置为固定的vw。或者设置百分比的width和padding-bottom。
清除浮动 bfc、伪元素
ie盒模型和标准盒模型 ie盒模型的宽高会包括边框和内边距。
DOCTYPE是HTML5的文档声明,告诉浏览器使用哪个HTML版本标准解析文档。
语义化标签的作用
- 在没有css样式时也能呈现清晰的结构
- 有利于SEO
- 方便团队开发和维护,具有可读性
- src和href的区别
- src会暂停其它资源的下载,直到将该资源加载、编译、执行。
- href表示超链接,浏览器会并行下载,不会停止当前文档的处理。
- 严格模式是以浏览器支持的最高标准执行,混杂模式表示页面以宽松向下兼容的方式显示。
- a元素还可以用来锚点和下载资源。
- 箭头函数没有this、arguments、super,this是从上层作用域链继承。
- 继承
- 原型链继承:无法向父级构造函数传递参数,共享父级的引用类型,函数是复用的,
- 借用构造函数继承:能向父级构造函数传递参数,不共享父级的引用类型,函数无法复用。
- 组合继承:结合原型链、借用构造函数,可以传参数、父级引用类型不共享、函数复用,缺点是调用两次父类构造函数。第一次是生成子类实例时,第二次是原型链继承时。
- 原型式继承:创建一个空函数,直接将原型指向需要继承的实例。缺点是引用类型共享,函数无法复用。
- 寄生式继承:将原型式继承封装一下,内部增强对象,函数可以复用了。
- 寄生式组合继承:直接基于父类的原型生成一个实例对象,
function Father
1
- new的实现
function newFn (fn, ...args) {
const obj = {}
Object.setPrototype(obj, Fn.prototype)
const result = fn.apply(obj, args)
return result instanceof Object ? result : obj
}
1
2
3
4
5
6
2
3
4
5
6
- call接收的多个参数,apply接收的数组,bind返回一个函数,参数跟call类似。
- 事件循环机制
- 函数柯里化,将多参数的函数简化成单参数的函数,该函数返回以剩余参数的单个参数为参数的函数。
- 减少重复传递不变的参数,达到复用的效果。
- promise.all,如果参数不是promise,则用promise.resovle转为promise。
- this的指向
- this是跟着调用对象走的
- 箭头函数不会创建自己的执行上下文,所以this继承上级的this。
- 事件监听:捕获和冒泡。从window开始到目标节点再回到window。事件委托就是利用事件冒泡。
- 闭包和应用场景
- 能访问到函数内部变量的函数。
- 写一个判断变量类型的函数
- script标签 defer和async 的区别,async是立即下载,同步执行。defer是立即下载,页面解析完成后再执行。
- DOMContentLoaded是在defer script执行完毕后执行。
- 优先下载同步script,其余顺序下载。
- 原型与原型链
- 每个函数都有一个prototype属性,叫做原型对象;每个对象都有_proto_属性,指向其构造函数的原型对象;当查询一个对象的属性时,会先查询这个对象本身有无这个属性,如果无,则会访问_proto_属性去查找原型对象有没有,原型对象也有_proto_属性,一路会Object构造函数的原型对象,如果也没有的话,则会反回undefined,因为Object构造函数的原型对象的原型对象为null。这就是原型链。
- 作用域链条
- js有全局执行上下文和函数执行上下文,当js查找一个变量时,会从当前所处的作用域往上查询。原理是当js文件执行时,会编译最外层的代码,创建一个全局作用域,推入作用域栈的栈底,然后执行代码到函数时,会编译创建一个函数作用域,推入作用域栈中,作用内部包含一个变量环境、词法环境、outer,词法环境是个栈结构,其中let、const就是通过词法环境实现的。outer指向上级作用域,outer的指向只跟函数的声明位置有关,在编译的时候就决定好了。
- instanceof原理
- 基于原型连查找的。判断构造函数的prototype是否在实例的_proto_属性上。
- js垃圾回收机制
- 标记清除:从根对象开始递归遍历对象的引用关系,给能访问到的对象打上标记。随便把未打上标记的对象清除。
- 优点:不存在循环引用;
- 缺点:会暂停程序执行,引起卡顿;内存碎片化。
- 标记整理:标记清除+整理;解决内存碎片化的问题。
- 引用计数:对象每被引用一次就加1,不再被引用时就减1,清除计数为0的。
- 优点:实时回收;
- 缺点:循环引用。
- V8垃圾回收:分为新生代和老生代,新生代采用scavenge算法将内存分为两半,每次用一半来存储数据,快满的时候采用标记清除,把存活的直接迁移至另一半,同时清空当前的。其中存活时间较长的对象晋升到老生代。老生代采用标记整理清除算法。同时还采用了增量标记、三色标记法、写屏障、惰性清理等策略优化回收策略。
- 实现apply、call、bind方法
parseInt(num, radix)
解析规则,- 截流防抖的实现。
- weakSet、weakMap
- 实现sleep
- 数据量大的情况下使用for循环,小数据则使用forEach。因为forEach要执行回调函数,需要创建额外的调用栈和函数上下文。
- 10万个元素的数组,取第一个元素和最后一个元素的时间几乎一样,因为都是直接根据索引取,js的数组是通过对象实现,查索引也就是查hash表。
- 深拷贝和浅拷贝
- setTimeout设置的时间会存在误差,因为那个时间只是表示把回调函数挂入宏任务栈的时间,要等主线程执行完同步任务才会执行宏任务。
- await和async的原理
- symbol的用途
- 防止命名冲突
- 设置私有变量
- 提供遍历接口
- promise.resolve
- intanceof实现原理
- encodeURI和encodeURIComponent的区别
- for in 和 for of 的区别
- 箭头函数内部的this是绑定运行时的父级上下文
new Number(3)
返回的是一个对象class static private
- onclick绑定的事件为冒泡型事件。
- document.onload 和 ready区别
- 三次握手和四次挥手
- https中间人攻击、劫持攻击和剥离攻击
- 验证证书合法性
- http状态吗
- 单点登录
- get与post的区别
- dns劫持、xss攻击
- csrf攻击
- 前端如何实现即时通讯。
- url解析全过程
- cookies、localStorage、sessionStorage
- 手写promise
class myPromise {
constructor (executor) {
this.status = 'pending'
this.value = undefined
this.reson = undefined
this.fulfilledFns = []
this.rejectedFns = []
let resolve = (value) => {
if (this.status === 'pending') {
this.status = 'fulfilled'
this.value = value
this.fulfilledFns.forEach(fn => fn())
}
}
let reject = (reason) => {
if (this.status === 'pending') {
this.status = 'rejected'
this.reason = reason
this.rejectedFns.forEach(fn => fn())
}
}
executor(resolve, reject)
}
then (onFulfilled, onRejected) {
const promise2 = new myPromise((res, rej) => {
if (this.status ==== 'fulfilled') {
const x = onFulfilled(this.value)
resolvePromise(promise2, x, res, rej)
}
if (this.status === 'rejected') {
const x = onRejected(this.reason)
resolvePromise(promise2, x, res, rej)
}
if (this.status === 'pending') {
this.fulfilledFns.push(() => {
const x = onFulfilled(this.value)
resolvePromise(promise2, x, res, rej)
})
this.rejectedFns.push(() => {
const x = onRejected(this.reason)
resolvePromise(promise2, x, res, rej)
})
}
})
function resolvePromise (promise, x, res, rej) {
if (x instanceof myPromise) {
if (x === promise) { rej('自己引用自己'); return }
x.then((xValue) => {
res(xValue)
}, (xReason) => {
rej(xReason)
})
} else {
res(x)
}
}
return promise2
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
- http1.0、1.1、2.0、3.0的区别
- http1.1比1.0
- 支持持久化连接,一个tcp连接可以传输多个http请求,一个域名最多支持6个tcp连接。
- 通过host字段,支持虚拟主机,1一个ip对应多个域名。
- 支持动态内容,将数据分成若干个数据包,然后后一个数据包带有一个数据包的大小。最后已一个零长度的包代表数据传输结束。
- 新增cookies,存在浏览器端的数据,每次请求都会携带。
- http2.0比http1.1
- 只保持一个TCP长连接。
- 增加二进制分帧层,实现多路复用。
- 设置请求的优先级
- 支持头部压缩。
- 服务器推送
- http3.0
- 使用udp,实现quic协议。
- 未广泛推广。
- 原型
- 作用域链条
- 模块
- CommonJS模块:
module.exports = xxx
导出,require()
导入 - ESM模块:
export xxx
导出,import xxx from xxx
、import()
导入,export xxx from xxx
中转 - ts中,
import
和export
会将当前文件标记为模块,不再能全局使用。
- 类实现接口,接口声明一个类的构造函数。
- 枚举的js代码实现
const enum xxx
可以获得性能提升- enum + namespace 可以给枚举添加静态方法
- target 和 lib的区别
- 无函数实现的情况下,函数类型声明的两种方式。
- 函数重载的意义:强制约束参数数量的关联性。比如4个可选参数,可以传1、2个,传4个,不能只传3个,可以通过函数重载实现。
- 双重断言
xxx as any as XXX
- 对象字面量作为参数时,拥有更严格的类型检查。
- 类型保护的方法:
typeof
、instanceof
、in
、XXX.xxx
、用户自定义类型保护函数。 - readonlyArray
# 自我介绍
面试官,您好,我叫刘煊港,今年26岁,2020年毕业于湖南工商大学软件工程专业,目前就职于思为科技有限公司前端工程师岗位,主要负责小程序、saas后台管理系统、app相关的需求开发和性能优化,主要用的技术栈有vue、uni-app、ts等。我个人会经常逛掘金和github来了解行业趋势和知识扩展,对自我要求也较高,注重typescript提升代码质量和可读性、熟练使用快捷键提升开发效率。并且有很好的团队合作意识,乐于推动团队建设。
# 面试题
项目中遇到的难点
- 工程化难点
- 优化uni-app开发体验
- 明确我要解决的问题,小程序端本地开发编译慢
- 最初的想法是把pages.json文件拆分到各模块,然后在打包之前,把pages.json文件组装在一起。缺点就是改造成本较大,需要拆分文件。不方便统一管理了。
- 后面逛社区的时候,发现了一个插件里介绍了uni-app提供了一个page.js的文件钩子,uni在打包时会读取该文件并执行,文件导出的是一个函数,接受参数为pages.json的json数据,返回的也是json数据,可以在函数内部对json字符串做处理。
- 于是我就写了一个脚本,在执行之前动态去生成pages.js文件,然后根据脚本的执行参数对内部的分包进行拆分,从而达到减少打包文件的效果,实现快速编译。
- 这次的优化显著提升了冷启动和热更新的速度。也在团队内部做了一次分享。
- 优化uni-app开发体验
- 技术难点
- 明确要解决的问题
- 自己想一下解决方案
- 找社区或者github找有没有更好的实现方式
- 最后结合实际情况,选择最适合的方案解决问题
- 工程化难点
http介绍
- http1.1
- 支持持久连接,默认开启,一个tcp连接上可以传输多个http请求。
- 每个域名最多维护6个tcp连接
- 增加Host字段,提供虚拟主机的支持,支持多个域名公用1个ip地址
- 支持动态内容传输,引入Chunk transfer机制,服务器将数据分割成若干个任意大小的数据块,每个数据块附上上个数据块的长度,最后使用一个零长度的块作为发送数据完成的标志。
- 客户端cookies、安全机制
- 问题
- 队头阻塞:在没有接收到上一个http响应时,不会开启下一个请求。
- tcp机制的慢启动导致带宽利用率不理想
- 同时多条tcp连接会竞争固定的带宽
- http2.0
- 一个域名只使用一个tcp长连接
- 多路复用
- 通过增加二进制分帧层实现多路复用,把请求转换成一个个带请求ID的帧。
- 服务器收到优先资源的请求,可以暂停别的请求来优先处理。
- 可以设置请求的优先级
- 服务器可以提前将数据推送到浏览器
- 头部压缩
- tcp的队头阻塞:中途一个数据包丢失导致重传等待导致
- 当达到2%的丢包率时,http/1.1比http/2的表现好。
- tcp协议的僵化
- 中间设备的僵化
- 操作系统更新滞后
- http1.1
http状态码
- 2开头表示成功
- 3开头表示重定向
- 301 永久重定向
- 302 临时重定向
- 4开头表示找不到资源
- 403被禁止
- 404找不到资源
- 5开头表示服务器有问题
XSS攻击
- 跨站脚本攻击
- 攻击者通过技术手段往网站注入恶意脚本,获取用户cookies、sessionID等敏感数据,从而危害数据安全。
- 存储型:攻击者将恶意代码存入服务器端数据库中,用户请求网页时,服务器端将恶意代码拼接进html返回给用户。
- 反射型:攻击者将恶意代码拼入URL,用户打开URL时,服务器端将URL中的恶意代码拼接进html返回给用户。
- DOM型: 攻击者将恶意代码拼入URL,用户打开URL时,前端取出URL中的恶意代码并执行。
- 防范的话html做转译。
CSRF攻击
- 利用服务器的漏洞和用户的登录状态在第三方站点实施攻击
- 引诱用户点击恶意链接,然后隐式调用漏洞接口
- 问题:怎么利用用户的登录状态
- 阻止
- 充分利用好Cookies的SameSite属性
- 通过Referer、Origin验证请求的来源站点
- CSRF Token
浏览器缓存
- cookies
- storage
vue
- vue和react的对比
- react用jsx vue用单文件组件
- 单项数据流和双向绑定的异同 *
- vue3为什么使用proxy
- vue2使用object.defineProperty有局限性
- 对象新增属性无响应式
- 数组.length无响应式
- 数组的方法无响应式
- vue2使用object.defineProperty有局限性
- vue和react的对比
技术分享做过哪些
- vscode快捷键的分享:主要分享快捷键的使用,如何使用快捷键提升效率,一些比较实用的快捷键。
- 文件跳转
- 多光标操作
- 代码搜索
- 优化uni-app开发模式下编译打包速度。
- vscode快捷键的分享:主要分享快捷键的使用,如何使用快捷键提升效率,一些比较实用的快捷键。
算法题
- 有效括号匹配
- 字符串匹配
离职原因
- 我想找一个更有挑战性、并且有更大成长空间的工作。
- 非常看好贵公司所处行业和所做的事情。