前言
最近一直在忙着找工作,想找一家技术OK,氛围OK的公司,大部分时间可能确实都在路上。确实没有时间去做一些技术沉淀和对新技术的学习。在这里记录一下最近遇到的问题,有兴趣的小伙伴可以根据这些巩固下自己的基础。愿所有的小伙伴都可以在金三银色吹火箭,拧螺丝。
CSS部分
BFC
BFC是CSS布局的一个概念,是一个环境,里面的元素不会影响外卖的元素
flex弹性布局
性盒子是一种用于按行或按列布局元素的一维布局方法,元素可以膨胀以填充额外的空间,收缩以适应更小的空间,适用于任何元素上,如果一个元素使用了flex弹性布局(以下都会简称为:flex布局),则会在内部形成BFC
常用属性
- display:flex 开启弹性布局
- align-items: center 文本居中
- justify-content: space-between 左右固定,中间自适应
- justify-content: end 盒子在右部
- flx-wrap: wrap 允许换行
- flex-flow:column 改变排列方向
对媒体查询的理解
媒体查询由⼀个可选的媒体类型和零个或多个使⽤媒体功能的限制了样式表范围的表达式组成,例如宽度、⾼度和颜⾊。媒体查询,添加⾃CSS3,允许内容的呈现针对⼀个特定范围的输出设备⽽进⾏裁剪,⽽不必改变内容本身,适合web⽹⻚应对不同型号的设备⽽做出对应的响应适配。
简单来说,就是根据不同设备,动态的改变字体的大小以及其他的样式,保证用户的体验。同时,重置浏览器也会根据设备的类型和屏幕的高度,重新渲染页面。
JS部分
JS的数据类型有哪些,有什么区别
基本数据类型(原始数据类型)
- string
- number
- null
- undefined
- boolean
ES6 新增
- symbol
ES10 新增
- biglnt
引用数据类型
- object
- fn
- Array
区别
基本数据类型存储在栈中,占用体积小,大小固定,频繁被使用
引用数据类型储存在堆中,占用空间大,大小不固定,如果引用数据类型储存在栈中,将会出现性能问题。
进阶思考
ES6 新增的symbol 类型有什么用,为什么要新增symbol类型?
答:使用symbol类型可以很好地解决用户数据和程序数据之间的命名冲突。例如,我们在全局声明了一个object,可能会同事存在两个js文件,向全局的object中去添加属性,这个时候,就会出现键相同的情况,如果是symbol类型,可以避免掉这个问题,同事symbol类型更加适用于私有对象的私有属性。
Js检验值的类型有哪些方法,有什么不同
-
typeof
-
instanceof
-
constructor
-
Object.prototype.toString.call()
typeof 方式
typeof
只能用于检验基本数据类型,对于引用数据类型始终返回值是object
,同时typeof(null)也会是object
思考:为什么typeof(null) 会返回object
答:在早期的JS底层,对象都是以0开头的,而null
的二进制正好是000,所以就会造成这个bug
instanceof 方式
instanceof
的返回值是布尔值,instanceof
只能正确判断引用数据类型,不能正确的判断基本数据类型
思考:为什么instanceof
无法判断基本数据类型
答:instanceof
的判断一个对象是否在其原型链原型构造函数的属性,基本数据类型是没有原型链的,所以不能正确的判断。正因为instanceof
的判断机制,所以使用instanceof
判断引用数据类型才有意义
constructor 方式
可以判断JS的基本数据类型和引用数据类型,但是有一个致命的缺陷,使用constructor
判断null或者undefined 会导致代码报错,会直接导致代码无法执行。
Object.prototype.toString.call() 方式
使用对象上的原型方法(toString())方法进行数据类型判断,可以正确的判断基本数据类型和引用数据类型。
null 和 undefined 的区别
undefined
的含义是未定义,通常用于基本数据类型的初始值
null
的含义是空对象,通常用于object的初始值
浮点数精度问题,你有遇到过吗?是如何解决的?
浮点数精度问题是由于计算机是通过二进制的方式储存数据的,对于JS来说,是变量初始十进制,再转化为二进制,再进行加减乘数预算,最后再转化为十进制。对于二进制来说,部分整数其实是无限不循环小数,所以就会导致浮点数精度问题的出现。
解决方式
:
-
toFixed() 方式
-
引入成熟的第三方库:
big.js
等
== 与 === 有什么区别?
== 把比较的两个值转换成相同的数据类型,在进行比较值。
=== 对比较的两个值 进行类型和值得校验。校验相对来说更严谨
let const var 有什么区别
-
块级作用域
:let const 具有块级作用域。var不具有块级作用域 -
变量提升
: var 具有变量提升的特性,可以先使用后声明,const let 不具有变量提升的特性 -
重复声明
:var可以重复声明一个变量,后声明的会覆盖之前声明的变量。 -
初始值
var let 声明的变量可以不具备初始值,但是const声明的变量必须具备初始值 -
暂时性死区
一个变量被声明之前是不可以使用的,在语法上被称为暂时性死区,但是var是可以的
new 一个箭头函数,都会发生什么
-
创建对象
-
将作用域复制给这个对象
-
改变创建对象的this指向
-
返回新的对象
箭头函数和普通函数的区别
-
箭头函数没有自己的this,如果在箭头函数中使用this,会指向上层作用域中this的指向
-
箭头函数没有自己的原型对象
-
箭头函数的写法更简洁
-
箭头函数没有自己的
arguments
扩展用算符平常你用吗?
扩展运算符是ES6新增的语法特性,我们经常会使用扩展运算符,合并对象,合并数组,也会根据使用场景,去通过扩展运算符,实现深拷贝一个对象,或者深拷贝一个数组
深拷贝和浅拷贝有什么区别?
深拷贝是在内存中去额外开辟了一个堆,存放新的数据,改变新数据是不会对原本的数据造成影响的。
浅拷贝仅仅是拷贝了原数据的储存地址,改变数据后,原数据也会受到影响。
可以说一下你对解构的理解吗
解构是ES6新增的语法,我们通常是使用解构从对象中解构出一个变量,如果这个变量在对象中不存在,会返回一个undefined,如果存在将会返回正确的值
解构其实还可以用于数组的结构,例如React 16.8 新推出的hook特性,如果是一个数组使用解构的话,是不局限于变量名,是根据索引进行解构的。
说一下数组的常用方法
-
pop()
删除最后一项 -
map()
循环数组,具有返回值, 不会对原数组造成影响 -
filter()
筛选数组,具有返回值, 不会对原数组造成影响 -
shift()
删除最后一项 -
unshift()
删除第一项 -
forEach
循环数组,对原数组会造成影响 -
splice
切割数组
可以说下你对forEath 和 map 的理解吗
forEach的循环是不可以打断的,底层是会创建很多Promise的进行循环,如果要强制打断的话,可以使用try catch 去中断循环,如果做一些修改数组的操作,将会改变原数组
map的循环是不会对原数组造成影响的。map的底层其实是嵌套的for循环。
其实使用forEath和map,主要是根据场景进行使用的。
说下你对Promise的理解,Promise与 async await的区别
Promise 是JS对异步的一个解决方式,可以通过.then的方式去获取执行成功的结果,也可以通过rejected去捕获错误。
Promise.all() 会等所有的异步执行结束后才会返回
Promise.race() 一个执行完毕机会返回结果
Promise 和 async await 都是JS对异步的解决方案,对于Promise来说,我们如果在一个逻辑里面频繁的处理异步现成,可能会导致回调地狱的出现。而且Promise的写法也不够简洁。async await 对于我们来说,在代码方法,是不会造成回调地狱的,而且代码会更简洁。同时 async await 可以通过try catch捕获错误。
可以说下你对for of 和for in 的理解吗
for of 是ES6新增的一个循环的方法,for of 不仅可以循环对象,也可以循环数组。
for in 可以对对象进行遍历。
for of 遍历的是对象的键值,for in 遍历的是对象的键名。
数组去重你通常用什么方法,ES6 Set方式后的数组可以使用forEach吗?
数组在ES6之前,通常是对数组进行一个循环,去除相同的元素。
ES6新推出了Set方式,我们可以通过Set 方式去达到一个去重的目的。但是Set以后返回的是一个Set对象,这个Set对象可以使用forEach方法,但是不可以使用map方法,如果要使用map方法,我们需要通过Array.from(arr)
去将其转化成一个数组
说一下你对原型链的理解
原型链基本分为三个部分
-
构造函数
-
实例
-
原型对象
构造函数new 出来一个实例,这个实例的proto指向了原型对象,构造函数的prototype指向了原型对象,原型对象通过constructor指向构造函数。
每个实例都可以通过proto去向上寻找自己的原型对象,直到找到null 原型链结束
说一下什么是闭包
闭包是指有权访问另一个函数作用域中的变量的函数
闭包可能会导致内存泄漏,循环调用的变量并不能被浏览器的GC算法所识别并回收,需要开发者手动将这个变量设置为null,才可以进行内存释放。
call() apply() bind() 有什么区别
call() apply() bind() 都可以改变this的指向,但是call() apply() 会立即执行。
call()的入参方式是单个
apply()的入参方式是数组
网络协议部分
http https 有什么区别
http 是明文传输,没有安全保证,对服务端和客户端来说都无法验明双方身份
https 使用了ssl加密方式,服务端和服务端可以验明双方的身份,安全有了一定的保障。但是需要解密和加密,对性能会造成一定的影响。
使用https协议的话对技术有一定的要求,一般的个人网站是无法满足这个技术的。
http端口号是80 ,https端口号是443。
http http1.1 http2 有什么区别
http1.1 增加了管道化运输,请求不需要再按照队列的形式发送,可以一起发送,提高了性能。增加了缓存机制,可以通过对请求的判断,实现强缓存或者协商缓存。加入了长链接机制,对于http来说,每次发送请求到获取数据的过程中会简历连接,但是在获取数据后就会断开连接,加入了keep-alive机制,保证了服务端和客户端的一个长连接,对服务端和客户端的交互进行了优化。
http2 是一款二进制协议,主要是增加了头部压缩,多路复用,
三次握手,四次挥手。为什么是三次握手,而不是二次呢?可以是四次吗?
三次握手
客户端与服务器建立连接的过程
-
客户端主动发起请求,发送SYN,将自己变为SYN-SENT, 发送seq = x
-
服务端收到客户的请求,返回seq = y 服务端的状态变为SYN – REVD
-
客户端收到返回值,进入ESTABLISHED状态,完成连接
四次挥手
-
客户端发FIN报文,将seq = x 发送至服务端,进入FIN-WAIT-1 状态
-
服务端收到报文,发送ACK确认, 客户端收到ACK状态,进入FIN-WAIT-2状态等待
-
服务端端将数据处理完成,将数据发送给客户端
-
客户端收到数据发送ACK 向服务端确认
三次握手的过程其实就是服务端和客户端互相验明身份的过程。二次握手,服务端无法确认客户端的身份。三次即可确认双方的身份,四次就不需要了。
DNS是什么?你了解过DNS吗?
DNS是域名系统,是应用层的一个协议。我们通常是通过DNS去解析域名获取IP,根据IP去向服务端发送数据请求的。
DNS也是一个分布式的数据库,正是因为DNS的缓存机制,我们可以很快地知道域名对应的IP地址,从而更快的获取连接。
你了解nginx吗?我看你简历上自己部署了一个个人博客,你可以说一下你理解的nginx是什么吗?
nginx具有三个特性,正向代理
,反向代理
,负载均衡
。
反向代理
反向代理其实是nginx做得最多的一件事。将请求在内部进行IP转化,发送到对应的服务器上,也可能是同一台服务器,端口号不同。安全性更高,不易被捕获服务器的IP地址。
server {
listen 80;
server_name localhost;
client_max_body_size 1024M;
location / {
proxy_pass http:'代理地址';
proxy_set_header Host $host:$server_port;
}
}
复制代码
负载均衡
负载均衡也是nginx最常用的一个功能,如果请求过多的时候,将不同的请求发送不同的服务器,避免因为服务器处理请求过慢,导致的响应数据的问题。
知道CDN吗?说一下CDN
CDN是构建在现有网络基础之上的智能虚拟网络,依靠部署在各地的边缘服务器,使用户就近获取所需内容
,降低网络拥塞,提高用户访问响应速度和命中率。
浏览器输入一个url会发生什么
-
DNS解析,将域名转化为IP地址
-
进行三次握手,客户端与服务端建立连接。
-
发送Http请求
-
四次挥手, 获取数据
-
解析HTML
-
渲染页面
-
断开连接
React 部分
React是什么,为什么要使用React
React 是JS的一个UI编程库,为开发者提供了一个函数式编程的方式,让开发者使用起来更舒服。React为浏览器的性能提供了一个下限,并且一次学习随处可用
React 在国外的使用率偏高,在国内一些大型企业级应用也会采用React,国内一些中小型的企业级应用则会采用Vue。
可以说一下React的事件机制吗
React的事件机制是一个合成事件。对于浏览器来说,我们在JS代码中,每设置一个监听事件,浏览器都会分出一个浏览器对象进行处理,如果监听事件太多,浏览器则会分出更多的浏览器对象进行监听,对浏览器的性能其实会造成影响,React则是将这个事件通过事件委托的方式,全部挂载到父元素身上,通过父元素去触发事件。这就是为什么,我们使用输入组件,或者点击组件,要通过e.target去拿到触发源的原因
为什么要使用VDOM,VDOM的性能一定比DOM好吗?
这个其实要区分场景,例如说我们只是更改一个标签的本文,我们使用VDOM操作其实性能是不比直接操作DOM好的,因为中间多了一层了VDOM的转化,但是为什么我们要使用VDOM,因为VDOM将浏览器的运算都集中到了JS中,浏览器进行计算是比较慢的。其实也就是VDOM为我们提供了一个性能的下限
说一下常用的Hook
useState,useEffect,useMeno,
useEffect 是如何模拟生命周期的
-
第二个参数传空数组
componentDidMount
-
第二个参数传递依赖项
componentDidUpdata
-
在useEffect return一个方法
componentWillUnmount
说一下React Hook 你工作中遇到的坑
主要就是通过useState更改值,但是拿不到最新的值的问题,通常使用useRef进行解决
你知道JSX吗?
JSX其实就是我们现在再写React 文件时,在页面上写的HTML结构,其实这种结构,最后都会通过React.createElement方法转化为Babel结构,第一个参数是标签的类别,第二个参数是组件的Props,第三个参数是里面的子节点
读过React 源码吗,可以说下React的更新极致吗
说一下React在循环数组的时候建议不要用index
作为key
。
数组发生改变,索引也就会发生改变,所以索引作为key,React内部进行Diff比对的时候,复杂度会升高。为什么React建议使用唯一值的key
呢,React diff 会通过这些被标记的元素,进行一系列的操作,从而保证不必要元素的渲染,提高性能。key 需要保证在同级元素中具有唯一性
虚拟DOM 相对于真实DOM的 优势
对于一些场景来说,虚拟DOM的效率不一定会比真实DOM高,比如修改一个按钮的文案,或者是初次渲染,因为React 多了虚拟DOM这一层级的操作,效率也会比真实DOM慢,但是虚拟DOM是提供了性能的下限,保证了页面更新渲染时的性能。虚拟DOM的优势其实在于,提供了一种函数式UI变成方式的同时,还能保证不错的效率
后记
如果有公司愿意给我一个机会,可以加一下老弟的微信,我现在在做的这一套Schema表单,和一体化表格,可以形成一套规范。同时也会减少百分之40的开发时间,提升效率。谢谢各位大佬