前端面试题总结

·  阅读 456

1. html

1. 如何理解html语义化

1. 让人更好的读懂 
2. 让搜索引擎更好的读懂 (有利于SEO)
复制代码

2. 详细例举一些 html标签 中内联元素 和 块级元素

块级元素 display: block/table  (div h1 h2 ul ol p table 等)
内联元素 display: inline/inline-block (span button input select img 等)
复制代码

2. css

1. flex布局

父元素上有什么属性 
    display: flex || inline-flex;
    justify-content: center || flex-start || flex-end || space-around || space-between
    align-items: center || flex-start || flex-end || stretch || baseline 
    flex-direction: row || row-reverse || columns || columns-reverse
    flex-wrap: wrap || nowrap || wrap-reverse
    flex-flow: flex-direction || flex-wrap 
    align-content: flex-start || flex-end || center || stretch
子元素上有什么属性
    order: <interger>
    align-self: flex-start || flex-end || center 
    flex-growth: <interger>
    flex-shrink: <interger>
    flex-basis: <interger>
    flex: flex-growth || flex-shrink || flex-basis 
复制代码

2. relative 和 absolute 依据什么来定位?

    relative 依据自身来进行定位
    absolute 依据最近一层的定位元素来进行定位 
    没有找到定位元素的话, 就会找到body
    
复制代码

3. 水平居中

行内元素 - 用 text-align: center 
块级元素 - 用 margin: 0px auto;
absolute元素 - left:50%; margin-left:<子元素宽度的负值>
display:flex; justify-content:center;
复制代码

4. 垂直居中

行内元素 - 用 line-height 取 父元素高度的值 
absolute元素 - top:50%; margin-top:<子元素高度的负值>
absolute元素 - top:50%; transform:translate('-50%')
absolute元素 - top:0px; bottom:0px; margin:auto; margin为auto的话 浏览器会自动分配均等空间 
display:flex; align-items:center;

复制代码

5. 水平垂直居中

flex布局 - display:flex; justify-content:center; align-items:center;
行内元素 - text-align:center; line-height: <父元素的高度>
absolute元素 - top:50%; left:50%; margin-left: 负值 margin-top: 负值 
absolute元素 - top:50%; left:50%; transform:translate('-50%','-50%')
absolute元素 - top:0px; right:0px; bottom:0px; left:0px; margin:auto;
复制代码

6. img中alt和title的区别

alt为图片加载不出来的时候,显示的文字
title为鼠标移到图片上面的时候,显示的文字
复制代码

7. css盒模型问题

.div {
    width:100px;
    padding:10px;
    border:1px solid black;
}
offsetWidth = width + padding + border
offsetWidth = 100px + 20px + 2px 

.div {
    width:100px;
    padding:10px;
    border:1px solid black;
    box-sizing:border-box;
}
offsetWidth = width 
复制代码

8. margin纵向重叠问题

2个元素上下相邻的时候 margin-bottom margin-top 取最大的值 重叠
复制代码

9. 移动端布局有哪些方案


固定布局

在<head>里把viewport加好,根pc端一样,设想整个网页的宽度为320px居中即可,超出部分留白。

优点:思路沿用PC端,上手简单。

缺点:大屏幕手机及手机横屏时,两边是留白较大,且大屏幕手机下看起来页面会特别小,操作的按钮也很小,用户体验较差

流式布局

流动布局重点就是使用百分比来代替传统px,但是元素的高度大都是用px来固定住,所以在大屏幕的手机下显示效果会变成有些页面元素宽度被拉的很长,但是高度还是和原来一样, 优点是流动布局可以很好解决自适应需求,缺点是通过大量的百分比布局,会出现兼容性的问题,且更适用于对横向拉伸的设计元素,设计的时候存在很多局限性

响应式做法

根据目标用户的访问设备的主要类型做三种或四种布局。 每种布局有一个区间即可利用媒体查询@media,可以为不同分辨率的设备加载不同的样式。这种方法的优点是可以相对精确的控制显示效果,但可能需要对同一个类书写不同的样式会导致代码比较繁复,后期维护困难

rem布局

rem是指相对于根元素的字体大小的单位,即根据html元素的font-size来计算大小。 比如说html的font-size大小为100px,一个div的width为1rem,则div的width大小为100px。

复制代码

10. rem是什么

px 绝对长度单位 
em 相对长度单位 相对于父元素 
rem 相对长度单位 相对于根元素
复制代码

11. 响应式布局的常用方案

1.@media-query, 根据不同屏幕的宽度设置根元素的 font-size
2.rem,基于根元素的相对单位 
复制代码

12. 网页视口尺寸

window.screen.height 屏幕高度
window.innerHeight 网页视口高度
document.body.clientHeight  body高度
复制代码

13. vh/vw/vmax

vh 网页视口高度的 1 / 100
vw 网页视口宽度的 1 / 100
vmax 取两者最大值;vmin 取两者最小值
复制代码

14. css3 什么属性促进硬件加速

    动画卡顿在移动web开发的过程中是会经常遇到的,解决这个问题,一般都会用到css3开启硬件加速。这个名字听起来很高大上,但是它做的事情很简单,就是通过GPU(Graphics Processing Unit)进行渲染,解放CPU。   

  CSS的 animation、tranform、transition并不会自动开启GPU加速,而是通过浏览器的缓慢的软件渲染引擎来实现执行,那么我们怎么才能实现GPU加速呢,很多浏览器提供了某些触发该模式的规则。

  比如使用 translate3d() rotate3d() scale3d() 这几个方法,我们就可以使用GPU加速了。

  但是呢,某些情况下,我们并不想要对元素应用3D变换的效果,却还想要实现GPU加速,这是我们就可以使用简单的CSS属性来“欺骗”浏览器了, 触发硬件加速。
复制代码

14. 如何实现一个半圆

  div {
    width:100px;
    height:100px;
    border-top: 1px solid black;
    border-right: 1px solid black;
    border-top-right-radius:100%;
  }
复制代码

15. 如何实现一个三角形

  div {
    width:0px;
    height:0px;
    border:20px solid red;
    border-right-color: transparent;
    border-bottom-color: transparent;
    border-left-color: transparent;
  }
复制代码

16. 如何实现一个圆形

  div {
    width: 100px;
    height: 100px;
    border-raduis: 50%;
  }
复制代码

3. js

1.请列举常见的值类型和引用类型

值类型
    let a = undefined 
    let b = 1 
    let c = 'string'
    let d = true 
    let e = Symbol('e')
引用类型 
    let a = null 
    /*null是一个特殊的引用类型,指向一个空地址*/
    let b = { a: 1 }
    let c = [1,2,3]
    function fn() { }
    /*函数也是特殊的引用类型,不用于存储数据, 所以没有拷贝和复制函数这一说法*/
    
侧重点: 
    注意undefinednull 的区别 很容易把nullundefined 归属到值类型中去 null是特殊的引用类型 指向空地址
    ES6的新特性 Symbol 也是值类型 要说出来 面试官会问有哪些新的ES6特性属于值类型 
    函数也是一种特殊的引用类型 不要把函数给漏掉 
复制代码

2.变量计算和类型转换

2.1  字符串拼接
    100 + 10 = 110 
    100 + '10' = '10010'
    true + '100' = 'true100'
2.2 == 和 === 
    100 == '100' // true 
    0 == '' // true 
    0 == false // true 
    false == '' // true 
    null == undefined // true 
    // 除了 == null 之外, 其它一律用 === 
    const obj = { x: 100 }
    if(obj.a == null) {} 
    //相当于 if( obj.a === null || obj.a === undefined ){}
侧重点: 
   == 符号会进行类型转换 
   === 符号不会进行类型转换
2.3 truly 和 falsely 变量 
    truly 变量  !!a === true 的变量
    falsely 变量 !!a === false 的变量 
侧重点:
    if else 逻辑判断 (&& || !) 判断都是用的 truly 和 falsely 变量 
复制代码

3. typeOf 能判断哪些类型

    typeof的值 返回字符串
    typeof 能判断所有的值类型
    能判断函数 
    typeof 判断不了引用类型 
复制代码

4. 谈谈浅拷贝 和 深拷贝

浅拷贝: 只能复制 值类型 引用类型复制不了 复制出来的对象还是对应同样的内存地址
深拷贝:  创建一个新的对象 属性中原有的内存地址会被克隆 指向也会改变 
比如常见的方法: JSON.parse JSON.stringfy
复制代码

5. 如何理解原型和原型链

image.png

侧重点:
    画出这张图来给面试官解释什么是原型和原型链
复制代码

6.instanceOf 是基于什么实现的

instanceOf 是基于原型链来实现的
复制代码

7.call bind apply的区别

fn.call(this,p1,p2,p3)
fn.apply(this,arguments)
侧重点: 
    call - call的第二个参数是单个传进去的
    apply - apply的第二个参数是以类数组的方式传进去的 
复制代码

8.es6的新特性有哪些

var let const 
var 有变量提升的功能 
let 没有变量提升的功能 有块级作用域 
const 没有变量提升的功能 而且为常量 不可被修改 有块级作用域 
复制代码
给形参函数设置默认值
复制代码
数组的...展开运算符
复制代码
数组和对象的解构赋值
复制代码
箭头函数 箭头函数本质上是匿名函数 箭头函数是没有this的 它的this是继承上下文的this
复制代码

10.浏览器渲染页面的过程

根据html代码生成Dom tree
根据css代码生成Css DOM 
然后把Css DOM 和 Dom tree 进行合并 render tree 
然后浏览器通过render tree 进行渲染页面
侧重点: 
    当碰到script标签的时候,浏览器会执行暂停渲染render tree, 从而执行js代码, 因为js代码会改变dom元素。 
        所以这也是为什么js script 放到最后执行的原因
复制代码

11.请说说你对浏览器重绘和重排的理解

重绘是 更改元素的样式 但是不更改元素的高度和宽度 不影响元素的几何布局 
重排是 更改元素的高度和宽度 影响了元素的几何布局 导致页面重新排列dom元素节点
复制代码

12.什么是作用域

作用域: 变量的合法使用范围 
全局作用域: 在全局可以使用 
函数作用域: 在函数中使用
块级作用域(es6新增的语法): letconst声明的变量在{}中使用
复制代码

13.什么自由变量

如果变量在当前作用域没有被定义,被使用了
则一层层往上级作用域查找
直到查询到全局作用域,如果还没有被查找到,则报undefined
复制代码

14.什么闭包

闭包就是在变量定义的地方向上级作用域查找,而不是在变量执行的地方向上级作用域查找
复制代码
实际闭包常见的应用
    1.函数作为参数被返回 
    2.函数作为返回值被返回 
隐藏数据 只提供API修改数据
复制代码

15.闭包的缺点

js有垃圾回收机制 函数执行完就被销毁 闭包函数则会被保留 不会被销毁 
这样不利于性能 随着 闭包变量的增多 性能也会越来越差
复制代码

16.this有几种赋值情况

复制代码

17.js异步和同步的区别

js是单线程语言
同步会阻塞代码
异步不会阻塞代码
复制代码

18.前端异步的使用场景

网络请求 和 定时任务 等 
复制代码

19.promise的三种状态

三种状态 pending resolved rejected 
pendig => resolved 
pending => rejected 
状态变化是不可逆的 
复制代码

20.async await 函数

async/await函数是异步代码的新方式

async/await是基于promise实现的

async/await使异步代码更像同步代码

await 只能在async函数中使用,不能再普通函数中使用,要成对出现

默认返回一个promise实例,不能被改变

await下面的代码是异步,后面的代码是同步的

复制代码

21.http状态码

2开头 
    200 - 返回正常
复制代码
3开头 
    301 - 永久重定向
    302 - 临时重定向 
    304 - 有缓存 资源未被修改  
复制代码
4开头
    404 - 资源未找到
    403 - 没有权限
复制代码
5开头
    500 - 服务器报错 
复制代码

22. 什么是浏览器同源策略

ajax请求的时候 浏览器必须要求和服务器同源(为了安全来考虑)
同源: 域名 端口 IP 必须一样 
侧重点 : 加载css js 可以无视同源策略 
复制代码

23. 实现跨域的常见方式

jsonp 和 CORS 
jsonp 运用 script可以绕过跨域限制 服务器可以动态拼接数据返回
CORS  运用 服务器设置http header 来实现 
nginx 反向代理可以解决跨域问题 
node 做中间层也可以解决跨域问题 
复制代码

24. 如何理解cookie

cookie的作用 是可以给浏览器 发送数据 和 存储数据 
cookie的实际场景应用 一般是用来存储 用户的认证信息
    以用户购买商品为例,整体流程如下:
    监测到浏览器客户端没有标识用户的 cookie,跳转到登陆界面
    用户账号密码登陆,后端验证,成功后,在Set-cookie中设置标识用户的 cookie
    登陆成功,保存用户标识的 cookie购买商品,自动携带用户身份的 cookie
    后端验证无误后,购买成功
    
1. 浏览器端:通过 js 代码来设置,例如 document.cookie = "firstName=dongyuanxin; path=/
2. 服务器端:通过给 Http Response Headers 中的Set-Cookie字段赋值,来设置 cookie。客户端接收到Set-Cookie字段后,将其存储在浏览器中 后端设置cookie 有一个httponly字段 来确保客户端不会修改cookie 

复制代码

25. 如何理解Session

Session也是以key value的方式来存储 
和cookie不同的是 
SessionId 存储在客户端
SessionData 存储在服务端  SessionData中包含 过期时间 和 冗余信息等 

总结:比较 cookie 与 session
    session 传输数据少,数据结构灵活:相较于 cookie 来说,session 存储在服务端,客户端仅保留换取 session 的用户凭证。因此传输数据量小,速度快。session 更安全:检验、生成、验证都是在服务端按照指定规则完成,而 cookie 可能被客户端通过 js 代码篡改。session 的不足:服务器是有状态的。多台后端服务器无法共享 session。解决方法是,专门准备一台 session 服务器,关于 session 的所有操作都交给它来调用。而服务器之间的调用,可以走内网 ip,走 RPC 调用(不走 http)。
复制代码

image.png

26. 如何理解token

这也是我刚接触 token 时候的疑惑,因为 session 对比 cookie 来说,解决了很多问题,所以感觉上 session 已经很完美了。但对于 session 来说,服务器是有状态的。这个事情就很麻烦,尤其是在分布式部署服务的时候,需要共享服务器之间的状态。总不能让用户不停重复登陆吧?虽然专门准备一个服务器用来处理状态是可行的,但是能不能让服务器变成无状态的,还不能像单纯 cookie 那么蹩脚?token 就解决了这个问题。它将状态保存在客户端,并且借助加密算法进行验证保证安全性。
复制代码

image.png

如上图所示,整体流程总结如下:

1.用户尝试登陆
2.登陆成功后,后端依靠加密算法,将凭证生成 token,返回给客户端
3.客户端保存 token,每次发送请求时,携带 token
4.后端再接收到带有 token 的请求时,验证 token 的有效性
复制代码
总结:token 真香token 的优点多多:服务器变成无状态了,实现分布式 web 应用授权可以进行跨域授权,不再局限父子域名token 设计绝对了它本身可以携带更多不敏感数据,例如最常用的 JWT安全性更高,密钥保存在服务器。若密钥被窃取,可以统一重新下发密钥。当然,token 增加了服务器压力(毕竟要加密)。但还是真香
复制代码

27. 如何理解localStorage 和 sessionStorage

localStorage 永久存储数据  除非代码手动删除 
sessionStorage 数据只存储在当前会话中 浏览器关闭则清空数据
而且这些数据不会随着浏览器发送出去
复制代码

28. 从输入url到获取页面 完整的渲染流程

1.查询DNS(域名解析) 获取域名对应的IP地址
2.浏览器和服务器 进行TCP连接 (3次握手)
3.客户端向服务端发送http请求 服务端接受到了请求 返回html
4.客户端拿到了html 通过这个html来渲染页面
复制代码

29.setTimeout 和 setInterval的机制

因为js是单线程的。浏览器遇到etTimeout 和 setInterval会先执行完当前的代码块,在此之前会把定时器推入浏览器的
待执行时间队列里面,等到浏览器执行完当前代码之后会看下事件队列里有没有任务,有的话才执行定时器里的代码
复制代码

30.splice和slice、map和forEach、 filter()、reduce()的区别

 1.slice(start,end):方法可以从已有数组中返回选定的元素,返回一个新数组,
 包含从start到end(不包含该元素)的数组方法
	注意:该方法不会更新原数组,而是返回一个子数组
 2.splice():该方法想或者从数组中添加或删除项目,返回被删除的项目。(该方法会改变原数组)
	splice(index, howmany,item1,...itemx)
		·index参数:必须,整数规定添加或删除的位置,使用负数,从数组尾部规定位置
		·howmany参数:必须,要删除的数量,
		·item1..itemx:可选,向数组添加新项目
3.map():会返回一个全新的数组。使用于改变数据值的时候。会分配内存存储空间数组并返回,forEach()不会返回数据
4.forEach(): 不会返回任何有价值的东西,并且不打算改变数据,单纯的只是想用数据做一些事情,他允许callback更改原始数组的元素
5.reduce(): 方法接收一个函数作为累加器,数组中的每一个值(从左到右)开始缩减,最终计算一个值,不会改变原数组的值
6.filter(): 方法创建一个新数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。它里面通过function去做处理

复制代码

31.TCP的三次握手和四次挥手

三次握手
复制代码

第一次握手:客户端发送一个SYN码给服务器,要求建立数据连接; 第二次握手: 服务器SYN和自己处理一个SYN(标志);叫SYN+ACK(确认包);发送给客户端,可以建立连接 第三次握手: 客户端再次发送ACK向服务器,服务器验证ACK没有问题,则建立起连接

四次挥手
复制代码

第一次挥手: 客户端发送FIN(结束)报文,通知服务器数据已经传输完毕; 第二次挥手: 服务器接收到之后,通知客户端我收到了SYN,发送ACK(确认)给客户端,数据还没有传输完成 第三次挥手: 服务器已经传输完毕,再次发送FIN通知客户端,数据已经传输完毕 第四次挥手: 客户端再次发送ACK,进入TIME_WAIT状态;服务器和客户端关闭连接;

32.DOM diff原理

如果元素类型发生变化,直接替换
如果是文本,则比较文本里面的内容,是否有差异,如果是元素就需要比较当前元素的属性是否相等,会先比较key, 在比较类型 为什么 react中循环 建议不要使用索引 ,如果纯为了展示 那可以使用索引
复制代码

33.移动端的兼容问题

给移动端添加点击事件会有300S的延迟
如果用点击事件,需要引一个fastclick.js文件,解决300s的延迟
一般在移动端用ontouchstart、ontouchmove、ontouchend
移动端点透问题,touchstart 早于 touchend 早于click,click的触发是有延迟的,这个时间大概在300ms左右,也就是说我们tap触发之后蒙层隐藏, 此时 click还没有触发,300ms之后由于蒙层隐藏,我们的click触发到了下面的a链接上
尽量都使用touch事件来替换click事件。例如用touchend事件(推荐)。
用fastclick,github.com/ftlabs/fast…
用preventDefault阻止a标签的click
消除 IE10 里面的那个叉号
input:-ms-clear{display:none;}
设置缓存
手机页面通常在第一次加载后会进行缓存,然后每次刷新会使用缓存而不是去重新向服务器发送请求。如果不希望使用缓存可以设置no-cache。
圆角BUG
某些Android手机圆角失效
background-clip: padding-box;
防止手机中网页放大和缩小
这点是最基本的,做为手机网站开发者来说应该都知道的,就是设置meta中的viewport

设置用户截止缩放,一般写视口的时候就已经写好了。

复制代码

34.箭头函数和普通函数的区别。

箭头函数比普通函数的写法更加简洁
箭头函数没有this 它的this是继承函数上下文所处的this 使用(call apply)方法改变不了this

复制代码

35.数组扁平化并去重

/*编写一个程序,将数组进行扁平化,let b = [[1,2,3],[4,5,6],[[1,2,3,4],8,9]]*/
b = b.flat(Infinity)
b = b.toString().split(',').map(item => Number(item))

/*进行数组去重 和 排序*/
b = [...new Set(b)].sort((a,b) => a - b)

复制代码

36.合并数组

concat 
for循环 
扩展运算符
复制代码

37.手写深拷贝

复制代码

38. 事件绑定 事件冒泡 事件代理

事件绑定 onClick 
事件冒泡 事件会冒泡到父元素上 最后冒泡到body上
事件代理 比如你想绑定一个事件 你通过代理的方式 把这个事件代理到父元素上 然后在父元素上通过event.target来进行判断 最后选择这个事件 
event.preventDefault() 阻止事件的默认行为
event.stopPropagation() 阻止事件冒泡行为 
复制代码

39. 如何判断一个变量是对象还是数组(prototype.toString.call())

千万不要使用typeof来判断对象和数组,因为这种类型都会返回object。
typeOf()是判断基本类型的Boolean,Number,symbol, undefined, String。 对于引用类型:除function,都返回object null返回objectinstanceof() 用来判断A是否是B的实例,instanceof检查的是原型。
toString() 是Object的原型方法,对于 Object 对象,直接调用 toString() 就能返回 [Object Object] 。而对于其他对象,则需要通过 call / apply 来调用才能返回正确的类型信息。
hasOwnProperty()方法返回一个布尔值,指示对象自身属性中是否具有指定的属性,该方法会忽略掉那些从原型链上继承到的属性。
hasOwnProperty()方法返回一个布尔值,指示对象自身属性中是否具有指定的属性,该方法会忽略掉那些从原型链上继承到的属性。
isPropertyOf()方法测试一个对象是否存在另一个对象的原型链上。

复制代码

40. 为什么建立连接是三次握手,而断开连接是四次挥手呢?

建立连接的时候, 服务器在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。
而关闭连接时,服务器收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,而自己也未必全部数据都发送给对方了,所以己方可以立即关闭,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送,从而导致多了一次。
复制代码

41. 什么是简单请求 什么非简单请求?

简单请求 : get post head 请求 
Content-Type为以下几种:
    – text/plain
    – multipart/form-data
    – application/x-www-form-urlencoded
非简单请求: put delete 请求 
有自定义头
post请求 带有json格式 

简单请求和非简单请求的区别是 
    简单请求:先执行后判断是否跨域
    非简单请求,会先发一个命令,检查通过之后才会真正把跨域请求发出去
复制代码

42. 函数防抖和函数节流的具体实现方法

函数防抖
  const debounce = (fuc,delay) => {
    let timer = null 
    return () => {
        if(timer)  {
          clearTimeout(timer)
        }
        timer = setTimeout(() => {
          fuc();
          timer = null 
        }, delay);
    }
}
函数节流 
  const throttle = (fn,delay = 100) => {
    let timer = null 
    return function() {
      if(timer) {
        return 
      }
      timer = setTimeout(() => {
        fn()
        timer = null 
      },100)
    }
  } 
复制代码

43. React fiber是什么

复制代码

44. 关于js浮点数运算

原来,计算机的运算都需要转成二制运算,而二进制和实现位数限制有些数无法有限表示。

计算机里每种数据类型的存储是一个有限宽度,比如 JavaScript 使用 64 位存储数字类型,因此超出的会舍去。舍去的部分就是精度丢失的部分。

知道了浮点数产生的原因了,那么怎么处理这个问题呢?

方法一:指定要保留的小数位数(0.1+0.2).toFixed(1) = 0.3;这个方法toFixed是进行四舍五入的也不是很精准,对于计算金额这种严谨的问题,不推荐使用,而且不同浏览器对toFixed的计算结果也存在差异。

方法二:把需要计算的数字升级(乘以10的n次幂)成计算机能够精确识别的整数,等计算完毕再降级(除以10的n次幂),这是大部分编程语言处理精度差异的通用方法。

复制代码

45. object.assign 是深拷贝还是浅拷贝

Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。

Object.assign()拷贝的是属性值。假如源对象的属性值是一个对象的引用,那么它也只指向那个引用。也就是说,如果对象的属性值为简单类型(如string, number),通过Object.assign({},srcObj);得到的新对象为深拷贝;如果属性值为对象或其它引用类型,那对于这个对象而言其实是浅拷贝的
复制代码

46. 手写深拷贝函数

复制代码

47. 数组slice 和 splice的区别

1.功能区别 ( slice 切片 splice 剪切 )
复制代码

48. 函数声明和函数表达式的区别

函数声明  - 🈶️函数提升的功能
函数表达式 - 没有函数提升的功能
复制代码

48. new Object() 和 Object.create()的区别

复制代码

49. JSON.parse、JSON.stringify()这方法有什么问题

JSON.parse(JSON.stringify(obj))深拷贝的问题

const newState = Object.assign({}, state)和JSON.parse(JSON.stringify(obj))都是可以用来深拷贝 但是也会出现下面的问题
如果obj里面存在时间对象,JSON.parse(JSON.stringify(obj))之后,时间对象变成了字符串。
如果obj里有RegExpError对象,则序列化的结果将只得到空对象。
如果obj里有函数,undefined,则序列化的结果会把函数, undefined丢失。
如果obj里有NaNInfinity和-Infinity,则序列化的结果会变成nullJSON.stringify()只能序列化对象的可枚举的自有属性。如果obj中的对象是有构造函数生成的,
则使用JSON.parse(JSON.stringify(obj))深拷贝后,会丢弃对象的constructor。
如果对象中存在循环引用的情况也无法正确实现深拷贝

复制代码

50. 了解过Map数据结构吗,有什么特性,在具体开发中使用过吗,何时应该使用?

https://zhuanlan.zhihu.com/p/67282360
复制代码

51. es6的模块语法 和 commonjs 的区别

es6 模版语法 是静态引入 编译时引用
commonjs 是动态引入 执行时饮用 
只用es6 才能静态分析 实现treeShaking 
复制代码

52. 如何减少重排和重绘

1.样式集中改变 可以添加一个类,样式都在类中改变

2.可以使用absolute脱离文档流。

3.使用 display:none ,不使用 visibility,也不要改变 它的 z-index

4.能用css3实现的就用css3实现。
复制代码

53. 声明一个对象,属性值改变不了

Object.freeze()
Object.property(obj, key, {})来进行设置writable:false
setter
复制代码

54. 函数声明和变量提升有什么区别

console.log(a);
var  a = 123 

输出值为undefined

fn(2)
function fn(a) {
  console.log(a);
}
输出值为2
复制代码

55. 如何在ES5的环境下实现let和const

1.运用闭包和立即执行函数的方法来实现let 

(function(){var a = 1;console.log(a)})();console.log(a)

2.运用Object.defineProperty的方法来实现const 

var __const = function __const(data, value) {
  window.data = value // 把要定义的data挂载到window下,并赋值value
  Object.defineProperty(window, data, { // 利用Object.defineProperty的能力劫持当前对象,并修改其属性描述符
    enumerable: false,
    configurable: false,
    get: function () {
      return value
    },
    set: function (data) {
      if (data !== value) { // 当要对当前属性进行赋值时,则抛出错误!
        throw new TypeError('Assignment to constant variable.')
      } else {
        return value
      }
    }
  })
}
__const('a', 10)
console.log(a)
delete a
console.log(a)
for (let item in window) { // 因为const定义的属性在global下也是不存在的,所以用到了enumerable: false来模拟这一功能
  if (item === 'a') { // 因为不可枚举,所以不执行
    console.log(window[item])
  }
}
a = 20 // 报错

3.运用Object.freeze的方法来实现const

var f = Object.freeze({'name':'admin'});
f.name = 'hello'; // 严格模式下是会报错的
f.name; // 打印出admin ,值没有被改变

复制代码

56. 如何在ES5的环境下实现let和const

> 原型链继承 核心: 将父类的实例作为子类的原型

> 构造继承 核心:使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类

> 实例继承 核心:为父类实例添加新特性,作为子类实例返回

> 拷贝继承

> 组合继承 核心:通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现 函数复用

> 寄生组合继承 核心:通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实 例方法/属性,避免的组合继承的缺点

复制代码

57. prefetch、preload 区别

那么 `Prefetch``Preload` 有什么区别呢?
具体来讲,`Preload` 来告诉浏览器预先请求当前页需要的资源,从而提高这些资源的请求优先级。比如,对于那些本来请求优先级较低的关键请求,我们可以通过设置 `Preload` 来提升这些请求的优先级。
`Prefetch` 来告诉浏览器用户将来可能在其他页面(非本页面)可能使用到的资源,那么浏览器会在空闲时,就去预先加载这些资源放在 `http` 缓存内,最常见的 `dns-prefetch`。比如,当我们在浏览A页面,如果会通过A页面中的链接跳转到B页面,而B页面中我们有些资源希望尽早提前加载,那么我们就可以在A页面里添加这些资源 `Prefetch` ,那么当浏览器空闲时,就会去加载这些资源。
所以,对于那些可能在当前页面使用到的资源可以利用 `Preload`,而对一些可能在将来的某些页面中被使用的资源可以利用 `Prefetch`。如果从加载优先级上看,`Preload` 会提升请求优先级;而Prefetch会把资源的优先级放在最低,当浏览器空闲时才去预加载。

链接地址 - https://www.jianshu.com/p/59d800532b2a

复制代码

58. js 垃圾回收 原理

基本的垃圾回收算法称为 **“标记-清除”** ,定期执行以下“垃圾回收”步骤:

-   垃圾回收器获取根并 **“标记”** (记住)它们。
-   然后它访问并“标记”所有来自它们的引用。
-   然后它访问标记的对象并标记它们的引用。所有被访问的对象都被记住,以便以后不再访问同一个对象两次。
-   以此类推,直到有未访问的引用(可以从根访问)为止。
-   除标记的对象外,所有对象都被删除。
复制代码

59. apply,call,bind三者的区别

-   三者都可以改变函数的this对象指向。
-   三者第一个参数都是this要指向的对象,如果如果没有这个参数或参数为undefinednull,则默认指向全局window。
-   三者都可以传参,但是apply是数组,而call是参数列表,且apply和call是一次性传入参数,而bind可以分为多次传入。
-   bind 是返回绑定this之后的函数,便于稍后调用;apply 、call 则是立即执行 。
复制代码

60. 如何实现图片懒加载如何实现

`<img>`图片的`src`实际上是放在`data-src`属性上的,当元素处于可视范围内的时候,就把`data-src`赋值给`src`属性,完成图片加载

在懒加载的实现中,有两个关键的数值:一个是**当前可视区域的高度**,另一个是**元素距离可视区域顶部的高度**。

参考链接:https://segmentfault.com/a/1190000024547276
复制代码

61. const 声明对象或者数组可以改变吗

因为对象和数组是引用类型,这就意味着,const仅保证指针不发生改变,修改数组的值不会改变对象的指针,所以是被允许的。也就是说const定义的引用类型只要指针不发生改变,其他的不论如何改变都是允许的.
复制代码

62. img中 src图片转换成base64的 优点和缺点


把图像文件的内容直接写在了HTML 文件中

优点: 节省了一个HTTP 请求
缺点: 浏览器不会缓存这种图像
复制代码

4. React

1. vdom是什么

1.用js模拟dom结构 
2.新旧DOM结构进行对比,得出最小更新范围,最后更新dom
3.数据驱动视图的模式下,有效控制DOM操作
复制代码

2. react中的keys

帮组我们跟踪哪些项目已更改、添加、从列表中删除,key是独一无二的,可以让我们高效的去定位元素,并且操作它
复制代码

3. React子组件向父组件传值

父组件通过props 给子组件传递数据,子组件则是通过调用父组件传给它的函数给父组件传递数据。
复制代码

4. 为什么虚拟DOM会提高性能 www.zhihu.com/question/29…

虚拟DOM相当于在js和真实dom中间加了一个缓存,利用dom diff算法避免了没有必要的dom操作,从而提高性能
具体实现步骤:
	·用JavaScript对象结构表示DOM树的结构;然后用这个树构建一个真正的DOM树,插到文档中
        ·当状态变更的时候,重新构造一棵树的对象树,然后用新的树和旧的树进行对比,记录两棵树差异
	·把2所记录的差异应用到步骤1所构建的真正的DOM树上,试图就更新了。

复制代码

5. diff算法

1. 判断是否sameVnode(就是看key 和 tag 是否相同)
2. 是的话,patchVnode,进一步比较;否,直接替换成新的,没有比较的价值
3. patchVnode:
1)只是文本不一样,修改文本
2)旧的有子节点,新的没有子节点,删除子节点
3)新的没有子节点,旧的有子节点,新增子节点
4)新的旧的都有子节点,且子节点不相同,updateChildren
复制代码

6. 如何理解MVVM


传统组件,只是静态渲染,更新还要依赖于操作DOM。

数据驱动视图 - Vue MVVM

代码中的MVVM:

M:对应的是 data () {return {}}

V:template模板

VM:视图与数据的连接层;视图的点击事件通过VM来操作数据;反之,VM也可以通过改变数据来修改视图。
复制代码

7. redux中的reducer(纯函数)

Redux数据流里,reduces其实是根据之前的状态(previous state)和现有的action(current action)
更新state(这个state可以理解为上下累加器的结果)
每次redux reducer被执行时,state和action被传入,这个state根据action进行累加或者是'自身消减'(reduce),
进而返回最新的state,这也就是典型reduce函数的用法:state ->  action ->  state
复制代码

8. react的refs

复制代码

9. react中的组件传值

通过props传值 
React.createContext
redux 
ref 
发布订阅的方式
复制代码

10. useEffect和useLayoutEffect的区别

useEffect

基本上90%的情况下,都应该用这个,这个是在render结束后,你的callback函数执行,但是不会block browser painting,算是某种异步的方式吧,但是classcomponentDidMountcomponentDidUpdate是同步的,在render结束后就运行,useEffect在大部分场景下都比class的方式性能更好.

useLayoutEffect

这个是用在处理DOM的时候,当你的useEffect里面的操作需要处理DOM,并且会改变页面的样式,就需要用这个,否则可能会出现出现闪屏问题, useLayoutEffect里面的callback函数会在DOM更新完成后立即执行,但是会在浏览器进行任何绘制之前运行完成,阻塞了浏览器的绘制.

复制代码

11. 说一下React.createElement 和 React.cloneElement的使用

createElement 和 cloneElement都能够生成可以直接在jsx页面组件中使用的标签语言,但是在生成的过程中是存在细微差别的

`
React.createElement(
  type,
  [props],
  [...children]
)
`

React.createElement():JSX 语法就是用 React.createElement()来构建 React 元素的。它接受三个参数,第一个参数type可以是一个标签名。如 div、span,或者 React 组件。第二个参数props为传入的属性。第三个以及之后的参数children,皆作为组件的子组件。

`
React.cloneElement(
  element,
  [props],
  [...children]
)
`
React.cloneElement()与 React.createElement()相似,不同的是它传入的第一个参数element是一个 React 元素,而不是标签名或组件。新添加的属性会并入原有的属性,传入到返回的新元素中,而旧的子元素将被替换。将保留原始元素的键和引用。

如下,使用cloneElement进行创建jsx元素,在这里我们将createElement创建的element对应的 React 元素做为基点,然后进行克隆,在克隆的过程中,进行添加id='2'属性,同时将子标签进行修改

复制代码

12. React组件封装时,如何进行渲染的优化,减少re-render?

一、react class 组件
    1、PureComponentshouldComponentUpdate
二、react hook 组件(函数组件)
    1、多挖掘能使用useRef的地方
    2、正确使用useEffect的第二个参数
    3、使用React.memo来控制整个函数组件的渲染时机
    4、使用 useMemo() 进行细粒度性能优化
    5、useCallback
    6、合理拆分组件
三、其他非re-render的性能优化点
    1、遍历生成的列表组件需要配置唯一的key
    2、路由懒加载
    3、虚拟列表
    4、把首屏渲染loading提前,避免网速慢的时候长时间白屏
    5、保持稳定的DOM结构有助于性能的提升
    6、不在render中处理数据
    7、不必要的标签,使用React.Fragment
    8、避免更改你正用于 propsstate 的值
复制代码

13. react和vue的区别

   =>  相同点:
	1.数据驱动页面,提供响应式的试图组件
	2.都有virtual DOM,组件化的开发,通过props参数进行父子之间组件传递数据,都实现了webComponents规范
	3.数据流动单向,都支持服务器的渲染SSR
	4.都有支持native的方法,react有React native, vue有wexx
=>  不同点:
	1.数据绑定:Vue实现了双向的数据绑定,react数据流动是单向的
	2.数据渲染:大规模的数据渲染,react更快
	3.使用场景:React配合Redux架构适合大规模多人协作复杂项目,Vue适合小快的项目
	4.开发风格:react推荐做法jsx + inline style把html和css都写在js了
		    vue是采用webpack + vue-loader单文件组件格式,html, js, css同一个文件
复制代码

14. class组件有哪些问题

复制代码

1、大型组件难拆分和重构,很难测试(即class不易拆分) 2、相同业务逻辑,分散到各个方法中,逻辑混乱 3、复用逻辑变得复杂,如Mixin,HOC,RenderProp

复制代码

15. react同构渲染是什么

复制代码

16. 手写redux源码

function createStore(params) {
  let state;
  let listeners = [];

  function subscribe(callback) {
    listeners.push(callback)
  }

  function dispath(action) {
    state = reducer(state,action)
    for(let i = 0; i < listeners.length; i++) {
      listeners[i]()
    }
  }

  function getState() {
    return state 
  }

  let store = {
    subscribe,
    dispath,
    getState
  }

  return store
}

引用文章: https://juejin.cn/post/6845166891682512909
复制代码

17. 手写redux源码

function createStore(params) {
  let state;
  let listeners = [];

  function subscribe(callback) {
    listeners.push(callback)
  }

  function dispath(action) {
    state = reducer(state,action)
    for(let i = 0; i < listeners.length; i++) {
      listeners[i]()
    }
  }

  function getState() {
    return state 
  }

  let store = {
    subscribe,
    dispath,
    getState
  }

  return store
}

引用文章: https://juejin.cn/post/6845166891682512909
复制代码

18. 用hook来实现debounce

复制代码

19. hook组件的好处

 1、写法更加的简洁

 2、业务代码更加聚合

 3、逻辑复用方便

复制代码

5. git

1. git add 和 git commit 有什么区别

git add和git commit的区别就在于:
git add把文件添加进去,实际上就是把文件修改添加到暂存区;
git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。

复制代码

6. webpack

1. webpack优化构建速度

1.优化babel-loader 
2.ignorePlugin
3.noParse 
4.happyPack 多进程打包
5.热更新
6.ParalleUglifyPlugin
7.sourceMap 修改成 eval

不用于生产环境
1.自动刷新
2.热更新
3.DllPlugin
复制代码

2. webpack优化产出代码


1.小图片base64编码(对图片使url-loader配置options.limit)
2.bundle加hash值([name].[contentHash:8].js)
3.懒加载()=>import('')
4.提取公共代码splitChunks:公共代码和三方代码
5.IgnorePlugin:忽略文件不引入打包
6.用cdn加速:在output中加publicPath在url-loader中的options中也加入publicPath
7.使用production和Scope Hosting

复制代码

3. webpack如何实现treeshaking

-   `ES6 Module`引入进行静态分析,故而编译的时候正确判断到底加载了那些模块
-   静态分析程序流,判断那些模块和变量未被使用或者引用,进而删除对应代码

webpack对代码进行标记,把import & export标记为3类:

    - 所有import标记为`/* harmony import */`

    - 被使用过的export标记为`/harmony export([type])/`,其中[type]和webpack内部有关,可能是binding,immutable等;

    - 没有被使用的export标记为`/* unused harmony export [FuncName] */`,其中[FuncName]为export的方法名,之后使用Uglifyjs(或者其他类似的工具)进行代码精简,把没用的都删除。
    
    https://segmentfault.com/a/1190000038962700
    https://segmentfault.com/a/1190000022194321
    
复制代码

4. 自己实现loader 和 plugin

参考链接 : https://blog.csdn.net/weixin_43459866/article/details/109085869
复制代码

7. 网络

1. http和https的区别

HTTP:是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少。

  HTTPS:是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。

  HTTPS协议的主要作用可以分为两种:一种是建立一个信息安全通道,来保证数据传输的安全;另一种就是确认网站的真实性。
复制代码

2. http1.0和http2.0的区别

1.  http1的解析是基于文本协议的各式解析,而http2.0的协议解析是二进制格式,更加的强大
2.  多路复用(Mutiplexing) : 一个连接上可以有多个request,且可以随机的混在一起,每个不同的request都有对应的id,服务端可以通过request_id来辨别,大大加快了传输速率
3.  header压缩: http1.x中的header需要携带大量信息.而且每次都要重复发送.http2.0使用encode来减少传输的header大小.而且客户端和服务端可以各自缓存(cache)一份header filed表,避免了header的重复传输,还可以减少传输的大小.
4.  服务端推送(server push): 可以通过解析html中的依赖,只能的返回所需的其他文件(css或者js等),而不用再发起一次请求.
复制代码

8. 手写代码题

1. 实现如下 sum 函数: sum(1)(2)(3)() => 6

const sum = (num) => {
  let a = sum 
  return  (numb) => {
    if(numb) {
      return sum(numb + a)
    } else {
      return a
    }
  }
}
复制代码

2. 实现发布订阅模式

class EventEmitter {
  constructor() {
      // 维护事件及监听者
      this.listeners = {}
  }
  /**
   * 注册事件监听者
   * @param {String} type 事件类型
   * @param {Function} cb 回调函数
   */
  on(type, cb) {
      if (!this.listeners[type]) {
          this.listeners[type] = []
      }
      this.listeners[type].push(cb)
  }
  /**
   * 发布事件
   * @param {String} type 事件类型
   * @param  {...any} args 参数列表,把emit传递的参数赋给回调函数
   */
  emit(type, ...args) {
      console.log(this.listeners,'listeners')
      if (this.listeners[type]) {
          this.listeners[type].forEach(cb => {
              cb(...args)
          })
      }
  }
  /**
   * 移除某个事件的一个监听者
   * @param {String} type 事件类型
   * @param {Function} cb 回调函数
   */
  off(type, cb) {
      if (this.listeners[type]) {
          const targetIndex = this.listeners[type].findIndex(item => item === cb)
          if (targetIndex !== -1) {
              this.listeners[type].splice(targetIndex, 1)
          }
          if (this.listeners[type].length === 0) {
              delete this.listeners[type]
          }
      }
  }
  /**
   * 移除某个事件的所有监听者
   * @param {String} type 事件类型
   */
  offAll(type) {
      if (this.listeners[type]) {
          delete this.listeners[type]
      }
  }
}
复制代码

9. 性能优化

1. 前端性能优化有哪些方式

让渲染更快
1. CSS放在head中,JS放在body最下面
2. 尽早开始执行JS,用DOMContentLoaded触发
3. 懒加载(图片懒加载,上滑加载更多)
4. 对DOM查询进行缓存
5. 频繁DOM操作,合并到一起插入DOM结构
6. 节流throttle 防抖debounce (让渲染更加流畅)

让加载更快
1. 减少资源体积:压缩代码(使用打包工具webpack),压缩图片
2. 减少访问次数: 合并代码(使用webpack),雪碧图,SSR服务器端渲染,缓存
3. 使用更快的网络:CDN

复制代码

(ps: 慢慢更新 每天10道面试题)

分类:
前端
标签: