这篇文章主要总结在近期面试中遇到的答不上来或者答不完整的问题。题目都是自行查阅整理,不知道是不是面试官想要的答案。
1. JSBridge
JSBridge是连接Native(客户端)和JavaScript前端的桥梁,通过JSBridge 两端的代码才可以通信。
native访问h5方法,只需在h5全局定义一个方法,native即可以调用。
h5调用native方法,1)API注入,native将方法挂在window上,h5使用window.xxx来调用;2)拦截url,将url(自定义scheme:'ownHttp://xxx')放入iframe中插入页面(display:none),native拦截url执行原生方法;3)h5的console,alert,prompt能够被native拦截console.log('ownHttp://xxx')
2. redux 和 context 区别
redux是做状态管理的,使用store存储数据,action触发事件,使用dispatch,reducer处理时间,用来修改状态。
context提供了无需传递props就可以向组件传递数据的方法。
两者区别或者怎么选择?
redux提供了对状态的修改方法,而context只是单纯的取值。如果您正在处理一个更复杂的应用程序,并希望查看您的应用程序的所有dispatch操作的历史记录,“点击”其中任何一个并跳转到该时间点,然后绝对考虑使用Redux。但是,如果你只想让一些数据全局化以便从一堆组件中访问它大可不必使用redux而用context。
3. react native 热更新原理
暂时不好整理,等我实际用到有所领悟再来补充把。
// TODO
4. 异常处理
- 使用 try-catch 语句
- onerror:任何没有通过try-catch处理的错误都会触发window对象的error事件。
将错误保存到服务器,标明是来自前端。利用img中的src路径可以访问跨域的地址,将错误传到后端。
function logError(msg){
let img = new Image();
img.src = `http://xxx?msg=${encodeURIComponent(msg)}`
}
try{
}catch(err){
logError(err)
}
5. react hooks有什么缺点
- 目前暂时还没有对应不常用的 getSnapshotBeforeUpdate,getDerivedStateFromError 和 componentDidCatch 生命周期的 Hook 等价写法。
- 目前 Hook 还处于早期阶段,一些第三方的库可能还暂时无法兼容 Hook。
额,不知道面试官想到的是不是这个答案...
6. 虚拟dom除了渲染方面性能好,还有什么优点
优点:
- 保证性能下限: 框架的虚拟 DOM 需要适配任何上层 API 可能产生的操作,它的一些 DOM 操作的实现必须是普适的,所以它的性能并不是最优的;但是比起粗暴的 DOM 操作性能要好很多,因此框架的虚拟 DOM 至少可以保证在你不需要手动优化的情况下,依然可以提供还不错的性能,即保证性能的下限;
- 无需手动操作 DOM: 我们不再需要手动去操作 DOM,只需要写好 View-Model 的代码逻辑,框架会根据虚拟 DOM 和 数据双向绑定,帮我们以可预期的方式更新视图,极大提高我们的开发效率;
- 跨平台: 虚拟 DOM 本质上是 JavaScript 对象,而 DOM 与平台强相关,相比之下虚拟 DOM 可以进行更方便地跨平台操作,例如服务器渲染、weex 开发等等。
缺点:
无法进行极致优化: 虽然虚拟 DOM + 合理的优化,足以应对绝大部分应用的性能需求,但在一些性能要求极高的应用中虚拟 DOM 无法进行针对性的极致优化。
首次渲染大量DOM时,由于多了一层虚拟DOM的计算,会比innerHTML插入慢。
7. 强制缓存中cache-control设为no-cache后,就一定没有缓存吗,协商缓存的缓存放在那里?
缓存是指代理服务器或客户端本地磁盘内保存的资源副本。利用缓存可减少对源服务器的访问,因此也就节省了通信流量和通信时间。
缓存服务器是代理服务器的一种,并归类在缓存代理类型中。换句话说,当代理转发从服务器返回的响应时,代理服务器将会保存一份资源的副本。
no-cache — 设了no-cache也可以在本地或者proxy服务器进行缓存,但是每次发起请求都要去服务器验证,服务器返回可以使用缓存,才可以真正使用本地缓存,任何节点都不能直接使用缓存。
协商缓存的缓存放在代理服务器。
8. 解释状态码 301 永久性定向和 302 临时性定向
301: 永久性重定向。表示请求的资源已被更改为新的URI,以后应使用资源现在所指的 URI。如果已经把资源对应的 URI 保存为书签了,这时应该按 Location 首部字段提示的 URI 重新保存。
302:临时性重定向。该状态码表示请求的资源已被分配了新的 URI,希望用户(本次)能使用新的 URI 访问。已移动的资源对应的 URI 将来还有可能发生改变。
303:该状态码表示由于请求对应的资源存在着另一个 URI,应使用 GET 方法定向获取请求的资源。303 状态码和 302 Found 状态码有着相同的功能,但 303 状态码明确 表示客户端应当采用 GET 方法获取资源,这点与 302 状态码有区 别。
304:该状态码表示客户端发送附带条件的请求(附带条件的请求是指采用 GET方法的请求报文中包含 If-Match,If-Modified- Since,If-None-Match,If-Range,If-Unmodified-Since 中任一首部。) 时,服务器端允许请求访问资源,但未满足条件的情况(有缓存,没有更新页面)。
403 Forbidden:被拒绝了
500 Internal Server Error:该状态码表明服务器端在执行请求时发生了错误。也有可能是 Web 应用存在的 bug 或某些临时的故障。
503 Service Unavailable:该状态码表明服务器暂时处于超负载或正在进行停机维护,现在无法 处理请求。
9. 0.1+0.1 != 0.3 js数值精度问题,转换成二进制计算导致精度丢失,那么详细讲讲精度是怎么丢失的
恕我无法描述出来,
请参考:
彻底弄懂:0.1+0.2 != 0.3
0.1+0.2 !== 0.3?
10. 手写迭代器
function iterator(arr) {
let i = 0
return {
next: () => {
return {
value: i < arr.length ? arr[i++] : undefined,
done:i < arr.length ? false : true,
}
}
}
}
var it = iterator(['a', 'b']);
it.next() // { value: "a", done: false }
it.next() // { value: "b", done: false }
it.next()
11. fib 斐波那契数列
题目:f(0) = 1, f(1) = 1, f(2) = 2, 实现 f(n) = f(n-1)+ f(n-2)
这道题目是在面试官的引导下完成的。首先写一个最简单的:
function f(n){
if(n<2) return 1
return f(n-1) + f(n-2)
}
然后面试官问我,这样可以实现,但是f(n) = f(n-1) + f(n-2), f(n-1) = f(n-2) + f(n-3),在这样递归计算的过程中,有每个值都被多次计算,应该如何优化,考虑将计算过的值存起来。 鄙人无能,没想到实现方法,,,面试官提醒我可以利用Map,
var obj = new Map()
function f(n) {
if (n < 2) return 1
if (obj.has(n)) return obj.get(n)
const value = f(n - 1) + f(n - 2)
obj.set(n, value)
return value
}
或者使用for循环来计算
var arr = [1, 1]
function f(n) {
if(arr[n]) return arr[n]
for (let i = 2; i <= n; i++) {
arr[i] = arr[i - 1] + arr[i - 2]
}
return arr[n]
}
12. typeof null == 'object'原因
“typeof null 为"object", 原因是因为 不同的对象在底层都表示为二进制,在Javascript中二进制前三位都为0的话会被判断为Object类型,null的二进制表示全为0,自然前三位也是0,所以执行typeof时会返回"object"。
这个bug是第一版Javascript留下来的。在这个版本,数值是以32字节存储的,由标志位(1~3个字节)和数值组成。标志位存储的是低位的数据。这里有五种标志位:
000:对象,数据是对象的应用。
1:整型,数据是31位带符号整数。
010:双精度类型,数据是双精度数字。
100:字符串,数据是字符串。
110:布尔类型,数据是布尔值。
参考: https://blog.csdn.net/weixin_42952665/article/details/82750684
13. 实现深拷贝
我给出的答案:
var deepCopy = (function f(target) {
if (typeof target !== 'object') return
var newData = target instanceof Array ? [] : {};
for (var item in target) {
if (target.hasOwnProperty(item)) {
newData[item] = typeof target[item] == 'object' ? f(target[item]) : target[item];
}
}
return newData;
})
面试官灵魂拷问1: 第一句if (typeof target !== 'object') return
基础类型传进来就return了吗,什么也不返回? 我说那就把target再返回去。
2:typeof target !== 'object' 判断对象一定准确吗?碰到null怎么办?我心里默想那就再加一个判断它不是null,追问:碰到Date怎么办? 额,我心里想那要判断的有点多了,确实不合适。面试官指导:
对象类型的转换为字符串会变成 "[object Object]",null会变为"[object Null]",数组会变为"[object Array]",能否利用?
Object.prototype.toString.call(target)
3:newData[item] = typeof target[item] == 'object' ? f(target[item]) : target[item];
这句不可以直接用newDate[item] = f(target[item])
吗?我说基础类型走递归不太好吧,他说,如果第一句就return了target,那不也没执行下边的吗?
嚯,
经过我最终整理,实现如下:
var deepCopy = (function f(target) {
// 将目标转换为字符串来判断类型,null转换为"[object Null]",
// new Date():"[object Date]",数值:"[object Number]",字符串:"[object String]"等
const type = Object.prototype.toString.call(target);
let newData = type == '[object Object]' ? {} : (type == '[object Array]' ? [] : false)
if(!newData) return target
for (var item in target) {
//只复制元素自身的属性,不复制原型链上的
if (target.hasOwnProperty(item)) {
newData[item] = f(target[item]);
}
}
return newData;
})
这次应该没问题了把。。。
14. 列举会使GPU硬件加速的css属性
先来了解一下何为GPU硬件加速:
就是将浏览器的渲染过程交给GPU处理,而不是使用自带的比较慢的渲染器。这样就可以使得animation与transition更加顺畅。一般一个元素开启硬件加速后会变成合成层,可以独立于普通文档流中,改动后可以避免整个页面重绘,提升性能,因此我们可以在浏览器中用css开启硬件加速,使GPU (Graphics Processing Unit) 发挥功能。
可以触发硬件加速的css属性:
transform
opacity
filter
为什么硬件加速会使页面流畅?
因为 transform 属性不会触发浏览器的 repaint(重绘),而绝对定位absolute中的 left 和 top 则会一直触发 repaint(重绘)。
为什么 transform 没有触发 repaint 呢?简而言之,transform 动画由GPU控制,支持硬件加速,并不需要软件方面的渲染。
如何开启硬件加速?
CSS animations, transforms 以及 transitions 不会自动开启GPU加速,3d动画才会开启:translateZ( ) 或 translate3d( ),但是很多时候并不需要3d变换:
webkit-transform : translateZ ( 0 ) ;
-moz-transform : translateZ ( 0 ) ;
-ms-transform : translateZ ( 0 ) ;
-o-transform : translateZ ( 0 ) ;
transform : translateZ ( 0 ) ;
webkit-transform : translate3d ( 0 , 0 , 0 ) ;
-moz-transform : translate3d ( 0 , 0 , 0 ) ;
-ms-transform : translate3d ( 0 , 0 , 0 ) ;
-o-transform : translate3d ( 0 , 0 , 0 ) ;
transform : translate3d ( 0 , 0 , 0 ) ;
在 Chrome and Safari中,当我们使用CSS transforms 或者 animations时可能会有页面闪烁的效果,下面的代码可以修复此情况:
-webkit-backface-visibility: hidden;
-moz-backface-visibility: hidden;
-ms-backface-visibility: hidden;
backface-visibility: hidden;
-webkit-perspective: 1000;
-moz-perspective: 1000;
-ms-perspective: 1000;
perspective: 1000;
15. 列举pc端和移动端的兼容性问题和解决方案
移动端:
- 不同浏览器的最小字体不同,有的是10px,有的是12px
解决办法:设置字体时,不要小于12px,如果一定要小于12px,使用transform:sacle()进行缩放 - 透明度opacity
解决办法:IE8 以及更早的版本支持替代的 filter 属性。例如:filter:Alpha(opacity=50) - Input 的placeholder会出现文本位置偏上的情况
input 的placeholder会出现文本位置偏上的情况:PC端设置line-height等于height能够对齐,而移动端仍然是偏上,解决是设置line-height:normal
PC端:
- 如果图片加a标签在IE9-中会有边框
解决方案:img{border:none;} - display:inline-block ie6/7不支持
解决方案: display:inline; - 标准的事件绑定方法函数为addEventListener,但IE下是attachEvent;
16. SEO(搜索引擎优化)
SEO的存在就是为了提升网页在搜索引擎自然搜索结果中的收录数量以及排序位置而做的优化行为。而优化的目的就是为了提升网站在搜索引擎中的权重,增加对搜索引擎的友好度,使得用户在访问网站时能排在前面。
如何做?
- 网站结构布局优化:尽量简单、开门见山,提倡扁平化结构
(1) 控制首页链接数量
(2) 扁平化的目录层次
(3) 导航优化:导航应该尽量采用文字方式,也可以搭配图片导航,<img>标签必须添加“alt”和“title”属性,告诉搜索引擎导航的定位。在每一个网页上应该加上面包屑导航。
(4)网站的结构布局---不可忽略的细节
(5)利用布局,把重要内容HTML代码放在最前
(6)控制页面的大小,减少http请求,提高网站的加载速度 - 网页代码优化
(1)突出重要内容---合理的设计<title>、<meta description>和<meta keywords>
(2)语义化书写HTML代码,符合W3C标准.eg:标题用h1-h6,列表用ul,li,重要文字用strong
(3)<a>标签:页内链接,要加 “title” 属性加以说明,让访客和 “蜘蛛” 知道。而外部链接,链接到其他网站的,则需要加上 el="nofollow" 属性, 告诉 “蜘蛛” 不要爬,因为一旦“蜘蛛”爬了外部链接之后,就不会再回来了。
等。。。 - 前端网站性能优化
(1)减少http请求数量.CSS Sprites(图片精灵),合并CSS和JS文件(使用grunt、gulp、webpack等),采用lazyload(懒加载)
(2)控制资源文件加载优先级
(3)尽量外链CSS和JS(结构、表现和行为的分离),保证网页代码的整洁,也有利于日后维护
(4)利用浏览器缓存
(5)减少重排(Reflow)
(6)减少 DOM 操作
(7)图标使用IconFont替换
等。。。
参考:https://juejin.cn/post/6844903824428105735
17. SSR
是什么?
server side render,服务端渲染。即:SSR大致的意思就是客户端将标签渲染成的整个 html 片段的工作在服务端完成,服务端形成的html 片段直接返回给客户端这个过程就叫做服务端渲染。
优缺点?
优点:
- 更好的 SEO。 因为 SPA (单页面应用)页面的内容是通过 Ajax 获取,而搜索引擎爬取工具并不会等待 Ajax 异步完成后再抓取页面内容,所以在 SPA 中是抓取不到页面通过 Ajax 获取到的内容;而 SSR 是直接由服务端返回已经渲染好的页面(数据已经包含在页面中),所以搜索引擎爬取工具可以抓取渲染好的页面。
- 更快的内容到达时间(首屏加载更快): SPA 会等待所有编译后的 js 文件都下载完成后,才开始进行页面的渲染,文件下载等需要一定的时间等,所以首屏渲染需要一定的时间;SSR 直接由服务端渲染好页面直接返回显示,无需等待下载 js 文件及再去渲染等,所以 SSR 有更快的内容到达时间。
缺点:
- 更多的开发条件限制: 例如服务端渲染在vue中只支持beforCreate和 created 两个钩子函数,这会导致一些外部扩展库需要特殊处理,才能在服务端渲染应用程序中运行;并且与可以部署在任何静态文件服务器上的完全静态单页面应用程序SPA不同,服务端渲染应用程序,需要处于 Node.js server 运行环境;
- 更多的服务器负载:在 Node.js 中渲染完整的应用程序,显然会比仅仅提供静态文件的 server 更加大量占用CPU 资源 (CPU-intensive - CPU 密集),因此如果你预料在高流量环境 ( high traffic ) 下使用,请准备相应的服务器负载,并明智地采用缓存策略。
参考: https://juejin.cn/post/6913752813403111438
18. PWA
PWA全称Progressive Web App,即渐进式WEB应用。
一个 PWA 应用首先是一个网页, 可以通过 Web 技术编写出一个网页应用. 随后添加上 App Manifest 和 Service Worker 来实现 PWA 的安装和离线等功能
解决了哪些问题?
- 可以添加至主屏幕,点击主屏幕图标可以实现启动动画以及隐藏地址栏
- 实现离线缓存功能,即使用户手机没有网络,依然可以使用一些离线功能
- 实现了消息推送
它解决了上述提到的问题,这些特性将使得 Web 应用渐进式接近原生 App。
参考:
讲讲PWA
Service Worker
网友评论