内容包括面试考点,答题技巧,以及一点工做后的经历... 读者能够根据右侧导航目录,按需阅读,但愿各位都有所获。前端
开篇不想暴击,但颇有必要。每每咱们为了面试,准备了好久,投了心仪的厂子,结果等来的不是面试通知,而是一封冰冷的邮件... 您的简历,与岗位要求不符
vue
通常这种状况能够总结为几类,评论欢迎补充:java
重要分析一下第 4 点,能够解读出不少东西:node
「Talk is cheap. Show me the code」
,建议:简历里带上你的 github、掘金等连接,若没有?还不赶忙动起来!简历上面写了什么,决定了面试官会问你什么。若是你写的很泛,除非你真的很全面无敌,不然状况会很糟。react
面试是有技巧的,简单的一问一答太过死板,试着在回答的时候引伸向你擅长的领域,抛出一个个关键词诱导考官提问。git
具体的例子,下文会涉及。但在此以前,咱们须要作足功课,务实基础。此外,请务必准备一些杀手锏,在须要的时候亮瞎考官的……,好比 HTTPS 全部加密算法
,chromium 进程 IPC 原理
,斐波拉契第 n 数的 logn 解法
,浏览器渲染过程
,Vue 编译器架构
,快排以及手写 V8 排序
。程序员
算法是大厂必考的项目,这里笔者提供 leetcode 字节跳动的企业题库,后面会慢慢补齐其余厂的。github
进入正题,前端要往深了走,基础很重要。面试
定义:有权访问另外一个函数做用域中的变量的函数。ajax
产生缘由:先解释下做用域链,而后说明当前环境存在指向父级做用域的引用。
应用:定时器 / 事件监听 / ajax / Web Worker 等都有涉及,关键就是使用了回调函数……
面试时能够展开的点,能够引出下一个话题:闭包变量存在堆中一个名为 [[scope]]
的对象内,同时闭包也常以 高阶函数
的形式建立,V8 的 垃圾回收
机制也涉及到了闭包。
讲到闭包,就会涉及到内存存储空间的知识,进而能够引伸到垃圾回收机制 GC。
咱们知道:栈中保存变量,函数调用完,栈顶空间自动销毁,而后切换执行上下文,假如存储对象很大,切换的开销天然也变得巨大。因而,堆就出场了。
强调:V8 的 GC 做用的是堆而不是栈。
复制代码
非增量
垃圾回收时需耗时 1 秒之久,这期间会致使 js 暂停、应用卡顿,形成性能降低,显然,1.4G 是通过深思熟虑的。变量晋升
,两个算法 mark-sweep 标记清除
,mark-compact 标记整理
。还有 增量标记算法
,这个算法优化将 GC 期间形成的 js 阻塞减小到本来的 1/6。微任务
阶段进行。GC 还能够展开的点:增量清理、增量整理、多核并行清理,内存泄漏,WeakMap、WeakSet 弱引用。
回答时,能够按照如下顺序来回答。
let obj = new Fn()
__proto__
属性,全名 [double underscore proto] 读做 dunder proto
便可。该属性指向构造函数的原型对象。__proto__
指向父类对象,接着不断追溯父类原型对象,直到指向 Object 对象为止,再上面只剩 null 了。明白了原型链,那么手写 instanceof 就不在话下了。列出几个经常使用的方法:
Object.getPrototypeOf(obj) // 获取原型对象,好比 instanceof 源代码
Object.setPrototypeOf(subClass, superClass) // 继承父类的静态方法
Object.prototype.hasOwnProperty(attr) // 检查对象自身是否有该属性
in // 检查对象或原型对象中是否有该属性 if (k in O) {}
Object.create(proto, [propertiesObject]) // 一个不带任何原型链属性、纯净且高度可定制的对象,好比数据字典能够用 create(null) 代替 {} 初始化
这块算是面试的重头戏了,资料太多,照搬没有意思,认清注意下面几个点。
process.nextTick
。requestAnimationFrame
,接着是 UI 渲染,Web Worker,注意这几个的顺序。process.nextTick
:是独立于 Event Loop 的任务队列,且在微任务以前执行。花点时间详细了解 Event Loop
里面的细节是颇有必要的,毕竟主流前端框架中的批量更新,fiber 的调度,事务等都或多或少与之相关,在提升性能这一块 Event Loop
能够作的事情不少。
array[Symbol.iterator]().next()
的语法糖,forEach + await 别用就对了。设计模式并非多么晦涩难懂的概念,咱们平常开发中多少都会接触到。它是前人在实际生产项目中不断迭代、试错、修正、抽象而来的经验总结,使用设计模式可让你的代码变得更加可维护、易于扩展。说人话就是日常能用就用,重构时必用。
工厂模式:组件化中经常使用的重构利器。
单例模式:分懒汉式和饿汉式,好比数据库链接,vuex、redux 等状态管理工具,甚至更复杂的场景,必须掌握。
观察者模式:太多地方用了,好比 Vue 响应式中的收集依赖和触发更新。
发布-订阅模式 与 观察者模式 的区别:在观察者模式中,观察者是知道 目标 Subject 的,Subject 一直保持对观察者进行记录。然而,在发布订阅模式中,发布者和订阅者不知道对方的存在。它们只有经过一个中间层,消息代理进行通讯,同时是异步的。在发布订阅模式中,组件是松散耦合的,正好和观察者模式相反。
观察者模式 举例:你对某知名企业很感兴趣(你做为观察者知道企业大名),投递简历后企业维护你和其余面试者的简历(企业知道了你),当职位空缺时主动通知你和其余面试者。这个例子,双方是直接的关系。
其实还有:状态模式、策略模式 都比较常见,也比较简单,一看就会,实际开发中若是写烦了 if-else
,也能够换换写法,优雅一下。
享元模式、中介者模式,emmm...跟 发布-订阅模式 极其的相似。
而 适配器模式(用于封装)、装饰者模式(用于加强功能)、代理模式(Vue3 的 Proxy)较易混淆,有兴趣就多了解。
主要讲讲主流框架
Vue
和React
,包括但不限于:框架演进、框架横向对比、虚拟 Dom、渲染、响应原理、版本差别、Diff 算法等...
解释器
经过词法分析和语法分析将源码转成 AST,根据 AST 生成执行上下文。解释器
根据 AST 生成 V8 字节码。为何不是二进制机器码:机器码太大,执行占用太多内存。解释器
逐行执行字节码,遇到热点代码启动 编译器
进行编译,生成对应的机器码, 以优化执行效率。针对 Js 运行的性能优化:
科普:不少人在刚入门的时候对 V八、Webkit、JSCore、runtime 这几个词没有概念,或者傻傻分不清,笔者在这里简单梳理下。
复制代码
AST,彷佛处处都有它的影子,包括浏览器、主流框架、Webpack 等打包工具、Babel、跨平台应用框架,如 uni-app 、Vue 转小程序。了解了 AST,以后不管是优化仍是转换,不过是增删改查罢了。
解析模版,生成 AST 语法树:
词法分析:使用大量的正则表达式对模板进行解析,遇到标签、文本的时候都会执行对应的钩子进行相关处理。
优化:其中涉及 静态节点优化
,设置 static 属性用于 Diff 时剪枝,静态节点就是一些不带变量的文本节点,或者一些不带 if 和 for 的节点。用于在下次渲染时直接跳过。
深度遍历 AST,标记静态节点以优化跳过比对,最后转为可执行的代码。
总结:语法分析 -> 语法分析 -> 优化
到这里,其实 AST 的任务已经结束。如下是 template 接下来的代码逻辑。
AST 会通过 generate 函数获得 render 函数,不一样的节点有不一样的 render 处理方式。render 生成虚拟 Dom,最后 patching,Diff,渲染 Dom。
3.引伸:flutter、React Native 的渲染机制
vue2.0 响应式原理 看这篇够够的了。
view 变化触发 data 更新经过事件监听
如下是 data 触发 view 更新
v2 中是递归遍历 data 中的全部的 property,并使用 Object.defineProperty
把这些 property 所有转为 getter/setter,在getter 中作数据依赖收集处理,在 setter 中 监听数据的变化,并通知订阅当前数据的地方
具体:
1.实现一个监听器 Observer:对数据对象进行遍历,包括子属性对象的属性,利用 Object.defineProperty()
对属性都加上 setter 和 getter。这样的话,给这个对象的某个值赋值,就会触发 setter,那么就能监听到了数据变化。
2.实现一个解析器 Compile:解析 Vue 模板指令,将模板中的变量都替换成数据,而后初始化渲染页面视图,并将每一个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变更,收到通知,调用更新函数进行数据更新。
3.实现一个订阅者 Watcher:Watcher 订阅者是 Observer 和 Compile 之间通讯的桥梁 ,主要的任务是订阅 Observer 中的属性值变化的消息,当收到属性值变化的消息时,触发解析器 Compile 中对应的更新函数。
4.实现一个订阅器 Dep:订阅器采用 发布-订阅 设计模式,用来收集订阅者 Watcher,对监听器 Observer 和 订阅者 Watcher 进行统一管理。
限制:
没法检测对象属性的添加与删除,须要配合 set/delete
defineProperty 监听 array 是有缺陷的:改变 length 长度或者超出设置,监听都会失效。
性能问题,层级太深致使性能降低
因此 vue 在数组的原型方法上作了一些手脚 defineProperty(obj, 'push') 监听 push 方法
检测数组变化源码解析:
1.Object.create(arrayPrototype)
初始化一个以数组原型对象 Array.prototype 为参数的对象:Object.create(Array.prototype)
2.将该对象里的全部数组方法用 definePrototype 重写
3.在数据 observer 绑定的时候,判断数据对象是否有 __proto__
,有就将数据直接绑定上重写后的原型
4.若是浏览器不支持 __proto__
,依据原型链,就将重写的原型直接挂在数据上好了。
5.这样当调用数组 api 时,能够通知依赖更新,若是数组包含引用类型,继续递归遍历监控
$set 原理:
若是目标是数组,直接使用数组的 splice 方法触发相应式。
若是目标是对象,会先判读属性是否存在、对象是不是响应式。
最终若是要对属性进行响应式处理,则是经过调用 defineReactive 方法进行响应式处理,最后通知订阅 notify。
总结:对象和数组都是经过递归遍历
vnode 对象是树的递归遍历
O(n^3) -> O(n)
触发setter -> 触发通知 notify -> 触发 watcher 加进异步更新队列,eventloop 会清空队列,watcher 尝试执行更新函数 -> 调用渲染函数,从新计算 vdom -> 进行 diff
代码逻辑:
没有旧节点,直接建立新的。
新旧 vnode 不一样,直接销毁旧的,建立新的。
新旧 vnode 相同,继续比较子节点:
其中 vnode 为文本节点,与旧不一样则直接更新
子节点依旧是新旧之间的比较,只有新节点直接建立,只有旧节点则删除旧的,新旧又不一样,开始 diff 核心算法,重点讲解:
while 循环比较新旧子节点:头索引跟头比较,尾跟尾,比完缩减往中间收拢,比较听从:
头与头比较,相同则复用不做处理,同时头++,尾、头尾、尾头的目的都是为了复用
用 key 比较
map 表遍历查找
剩余节点,批量新增或删除
总结:能不动就不动,不行就移动,最后处理新建或者删除。相比React的Diff算法,一样状况下能够减小移动节点次数,减小没必要要的性能损耗,更加的优雅。
vdom:建立 vdom 的时候多了个 dynamicChildren 动态节点,patch 的时候只比对动态。
vue2 静态节点也会 patch。
vdom:节点变动类型用 patchFlag 细分,用位掩码组合,做为断定更新的依据。
vue2 若是是普通节点,会经过内置的update钩子全量进行新旧对比,而后更新;若是是component,则会在prepatch阶段进行判断,有变化则会从新触发forceUpdate,形成不少无用的重复对比。
diff 核心变化:用数组 map 记录节点变动的位置以及新增的节点 + 最长子序列(若是递增则位置不变)。
相同事件缓存不会从新生成。
vnode 对象是链表的循环遍历,与递归不一样的是能够设置暂停和恢复,根据调度展开的优化代码。
复用没有变动的节点,用 key。
先比较两棵树的根节点,如果不一样的类型,则直接销毁旧的,重建新的。如果相同的类型,则看下 className、style 等是否相同,同时保留不变的状态,比较完继续对子节点递归,好比列表,在设置 key 的状况下 diff 的开销会更小 (没有key的状况下,在表头插入将会重建,表尾只会添加)
MVC 相信这是绝大部分程序员最先接触到的架构。
MVVM 双向绑定:V 的变更,自动反映在 VM 上。V 和 M 不发生联系,其余部分的通讯都是双向的。
MVVM 框架目前存在的问题:执行效率,数据改变, UI 也会频繁更新,引起子组件更新,性能不是最优。好消息是 Vue 3
已经解决了这个子组件重复渲染的问题,但需知没有完美的解决方案,只有舍与得。
不少人没有分清的是:ReactJs 实际上是一个单向数据流的 js 库,状态驱动视图,是 MVC。而 React 全家桶是 MVP,近似 MVVM。
复制代码
自己 C,P,VM 的边界界定就十分模糊,不用钻牛角尖,核心其实就是每一层专一于每一层的任务。如何对代码进行组织管理,仍是要看需求来界定的,这也是框架架构模式不断发展的缘由。
这一道题,能够说是上面的归总,咱们能够从大到小,从略到详,从思想、生态、语法、数据、通讯、Diff、版本等角度来说,笔者整理了一些,如下挑几个重点吧...
Vue 和 React
Vue3 和 React16 的区别
Vue3 和 React16 的类似处
Vue3 和 React16 总结
从输入到渲染的整个流程?
流程里每一个部分拿出来都能深挖,我认为这道题很有道中三生万物的韵味,前端的一切均可以从这里开始,说白了 PC 的前端是被绑定在浏览器中的。
我本人本来对于渲染的这一块,图层和合成理解并不清晰,因而将这篇放这里:为何 CSS 动画比 JS 高效
位移距离 × 位移影响的面积 < 0.1
知足这个公式便算体验优秀,反例:小屏手机上忽然插入 dom 或广告让人膈应。浏览器缓存
掌握强缓存字段,协商缓存字段。
展开:除了常规的缓存手段,还能够扩展下 1.代理缓存,2.V8 代码缓存
HTTP
这一块的内容是经过一些书籍和文章整理来的,记录了一些容易混淆的点。
首先须要理清:http2 解决性能问题;http3 解决 http2 遗留问题;https 解决安全问题。
HTTP 加密算法
对称加密
非对称加密
传统 RSA 握手:是 1. + 2. + 数字证书
结合(在交换密钥环节使用公开密钥加密方式,创建通讯交换报文阶段使用共享密钥加密方式)
TLS1.2 握手,与 3.
的区别在于 pre_random
的生成方式不一样。
证书相关:
证书只解决了公钥持有人究竟是谁。
原证书内容:签发者、证书用途和基本信息、服务器公钥、服务器加密算法、服务器 HASH 算法、证书的到期时间等。
原证书内容 + 最重要的防篡改的数字签名 = 服务器发给客户端的数字证书
数字签名:对原证书内容进行 hash 函数(好比 SHA256)生成的摘要 digest(摘要表明服务器身份,能够理解为身份证),通过 CA 私钥加密后生成数字签名 signature,将数字签名附在原证书末尾。这里跟 JWT 很像。
客户端收到数字证书,使用 CA 公钥解密 signature 获得 digest 验明身份,再使用 hash 函数对证书原数据计算,获得的结果与 digest 对比,彻底一致说明数据未被修改
放出《图解 HTTP》原文用以确认:
服务器有本身的公钥和私钥,此时向 CA 申请证书,提交本身的公钥及基自己份信息。
CA 也有本身的公钥和私钥,...用 CA 本身的私钥...生成数字签名,同时将服务器公钥绑定入证书。这里注意:CA 公钥已经在咱们安装浏览器的时候植入咱们机器了。
客户端收到数字证书,先用浏览器内置的 CA 公钥解密证书的数字签名,获得 hash 后的摘要,咱们假定叫作 hash_0
,而后咱们本身使用 hash 函数对证书内原报文进行计算,生成 hash_1
,二者一致便可确认服务器公钥的真实性。
Q
:中间人是否会拦截发送假证书到客户端呢?
A
:由于证书的签名是由服务器端网址等信息生成的,而且经过第三方机构的私钥加密中间人没法篡改; 因此最关键的问题是证书签名的真伪。
还有 网络安全
、4 种常见链接方式
、TCP 握手和挥手
、TCP 流量控制和拥塞控制
、HTTP 传输各类资源的表头字段
、流与分段传输 (包括上传和下载)
、TCP 序列号
等一堆重点。
扩展:
UDP 协议在游戏场景使用较多,有 DTSL 保证安全,UDP 至关于 4 层的 IP 协议,方便上层协议的自定义和扩展。
https 握手证书验证过程太耗费流量,同时因安全问题被禁止压缩,且假如把 tls 只是当作一个技术参考,是能够任意修改的,因而不少企业开始自定义内部协议,好比微信。
QUIC(Quick UDP Internet Connections)
基于UDP的传输层协议,提供像TCP同样的可靠性。
直播协议:RTMP、HTTP-FLV、HLS
只有严格的工序、精确的用量才能保证甜品如咱们预期;只有不断改进烘焙方式和花样才能推陈出新,吸引更多顾客;只有好吃的甜品可以给人愉悦和幸福感。
完整的开发流程通常以下:
价值:你作的东西是否有价值?价值囊括不少方面。
推进力:企业所但愿看到的,升职加薪的必要条件。
社区产出:提升你的社会影响力,可能创造无限可能的将来。这一块大厂彷佛很看重,有没有道友现身说法的 ?
就像简历中咱们所写的:将某个项目的首屏加载提升了 x 倍,在 LCP、FID、CLS 等核心指标上又优化减小了多少秒;今天将软件运行优化得趋于原生体验;明天又产出了某个自研脚手架,提升 x 倍的开发效率;还有社区贡献,影响力...这些都是价值,或者说亮点。
价值在企业招聘中,比重很大,关乎你的将来钱途。甚至间接影响你的身体情况。
别不信,举个例子:程序员,避免不了天天面对新的需求,可是工做内容都是那样,重复又重复,若是一味莽干,免不了要加班、要秃头,占用多少本身的时间和生命?因此一个具备高价值、高优先级的东西,就是提效工具。
有些老油子可能会说:工做都那么忙了,业务需求频繁变动,哪来的时间?我只能轻蔑一笑,呵呵,时间如乳 go&%f3h,挤挤老是会有的。
一个提效工具能挽救多少业务、多少根头发,多少对情侣,相信几年以后,诸君会深有体会。
总结:优先作重要不紧急的事情:我的/团队规划、提效工具/平台创建、锻炼身体/我的影响力创建。事情是作不完的,只须要保证最重要的事情一直在被推动,不重要的能够讨论/推掉/改方案,最后还有一点,就是持续反思,反思可让你进步飞快。
早些时候参加了个线下峰会,当时看着一群大佬轮流在台上技术分享,都是一些很是有意思的干货内容,整场下来个人状态是:吃鲸...兴奋...崇拜...
这就是前端吗 ?i 了 i 了,因而额前绑上奋斗的 “奋”,一头莽进了这行。
转眼 0202!
入行这几年,大部分时光都是平淡无奇的,我原本就是个平凡、温和、闷骚、咸鱼的人……常驻知乎、掘金等社区却一直潜水不起一点波纹。
某个时刻,我阅读到 神三元 的系列文章,起初以为干货满满,嗯,这是个大佬,关注了,每次阅读完他的文章我都淡定地喝一口茶,感受获益良多。
疫情期间,他又有产出,我照例翻出一览,良久,我喝了口茶,随后眉头一皱,顿觉不对,看下标题,春招?……噗!我震惊,不肯定,而后欣喜,沮丧……
这!这竟然是一个大三学生,我 &$%^@,大三就进了字节互娱架构组,了不得,恭喜你……
没有比较就没有伤害,想一想本身……emmm,原来我是个假前端!
神三元早早就明确了将来目标,就像他文章中说的,找到了痛点。而咱们大多数人直到工做了,还很迷茫。就像女生刷 Fit 视频,看到视频里的健身达人曲线姣好的身材,羡慕不已。但看完视频,却只是简单地在床上翻了个身给予回应,甚至还照常打开某团点了杯奶茶。
呵呵,我不想再这样了,如今,先完成 那个 目标吧!
写给将来的我和大家……