前端面试基础题汇总
- HTML5基础
- css3基础
- JavaScript基础
-
-
- 闭包
- typescript(ts)
- 前端优化
- 内存泄漏和内存溢出
- websocket和HTTP
- ES6新特性
- 普通函数和箭头函数
- 同源策略
- promise
- 防抖和节流
- 原型和原型链
- js运行机制
- 开发环境、测试环境、生产环境
- addEventListener(event,function,useCapture)
- js的异步操作有哪些
- 错误类型 - 常见4种(引用,语法,范围,类型)
- es5-严格模式
- 事件绑定,侦听,监听
- 事件委托机制
- 调用new操作符
- ajax的概念和特点
- ajax的优缺点
- Es6 module和commonjs的区别
- 解析一个完整的URL
- http缓存机制
- 什么是immutable, 为什么要使用它
- js延迟加载的方式
- js的几种模块规范
- forEach和map区别
- 修改URL
-
- react基础
-
-
- react新特性
- react路由鉴权
- react优缺点
- Redux工作流程
- react-redux
- 容器组件和UI组件的区别
- Redux遵循的三个原则
- redux组成
- redux的reducer为何要使用纯函数
- react实现组件复用逻辑
- redux-thunk和redux-saga
- React hooks
- react函数组件和类组件区别
- 为什么有时连续点击多次setState只有一次生效
- 高阶组件
- react的connect高阶组件实现, 如何在全局中取得store
- react的数据加载
- setState调用后react做了什么工作
- 导致单页面首页白屏的原因
- 受控组件
- 非受控组件
- react的diff算法
- react组件通信
- react的生命周期
- react优化
- react路由模式
- react-router和react-router-dom
- react路由组件
- react-router路由原理
- react原理
- react vs vue
- react渲染 - key
- 什么是jsx
- 单页面和多页面
- 单页面和多页面的区别
-
- vue基础
- 计算机基础
- 项目积累
- webpack
HTML5基础
H5新增内容
- 语义化标签:header、nav、footer、section、article、aside 优点:更好的SEO,更清晰的HTML结构,增强了可读性,便于维护开发
header:定义页面或文章头部,通常包含logo、页面标题等
nav:定义只包含导航链接的章节
section:定义文档中的一个章节/部分
aside:定义和页面内容关联度较低的内容(即使删除,剩下的内容仍然合理)
footer:定义页面或章节的尾部,通常包含版权信息、法律信息和反馈建议等有效链接地址
- 媒体标签:audio、video
- 功能性标签:SVG、canvas
- 定位:Geolocation
- localStorage、sessionStorage
- fetch请求方式
- input新类型:email、URL、date、datetime、number、range、color、tel、search…
- input新属性:placeholder、min/max、list、outline
什么是BFC
- 块级格式化上下文
- 根元素HTML就是一个BFC
- float值不为none
- overflow的值不为visible
- display的值为inline-block/ table-cell/ table-caption/ flex/ inline-flex
- position的值为absolute或fixed
BFC特性
- Box垂直方向的距离由margin决定,属于同一个BFC的两个相邻box的margin会发生重叠
- 计算BFC的高度时,浮动元素也参与计算
- BFC的区域不会与float box发生重叠
- BFC内部的Box会在垂直方向,一个接一个的放置
- 每个元素的margin box的左边会与包含块border box的左边相接触(对于从左到右的格式化,否则相反),即使存在浮动也会如此
- BFC就是页面上的一个独立容器,容器里面的元素不会影响到外面的元素
localStorage和sessionStorage
- localStorage和sessionStorage一样都是用来存储客户端临时信息的对象。
- 他们均只能存储字符串类型的对象(虽然规范中可以存储其他原生类型的对象,但是目前为止没有浏览器对其进行实现)。
- localStorage生命周期是永久,这意味着除非用户显示在浏览器提供的UI上清除localStorage信息,否则这些信息将永远存在。
- sessionStorage生命周期为当前窗口或标签页,一旦窗口或标签页被永久关闭了,那么所有通过sessionStorage存储的数据也就被清空了。
- 不同浏览器无法共享localStorage或sessionStorage中的信息。相同浏览器的不同页面间可以共享相同的 localStorage(页面属于相同域名和端口),但是不同页面或标签页间无法共享sessionStorage的信息。这里需要注意的是,页面及标 签页仅指顶级窗口,如果一个标签页包含多个iframe标签且他们属于同源页面,那么他们之间是可以共享sessionStorage的。
一个小问题:清除图片间隙
- 清除图片左右间距
- 两张图片挨着写(img标签挨在一起)
- 父元素的font-size设置为0
- 给图片设置浮动
- 清除图片上下间距
- 图片设置为display:block
- 给图片设置vertical-align:top/bottom/middle
元素水平垂直居中
- 弹性盒
- 父元素:display:flex;子元素:margin:auto;
- 父元素:display:flex;justify-content:center;align-item:center; - 定位
- 父元素:position:relative;子元素:position:absolute;left:0;right:0;bottom:0;top:0;margin:auto; - 定位+2D变形
- 父元素:position:relative;子元素:position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);
浏览器输入URL后的流程
- 浏览器向 DNS 服务器请求解析该 URL 中的域名所对应的 IP 地址 - 做域名解析
- 解析出 IP 地址后,根据该 IP 地址和默认端口 80,和服务器建立TCP连接 - 发起HTTP请求,建立TCP链接
- 浏览器发出读取文件(URL 中域名后面部分对应的文件)的HTTP 请求,该请求报文作为 TCP 三次握手的第三个报文的数据发送给服务器 - 浏览器发起读取文件请求
- 服务器对浏览器请求作出响应,并把对应的 html 文本发送给浏览器 - 服务器做出回应,返回对应资源(HTML文件)
- 释放TCP链接
- 浏览器解析资源(HTML文件)
重绘和回流
回流:当render tree中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建时,这就称为回流(reflow)。每个页面至少需要一次回流,就是在页面第一次加载的时候,这时候是一定会发生回流的,因为要构建render tree
重绘:浏览器会重新绘制受影响的部分到屏幕中,该过程称之为重绘
当render tree中的一些元素需要更新属性时,而这些属性只是影响元素的外观、风格而不会影响布局的时候,比如background-color,文字颜色、边框颜色等。则就称为重绘。
- 何时发生重绘或回流
- 页面第一次渲染
- 添加或删除可见的DOM元素
- 元素的位置发生变化
- 元素的尺寸发生变化(包括外边距,内边距,边框大小,高度和宽度等)
- 内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代或者字体改变
- 浏览器窗口尺寸的变化(因为回流是根据视口的大小来计算元素的位置和大小的)
- 定位或者浮动,盒模型等
- 获取元素的某些属性 - 减少重绘或回流
- 使用transform做形变和位移替代定位top
- 使用visibility替换display:none, 因为前者只会引起重绘,而后者会引起回流
- 不要使用table布局,可能很小的一个改动会造成整个table的重新布局
- 动画实现的速度选择,动画速度越快,回流次数越多,也可以选择使用requestAnimationFrame
- CSS选择符会从右往左匹配查找,因此要避免层级过多
- 将频繁重绘或回流的节点设置为图层,图层能够阻止该节点渲染行为影响别的节点。比如video标签,浏览器会自动将该节点变为图层
- 避免多次读取某些属性
- 合并多次对DOM和样式的修改,然后一次处理掉
css单位
- em:相对长度单位,相对于当前元素内部的文本尺寸
- rem:css3新增的相对长度单位,相对的是根元素HTML的文本尺寸
- vw:相对视窗宽度的百分比(1vw代表视窗宽度1%)
- vh:相对视窗高度的百分比
- vmax:当前vw和vh中较大的值
- vmin:当前vw和vh中较小的值
css长度单位
- px:常用的绝对长度单位,相对与显示器分辨率而定位的单位,兼容性较好
- 百分比:常用相对长度单位,相对于父元素的尺寸取值
- pt:绝对长度单位 1px = 0.75pt
清除浮动:清除浮动主要是为了解决,父元素因为子级元素浮动引起的内部高度为0的问题
- 添加空盒子,空盒子添加clear:both - 缺点:添加无意义标签元素
- 父元素添加overflow:hidden(触发bfc) - 缺点:内容增多的时候容易造成不会自动换行导致内容被隐藏掉,无法显示要溢出的元素
- 使用伪元素
.clearfix:after{
/*伪元素是行内元素 正常浏览器清除浮动方法*/
content: "";
display: block;
height: 0;
clear:both;
visibility: hidden;
}
.clearfix{
*zoom: 1;/*ie6清除浮动的方式 *号只有IE6-IE7执行,其他浏览器不执行*/
缺点:IE6-7不支持after
- 使用before和after双伪元素清除
.clearfix:after,.clearfix:before{
content: "";
display: table;
}
.clearfix:after{
clear: both;
}
.clearfix{
*zoom: 1;
- 给父元素添加高度
- 给父元素添加浮动
- 给父元素添加display:flow-root;
display:flow-root;是新增的方法,无论是内联还是块级元素,使用后都会变成块级元素,同时,该元素会建立一个新的BFC,并且不会给元素带来任何的副作用,但是有兼容问题
浏览器的渲染原理
- 将HTML文档解析为DOM树
- 将css样式表解析为cssOM(css对象模型规则树)
- 将DOM树和cssOM合并为render tree
- 计算元素位置,给出坐标
- 绘制元素节点到屏幕上
行内元素
- 设置宽高无效
- margin设置仅左右有效,padding设置上下左右都有效
- 不会自动换行
块状元素
- 可以设置宽高
- margin,padding上下左右均有效
- 会自动换行
- 块状元素排列从上至下(未脱离文档流时)
行内块状元素
- 不会自动换行
- 可以设置宽高
- 默认排列从左至右
css选择器
- 通配符
- 元素选择器(标签选择器)
- 分组选择器(群组选择器)
- 类选择器
- id选择器
- 属性选择器([title]/a[href=“www.123.com”])
- 后代选择器(div p span)
- 子元素选择器(h1>strong)只会选择h1下面的strong标签,再往下面一层的strong标签不会被选择
- 相邻兄弟选择器(div+p)选择紧跟在div标签后面的p标签,连续多个p跟在div后面也全部选中,中间隔了一个其他标签,则后面的不再选中
- 兄弟选择器(div+p)选择div元素后面的所有兄弟元素p,是兄弟元素就行
- 伪类选择器
- 锚伪类:
- a:link //未访问的链接
- a:visited //已访问的链接
- a:hover //鼠标移动到链接上
- a:active //选定的链接
div+css 的布局较 table 布局有什么优点
- 改版的时候更加方便,只需要改动css文件即可
- 页面加载速度更快,结构化清晰,页面显示简洁
- 表现与结构相分离
- 易于SEO
浏览器兼容问题
可以分为两个大的方面:
- css兼容
- JavaScript兼容
css兼容主要是一些新的css属性不被支持,有的可以通过添加前缀解决,不能通过前缀解决的可以使用其他的css属性模拟
JavaScript兼容主要是一些新的语法和API,比如es6语法,可以使用babel做转码,转为合适的版本,针对API方面的兼容,需要检测浏览器是否支持相关API,再选择使用
css3基础
CSS3新增内容
- 过渡:transition
- 动画:animation
- 2D3D形变(形状转换)transform translate rotate
- 盒子阴影:box-shadow
- 图片边框:border-image
- 文字换行,超出省略
- rgba色
- 渐变
- filter
- 弹性盒
- 栅格
- 多列
- 盒模型
- 媒体查询
动画和过渡区别
- 动画不需要事件触发,过渡需要,过渡只有开始和结束两个关键帧,动画可以设置多个关键帧
什么是FOUC(无样式内容闪烁)
如果使用import方式来导入css文件,会导致某些页面在windows下的IE出现奇怪的现象,以无样式显示页面内容的瞬间闪烁,就称之为文档样式短暂失效(Flash of Unstyled Content),简称为FOUC。
原因是当css样式表晚于HTML结构加载时,加载到此样式表时,页面将停止之前的渲染,样式表被下载和解析后,重新渲染页面,就出现了短暂的闪屏现象。
解决:使用Link标签,将css样式表放在head中
JavaScript基础
闭包
闭包:通俗来讲我们说函数里面嵌套函数的一种形式,或者说是定义在一个函数内部的函数
一句话来概括闭包是指有权访问另一个函数作用域内部变量的函数
- 闭包的好处/用途
- 希望一个变量可以常驻内存中(延迟变量作用域)
- 避免全局变量的污染
- 私有成员的存在
- 闭包的缺陷
- 变量常驻内存,增加了内存的开销
- 使用不当会造成内存泄漏
typescript(ts)
- 不是一门新语言,是用来规范js的语言,是js的超集,常用在大型项目中,使得代码更规范,维护更加方便
- 不需要去浏览器中浏览效果,就能知道编译错误
- 类型就是最好的注释,看类型我们就知道这个是什么
- 即使ts中有编译报错,tsc依旧可以将其编译成js
- 特点:
- 增加静态检查,增加代码健壮性
- 多人协作,提高生产力,降低维护成本
- interface和type区别
- 是ts中定义类型的两种方式
- 都可以描述一个对象或者函数
- interface只能定义对象类型
- interface能够声明合并,type不行
- type 可以声明基本类型别名,联合类型,元组等类型
typescript官网链接
前端优化
- 减少HTTP请求 - 根据IP建立TCP链接请求数据
- 减少DNS查询 - 域名解析为IP地址 - DNS解析数据会缓存一段时间,因此影响首次解析速度
- 避免页面跳转,客户端收到服务器的跳转回复时,会再次执行页面跳转,跳转次数过多,可能会造成看不到任何页面内容的效果
- 延迟加载
- 避免页面主体布局中使用table
- 减少DOM元素数量
- 根据域名划分下载内容
- 减少iframe数量
- 使用CDN
- 压缩传输文件
- 避免空的图片src
- css样式表放在顶部
- link代替@import
- 避免滤镜
- JavaScript脚本置底
- 使用外部JavaScript和css文件
- 减少DOM操作次数
- 图片懒加载
内存泄漏和内存溢出
- 内存泄漏:指的是部分内存一直被占用而得不到释放
- 引起内存泄漏
- 意外的全局变量引起的内存泄露
- 闭包引起的内存泄露
- 没有清理的DOM元素引用 - 获取了一个DOM元素的引用,然后删除了这个DOM元素,但保留了这个元素的引用
- 被遗忘的定时器或者回调
- 内存溢出:也称为内存越界。数据存储的空间超出了实际分配的内存,典型如栈溢出 - 递归函数
websocket和HTTP
- HTTP:每次HTTP请求都需要做一次tcp链接,只能从客户端发起通信请求,服务端不能主动推送信息
- websocket:是长连接状态,客户端可以向服务端请求数据,服务端也可以向客户端推送数据
ES6新特性
- 暂时性死区:只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”
- let和const
let 、const和var
扫描二维码关注公众号,回复: 12663134 查看本文章
- let和var用来声明变量,const用来声明常量,let和const的区别就在于变量和常量,其他规则一样
- var声明变量具有变量提升,即变量可以在声明之前调用,值为undefined
- let声明变量不在具有变量提升,在声明之前调用会报错
- 暂时性死区:let和const存在暂时性死区,它们具备块级作用域的特点,声明的变量或者常量被绑定在这个区域内,不再受外部的影响
- var允许重复声明同一变量,在同一作用域内,let和const不允许重复声明变量
- var声明的是函数作用域,let声明的是块级作用域,即在两个花括号之间
- let声明的变量不会成为window对象的属性
- 解构赋值:按照一定的规则,从数组或对象中提取值,对变量进行赋值
- 扩展运算符
- 模板字符串
- 字符串的新方法
- string.fromCodePoint() - 从 Unicode 码点返回对应字符
- includes() | startsWith() | endsWith() - 参数字符串是否在原字符串的尾部
- repeat() - 返回一个新字符串,表示将原字符串重复n次
- 数组的新方法
- Array.from() - 用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)
- Array.of() - 用于将一组值,转换为数组
- includes()
- flat() - 扁平化数组
- 对象的扩展 - 属性的简洁表示
- 对象的新方法
- object.is() - 比较两个值是否相等 其运算逻辑与 “===” 基本相似 但是有两个不同 object.is(+0,-0)//false 原生显示true object.is(NaN,NaN) //true 原生显示false
- Object.assign() - 对象的合并 - 可以实现浅拷贝
- Object.keys() - 对象的键名
- Object.values() - 对象的键值
- Object.entries() - 回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组
- 函数的扩展
- 参数默认值
- 箭头函数
- symbol类型
- set和map数据结构
- proxy
- Iterator接口和for…of
- async函数
- promise对象
- class类
普通函数和箭头函数
- 箭头函数是普通函数的简洁表示
- 箭头函数不能作为构造函数使用,也就是不能使用new关键字
- 箭头函数没有原型属性
- 箭头函数不能做generator函数,不能使用yield关键字
- 箭头函数的this会捕获其上下文的this,在定义的时候就决定了
- 箭头函数的this不能被改变(this并不会受到call、bind、apply的影响)
同源策略
- 为什么会产生跨域
- 是因为浏览器的同源策略
- 什么是同源策略
- 同源策略阻止从一个域上加载的脚本获取或操作另一个域上的文档属性
- 哪些方式会产生同源策略
- 端口不同,域名不同,协议不同,域名和域名对应的ip之间
- 解决跨域的方式
- 前端 ->jsonp
- cors方式
- 后端代理
- 反向代理
- h5新增postMessage
- 简述jsonp的特点。
- script标签的src属性获取数据不存在跨域
- 利用callback回调函数传值
- 仅仅支持get方式
promise
- 什么是promise
- Promise 异步编程的一种解决方案,比传统的解决方案(回调函数)更合理和更强大。
- 可以将异步操作队列化,按照期望的顺序执行,返回符合预期的结果
- 可以在对象之间传递和操作promise,帮助我们处理队列
- 代码风格更加容易理解和维护
- Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(resolve已成功)和rejected(已失败).
- 一旦状态设定,就不会再变
- promise原型下面三个常用的方法:
- Promise.prototype.then
- Promise.prototype.catch
- Promise.prototype.finally
- Promise.all():用于将多个 Promise 实例,包装成一个新的 Promise 实例,接受一个数组作为参数,只有数组里面的每个状态都变成resolve,则新的 Promise 实例状态才会变成resolve.
防抖和节流
防抖:短时间内多次触发同一事件,只执行最后一次,或者只执行最开始的一次,中间的不执行
在事件触发时,开始计时,在规定的时间(delay)内,若再次触发事件,将上一次计时(timer)清空,然后重新开始计时。保证只有在规定时间内没有再次触发事件之后,再去执行这个事件
- 场景:面resize事件,页面适配时,根据最终呈现的页面情况进行dom渲染,一般使用防抖,只需判断最后一次的变化情况;search搜索联想,用户在不断输入值时,用防抖来节约请求资源
节流:指定时间间隔内,若事件被多次触发,只会执行一次
在事件触发之后,开始计时,在规定的时间(delay)内,若再次触发事件,不对此事件做任何处理。保证在规定时间内只执行一次事件
- 场景:一般是onrize,onscroll等这些频繁触发的函数,如获取滚动条的位置,然后执行下一步动作;鼠标不断点击触发,mousedown(单位时间内只触发一次);搜索框input事件,例如要支持输入实时搜索可以使用节流方案
总的来说防抖控制的是次数,节流控制的是频率
原型和原型链
- 原型:每一个函数都有一个prototype对象属性,这个属性指向该函数的原型对象;每个对象都会有一个__proto__属性,这个属性指向该对象的原型
- 原型链:实例对象与原型之间的连接,叫做原型链
js运行机制
首先我们需要了解JavaScript的特性就是单线程,单线程简单的说就是同一时间只能做一件事。那么为什么是单线程呢?作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程再某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?
单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。多线程可以将任务放到不同的线程中去处理。CPU的调度单位是线程,它会在不同的线程之间切换,任务是隶属于线程的
于是,JavaScript中所有任务可以分成两种,一种是同步任务,另一种是异步任务。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入“任务队列”的任务,只有“任务队列”通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行
主线程从“任务队列”中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件轮询)
这个任务队列都是已经完成的异步操作
对于异步任务队列来说,又分为宏任务和微任务
宏任务:包括整体代码 script,setTimeout,setIntervcal
微任务:Promise,process.nextTick
执行顺序:进入整体代码后,开始第一次循环。接着执行所有的微任务,然后再次从宏任务开始,找到其中一个任务队列执行完毕,再执行所有的微任务
开发环境、测试环境、生产环境
- 开发环境:专门用于程序员开发的环境,一般打开全部错误报告和测试工具,是最基础的环境
- 测试环境:通常克隆一份生产环境配置,让程序在测试环境工作,是从开发到生产环境的过渡环境,主要测试是否存在bug
- 生产环境:正式对外提供服务的,一般关掉错误报告。真实的环境,提供给用户的环境
addEventListener(event,function,useCapture)
- event:必须。要执行的事件
- function:必须。事件处理函数/事件触发时执行的函数
- useCapture:可选。默认false-事件在冒泡阶段执行。true-事件在捕获阶段执行
js的异步操作有哪些
- 定时器是异步的
- 事件绑定是异步的(事件处理函数)
- ajax通常使用异步(也可以设置为同步)
- 回调函数可以理解为异步
- promise
- generator
- async和await
错误类型 - 常见4种(引用,语法,范围,类型)
- 引用错误:referenceError 所引用的类型不存在 – 变量未声明
- 语法错误:syntaxError 使用的语法有错误 – 关键字写错
- 范围错误:rangeError 使用的值范围有错误 — 栈溢出
- 类型错误:typeError 使用的类型有错误 – 调用的对象不对 – a():a不是一个函数
es5-严格模式
- ES5严格模式的目的.
- 消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为
- 为未来新版本的Javascript做好铺垫。
- 消除代码运行的一些不安全之处,保证代码运行的安全。
- 提高编译器效率,增加运行速度。
- 严格模式下语法和行为改变
- 变量必须声明(变量提升不再存在)
- 禁止使用with语句
- 禁止this关键字指向全局(window)
- 函数参数不能重名
- 禁止八进制表示法 - 017 常规输出15,严格模式下报错
- 不允许对arguments赋值
- 禁止使用arguments.callee/arguments.caller(禁止了使用arguments的方法)
- es5新增的数组的方法
- 位置方法:indexOf/lastIndexOf
- 迭代方法:every/some/filter/map/forEach
- 归并方法:reduce/reduceRight
- 扁平化:flat
事件绑定,侦听,监听
- 普通事件和事件绑定的区别
- 普通事件重复绑定后面的会覆盖前面的,事件绑定可以对同一个事件绑定多个事件处理函数 - 事件绑定标准浏览器和非标准浏览器的区别(四个不一样)
- 参数不一样,标准三个,非标准两个,差最后的一个是否冒泡
- 事件类型不一样,是否有‘on’
- 执行顺序不一样。IE浏览器先执行后面的,标准浏览器按顺序执行
- this指向不一样,标准浏览器事件处理函数里面的this当前的操作的元素,但是非标准浏览器的this指向window
事件委托机制
- 事件委托的概念:利用冒泡原理,将子元素事件委托给父元素
- 事件委托的优缺点:
- 优点:减少事件注册,节约内存,提升性能
- 缺点:所有的事件都用事件委托可能会出现事件误判
调用new操作符
- 创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型
- 属性和方法被加入到 this 引用的对象中
- 并且最后隐式的返回 this (创建也是隐式) -> 创建和返回都是隐式的
ajax的概念和特点
- 异步JavaScript和XML,是指一种交互式网页开发技术
- AJAX 可以使网页实现异步(局部)更新。
- 服务器负担的工作转移到客户端,利用客户端的闲置的资源进行处理,减轻服务器和带宽的负担,节约空间和成本。
ajax的优缺点
- 优点:
- 局部实现无刷新更新数据
- 异步通信服务
- 更好的实现前后端分离
- 前后端负载平衡
- 缺点:
- 无刷新更新数据->对浏览器的back和history机制造成了破坏
- 数据传输的安全问题
- 搜索引擎支持较弱
- 对移动端设备支持不是很好
Es6 module和commonjs的区别
- commonjs建立模块依赖是在运行时,ES6module是在编译时
- 在模块导入方面,CommonJS导入的是值拷贝,ES6 Module导入的是只读的变量映射
- ES6 Module通过其静态特性可以进行编译过程中的优化,并且具备处理循环依赖的能力
解析一个完整的URL
包含如下选项:
* location: {
* href: ‘包含完整的url’,
* origin: ‘包含协议到pathname之前的内容’,
* protocol: ‘url使用的协议,包含末尾的:’,
* host: ‘完整主机名,包含:和端口’,
* hostname: ‘主机名,不包含端口’
* port: ‘端口号’,
* pathname: ‘服务器上访问资源的路径/开头’,
* search: ‘?开头的查询参数’,
* hash: ‘#开头的哈希值’
* }
function parseUrl(url) {
if(typeof window == 'undefined') {
//node环境
const URL = require('url');
return URL.parse(url);
} else {
//浏览器环境
//比较取巧的做法就是利用a标签,当然只用于有dom的执行环境
var link = document.createElement("a");
link.href = url;
return {
href: link.href,
origin: link.origin,
protocol: link.protocol,
host: link.host,
hostname: link.hostname,
port: link.port,
port: link.pathname,
search: link.search,
hash: link.hash
}
}
}
http缓存机制
根据是否需要重新向服务器端发起请求可以分为强缓存和协商缓存两大类
- 强缓存:强缓存与时间期限有关,浏览器会查看缓存中的资源是否过期,过期则重新请求数据,未过期则取得缓存资源做下一步处理
- 协商缓存:会和服务器做交互,取得缓存会先向服务器确认缓存是否可以使用,如果可以,服务器会返回可用信号,如果不可以,则返回新的资源
- 两个缓存机制可以同时存在,且强缓存优先级高于协商缓存,意味着请求资源时会先比较强缓存字段,如果成功则不会再执行协商缓存
什么是immutable, 为什么要使用它
- Immutable Data 就是一旦创建,就不能再被更改的数据。对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象
- Immutable 实现的原理是 Persistent Data Structure (持久化数据结构),也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变
js延迟加载的方式
- 将js脚本放在文档底部,使js脚本尽量最后加载
- 给js脚本添加defer属性,使js脚本与文档解析同步执行,这样可以使页面渲染不被阻塞
- 给js脚本添加async属性,使js脚本异步解析,不阻塞页面渲染
- 动态创建DOM标签的方式,对文档的加载事件进行监听,文档加载完成后动态创建script标签来引入js脚本
js的几种模块规范
- commonJS - Node.js就是使用此规范 - 适用于服务端
- require引入模块,module.exports暴露模块,一个文件就是一个模块
- 模块的调用是同步的
- AMD - 适用于浏览器端 - require.js使用此规范
- define定义模块,require加载模块
- 模块的调用是异步的
- 推崇依赖前置,在定义时就声明依赖模块
- 模块加载完成后执行依赖模块
- CMD - sea.js使用此规范
- define定义模块,require加载模块
- 模块调用是异步的
- 推崇就近依赖,使用时声明模块
- 下载所有依赖模块不执行,遇到require是执行对应依赖
- ES6
- import导入模块,export导出模块
forEach和map区别
他们都是用来遍历数组的,第一个参数都是一个函数,这个函数允许传入三个参数
用法:
- forEach用法:
let result = arr.forEach((item,index,arr)=>{
console.log(item,index,arr);
}) //--item:数组项 index:数组项索引 arr:遍历的数组
- map用法:
let result = arr.map((item,index,arr)=>{
console.log(item,index,arr);
return item*2
})//--item:数组项 index:数组项索引 arr:遍历的数组
区别:
最大的区别就是forEach没有返回值,map有返回值,这个返回值是一个新数组
修改URL
- 我们修改URL后的参数是否会刷新页面:会的
- 那么我们可以用什么方式让它修改了URL但是又不刷新页面:可以用history里面的pushState和replaceState方法
react基础
react新特性
- render方法支持直接返回string,number,boolean,null,portal,以及fragments(带有key属性的数组),这可以在一定程度上减少页面的DOM层级
- setState传入null时不会再触发更新
- fiber算法
react路由鉴权
- 在之前的版本中,React Router 也提供了类似的 onEnter 钩子,但在 React Router 4.0 版本中,取消了这个方法。React Router 4.0 采用了声明式的组件,路由即组件,要实现路由守卫功能,需要我们自己去写
- 可以在路由表里面添加路由权限,路由载入的时候如果对应路由权限不满足,则阻止加载这个路由页面
react优缺点
- 虚拟DOM,提升性能
- 跨浏览器兼容
- 组件化开发,代码重用,可维护
- 函数式编程
- jsx语法,在js中编写DOM
缺点:不适合单独做一个完整的框架,react注重于视图层结构,大型项目的完整架构就需要引入其他相关的东西
Redux工作流程
- 首先,用户发出 Action。然后,Store 自动调用 Reducer,并且传入两个参数:当前 State 和收到的 Action。 Reducer 会返回新的 State 。State 一旦有变化,Store 就会调用监听函数,重新渲染 View。
react-redux
- react-redux将组件分成UI和容器组件,react-redux提供的connect可以将这两种组件连接起来
- redux是独立的应用状态管理工具。它是可以独立于react之外的。如果我们需要在react当中运用它,那么我们需要手动订阅store的状态变化,来对我们的react组件进行更新。react-reudx这个工具,就帮我们实现了这个功能,我们只需对store进行处理,react组件就会有相应的变化
容器组件和UI组件的区别
简述:UI组件负责页面的渲染,容器组件负责页面的逻辑
Redux遵循的三个原则
- 单一数据源
- state只读
- 数据的改变必须要通过纯函数完成
redux组成
- store:用来存储数据和数据管理,更新视图
- actions:发送动作给reducer,reducer接收动作,判断动作类型修改数据,修改事件后,组件重新做redux事件的订阅
- reducer:是一个纯函数,接收旧state和action,根据不同的 Action 做出不同的操作并返回新的 state
redux的reducer为何要使用纯函数
首先我们理解reducer纯函数:传入的参数不得修改,通过外部状态来修改(比如依赖DOM和全局变量);不得调用非纯函数,比如(Date.now();Math.random())
- Redux只通过比较新旧两个对象的存储位置来比较新旧两个对象是否相同(也就是JavaScript的对象浅比较),如果在reducer内部直接修改state对象的旧值,那么新的state和旧的state就指向同一个对象,redux将会认为state没有改变,也就不会触发页面刷新了
- redux的核心是提供可预测化的状态管理,即我们需要无论何时特定的action触发行为保持一致的,如果使用了Date.now()等非纯函数,即使同样的action,对于reducer的处理结果也是不同的,也就不能再保证可预测性了
react实现组件复用逻辑
- 高阶组件
- render props
- 自定义hook
redux-thunk和redux-saga
- redux-thunk:Redux store 仅支持同步数据流。使用 thunk 等中间件可以帮助在 Redux 应用中实现异步性(更多关于redux-thunk)
好处:可以进行前后端数据交互
缺点:将带有数据请求的action和没有带有数据请求的action混在一起了;
缺点解决: 弃用redux-thunk,使用redux-saga
redux-saga可以将异步action和普通action区别开来
- redux-saga:redux-saga是一个用于管理redux应用异步操作的中间件,redux-saga通过创建sagas将所有异步操作逻辑收集在一个地方集中处理,可以用来代替redux-thunk中间件(更多关于redux-saga)
React hooks
hook是React 16.8新增特性
-
基础hook
- useState - 作用相当于类组件的this.state
const [count,setCount] = useState(0) - setCount 用来修改count的值
setCount(1) - count的值被修改为1,但是在修改数组和对象时有所不同
const [obj,setObj] = useState({username:‘King’})
setObj(obj.username = ‘lucy’) - error username并不会被修改
我们可以使用浅克隆或深克隆的方式来修改:
const newObj = {}
newObj.username = ‘lucy’
Object.assign(obj,newObj)- useEffect
功能相当于类组件里面的componentWillUnmount,componentDidMount,componentDidUpdate的组合
useEffect有两个参数,第一个参数是一个回调函数,第二个参数是一个数组,第二个参数为可选参数
useEffect在页面刷新时会执行一次,相当于componentDidMount钩子函数
只有第一个参数时,页面中的useState的数据改变都会执行一次
第一个参数里面返回一个函数时,这个函数里面执行的功能相当于组件被卸载时运行,相当于componentWillUnmount
第二个参数为[] 空数组时,useEffect只会执行一次,相当于componentDidMount
第二个参数为[count]时,将会在count发生改变时执行
第二个参数为[count,value],将会在count和value发生改变时执行- useContext - 作为中间值,进行跨组件传参
-
额外的hook
- useReducer - (功能)
- useCallback - 和useMemo类似,也是用于函数组件优化,效果类似
- useMemo - 用于函数组件优化,可以使得函数状态改变时不会导致全部组件重新渲染
- useCallback和useMemo的一个区别在于前者返回一个函数,后者返回的是memo的值
- useCallback(fn, deps) 相当于 useMemo(() => fn, deps)
- const callbackValue = useCallback(回调,[依赖项]),该回调仅在依赖项发生改变时才会更新 - useRef - 可以命令式的访问子组件,配合ref属性使用,但是ref不能绑定到函数组件上,如果绑定,函数组件需要用forwardRef包裹起来
- useImperativeHandle - 可以在让我们在使用ref属性时把自定义的内容传递给父组件,需要配合forwardRef使用
- useLayoutEffect - 和useEffect一样,区别在于,useLayoutEffect主要是常用于根组件
官方文档表示,平时我们只需要用useEffect即可,如果useEffect出现了问题,再尝试使用useLayoutEffect
- useDebugValue - 显示自定义组件
-
useEffect和useLayoutEffect
- useEffect:大多数情况下,都是用这,在render结束后,它会执行里面的callback,并不会阻止浏览器的渲染,对于class里面的componentDidMount和componentDidUpdate算是同步的,在render结束后就运行,因此useEffect大部分情况下要比class的钩子函数要好
- useLayoutEffect:当你在useEffect里面想要操作DOM,并且会改变样式,就可能需要用这个,否则可能会造成页面闪屏的情况,useLayoutEffect里面的callback会阻塞浏览器的渲染
react函数组件和类组件区别
定义组件有两个要求:
- 组件名称需要大写字母开头
- 组件返回值只能有一个根元素
- 区别
- 性能上函数组件略高于类组件(因为类组件需要做实例化,函数组件可以直接执行函数获取返回结果)
- 函数组件没有this,没有生命周期,没有state
- 类组件有this,有生命周期,有state
为什么有时连续点击多次setState只有一次生效
因为React批处理机制中会对存储的多个setState进行合并
高阶组件
是一个函数,传入一个组件作为参数,对输入组件进行加工,输出一个有特定功能的新组件
高阶组件(high-order component)类似于高阶函数,接收 React 组件作为输入,输出一个新的 React 组件。高阶组件让代码更具有复用性、逻辑性与抽象特征。可以对 render 方法作劫持,也可以控制 props 与 state
- 实现高阶组件的方法有两种:属性代理和反向代理
- 属性代理:通过高阶组件来传递 props,这种方法即为属性代理
- 反向代理(反向继承):高阶组件的返回组件继承于另一个组件,因为被动的继承了另一个组件,所以所有的调用都会反向
react的connect高阶组件实现, 如何在全局中取得store
作用:连接React组件与 Redux store
- connect函数的返回值是一个高阶组件,通过高阶组件来获取store中的数据
- connect底层原理:是闭包
- mapStateFromProps:从countReducer中解构出state数据,用来获取数据,这里可以获取全部的state,我们需要返回对应组件的state来使用
- mapDispatchFromProps:将ActionCreators中的方法绑定到组件上,并且发送action
- connect方法利用了合并分发的原理来帮助我们完成store内容的获取
- 合并: 将store中的所有数据拿到手
- 分发: 将我们UI需要的数据派发出去
- 合并分发 :合并的意思是:(我们项目中)redux的数据是集中在一处的,分发的意思是:给的是所有数据中的分块的数据
react的数据加载
- constructor里面加载:在这里面获取数据的话,如果时间太长,或者出错,组件就渲染不出来,整个页面都没法渲染了,所以我们通常用作组件state初绐化工作,并不是设计来作加载数据的
- componentWillMount:如果使用SSR(服务端渲染),componentWillMount会执行2次,一次在服务端,一次在客户端
目前16版本加入了UNSAFE来标识,这个钩子函数就用的很少了,这个钩子函数可能会执行多次,所以一般也不在这里面做数据请求
- render:出现无限render
- componentDidMount:确保已经render过一次。提醒我们正确地设置初始状态,这样就不会得到导致错误的"undefined"状态
setState调用后react做了什么工作
- React会将当前传入的参数对象与组件当前的状态合并,然后触发调和过程,在调和的过程中,React会以相对高效的方式根据新的状态构建React元素树并且重新渲染整个UI界面
- React得到元素树之后,React会自动计算出新的树与老的树的节点的差异,然后根据差异对界面进行最小化的渲染,在React的差异算法中,React能够精确的知道在哪些位置发生看改变以及应该如何去改变,这样就保证了UI是按需更新的而不是重新渲染整个界面
导致单页面首页白屏的原因
主要有三个:1.网络问题 2.文件大小问题 3.电脑性能问题
对于网络和文件大小问题:主要是合并请求,减少请求和文件的打包压缩等优化,所以要解决白屏时间过长的问题我们还是要从根源上解决,那就是服务器返回来的html只有html骨架,并没有什么实际内容可以显示在浏览器中,我们需要做的就是往html中填充内容,让浏览器在发送请求获取js等文件再到解析js生成页面所需要的html这段时间里有内容可以显示在浏览器中
受控组件
表单元素的value值受到组件的state的控制,我们就把这个表单元素称为受控组件
特殊场景:父组件修改state,子组件渲染,即子组件的值受到父组件的控制
非受控组件
表单元素的value值受到自己的控制
react的diff算法
作用: 计算出Virtual DOM中真 正变化的部分,并只针对该部分进行原生DOM操作,而非重新渲染整个页面
只有在react更新阶段才会使用diff算法
react组件通信
- 父->子组件:父组件定义状态,子组件用属性来接收,父组件更改状态,子组件也会同步更改
- 子->父组件:父组件传递一个方法给子组件,子组件通过this.props接收方法后调用 但是子组件调用方法时注意:onClick = {() => { changeJk( 子组件的状态做参数传给父组件 ) }}
- 跨组件:(组件是深层嵌套的父子组件关系)借助中间组件来实现,react下面的createContext,两个通信组件都需要引入createContext,传输组件用<自定义组件名.Provider value={状态}>来包裹子集组件,接收组件用static contextType = context里面自定义的名字 ,使用时用this.context即可
- 非父子组件:共同的父组件做中介,执行组件通过this.props获取来自父组件的方法,实际上执行的方法是另一个需求组件的方法
- 总述:要改的状态在哪个组件,方法就写在哪个组件
react的生命周期
- 挂载阶段/初始化阶段:
- constructor:
- 1.组件的props赋值给this.props
- 2.定义state
- 3.普通函数绑定this
- componentWillMount:(即将被弃用)
- 1.初始化事件和生命周期
- 2.可以请求数据,也可以修改数据
- render:
- 1.生成vDOM
- 2.解析this.props 和 this.state
- !!Note:不能在这个钩子函数里面使用setState,因为js是单线程的,不能要求它在解析this.state的时候又改变state
- componentDidMount:
- 1.组件挂载结束,可以获取数据和做数据的修改
- 2.真实DOM渲染完成,可以获取真实DOM,操作DOM元素
- constructor:
- 更新阶段:
- componentWillReceiveProps: - 更新props才有这个函数
- 将弃用
- 接收的props改变时触发
- shouldComponentUpdate(nextProps,nextState): - state更新从这里开始
nextProps,nextState表示变化之后的props和state,这个函数应该返回一个布尔值,默认返回true,true表示渲染,false表示不渲染
shouldComponentUpdate(nextProps,nextState){
return nextProps.value != this.props.value //this.props.value表示的是更新前值,nextProps.value表示的是更新后的值,当两个值相等返回false,即props没有更新,页面不必重新渲染,两个值不等时返回true,即props已经更新,页面需要重新渲染
// return nextState.value != this.state.value //!!Note:这里的nextState.value 和 this.state.value是一样的,所以不能像props一样来做判断,要么用其他方法做判断是否更新,要么不做判断
} - componentWillUpdate:
- 数据即将更新前的准备
- 将弃用
- render:
- 数据更新后页面需要再次渲染
- componentDidUpdate:
- 数据完成更新后的阶段
- 可以做dom操作,数据获取,数据修改
- 第三方库实例化
- componentWillReceiveProps: - 更新props才有这个函数
- 卸载阶段:
- componentWillUnmount:
- 组件被卸载时执行
- 用来清除卸载组件时却不会被卸载的实例、事件等
- 清除全局引用
- 清除定时器
- 清除第三方实例
- 清除事件等
- componentWillUnmount:
- 错误捕获阶段:
- componentDidCatch(error,info):
- error:实际的错误信息
- info:错误的位置
- 这个钩子函数放在父组件,当子组件出现错误时这里反映错误
- componentDidCatch(error,info):
react优化
- 组件尽可能进行拆分
- 列表组件优化,添加key属性
- bind函数绑定,this的绑定最优在constructor函数里面做绑定
- 不要滥用props
react路由模式
我们常用的的是BrowserRouter,也就是浏览器的路由方式,另外react还有几种路由方式
- BrowserRouter:浏览器的路由方式,也就是在开发中最常使用的路由方式
- HashRouter:在路径前加入#号成为一个哈希值,Hash模式的好处是,再也不会因为我们刷新而找不到我们的对应路径
- MemoryRouter:不存储history,所有路由过程保存在内存里,不能进行前进后退,因为地址栏没有发生任何变化
- NativeRouter:经常配合ReactNative使用,多用于移动端
- StaticRouter:设置静态路由,需要和后台服务器配合设置,比如设置服务端渲染时使用
react-router和react-router-dom
- react-router:实现了路由的核心功能,react-router-dom: 基于react-router,加入了在浏览器运行环境下的一些功能,例如:Link组件,会渲染一个a标签,BrowserRouter和HashRouter 组件,前者使用pushState和popState事件构建路由,后者使用window.location.hash和hashchange事件构建路由
- 结论:react-router-dom依赖react-router,所以我们使用npm安装依赖的时候,只需要安装相应环境下的库即可,不用再显式安装react-router。基于浏览器环境的开发,只需要安装react-router-dom
react路由组件
- Route:路由界面,执行路由组件载入<Route path="/home" component={Home} />
- Router:路由盒子,包裹需要执行路由的组件
- Link:路由组件,实际上解析成一个a标签,需要由一个to属性来执行链接地址。<Link to="/home" > 首页 <Link />
react-router路由原理
- 可以实现无刷新条件下切换显示不同的页面,路由的本质就是页面的URL改变时,页面的结果根据URL变化而变化,但是页面不会刷新
- hash实现前端路由,在URL中#后面的就是hash值,通过监听hashChange事件,实现hash改变,就改变页面,但是页面不会刷新
- history实现路由:使用history提供的方法(go、back、forward、replaceState、pushState)
- hash路由和history路由的区别:hash在地址栏有#、history是h5新增,有兼容问题、hash不会重新加载页面、history运用了浏览器的历史记录栈,之前有back,forward,go方法,之后在HTML5中新增了pushState()和replaceState()方法(需要特定浏览器的支持),它们提供了对历史记录进行修改的功能,不过在进行修改时,虽然改变了当前的URL,但是浏览器不会马上向后端发送请求
react原理
- setState
setState在合成事件和钩子函数中是异步的
在原生事件和setTimeout中是同步的
setState的“异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形成了所谓的“异步”
第一个参数可以是对象或者函数 是更新state
第二个参数获取最新的state,副作用操作 dom操作事件触发声明 数据获取
- jsx语法
JSX 仅仅是 createElement() 方法的语法糖(简化语法)
JSX 语法被 @babel/preset-react 插件编译为 createElement() 方法
- 组件更新机制
setState() 的两个作用: 1. 修改 state 2. 更新组件(UI)
过程:父组件重新渲染时,也会重新渲染子组件。但只会渲染当前组件子树(当前组件及其所有子组件)
- 组件性能优化
减轻 state:只存储跟组件渲染相关的数据
避免不必要的重新渲染 : shouldComponentUpdate(nextProps, nextState)
通过返回值决定该组件是否重新渲染,返回 true 表示重新渲染,false 表示不重新渲染 起到优化作用
- 纯组件 PureComponent
PureComponent 内部自动实现了 shouldComponentUpdate 钩子,不需要手动比较
纯组件内部通过分别 对比 前后两次 props 和 state 的值,来决定是否重新渲染组件
纯组件内部的对比是 shallow compare(浅层对比)
- 虚拟 DOM 和 Diff 算法
数据改变视图更新
初次渲染时,React 会根据初始state(Model),创建一个虚拟 DOM 对象(树)
根据虚拟 DOM 生成真正的 DOM,渲染到页面中
当数据变化后(setState(),重新根据新的数据,创建新的虚拟DOM对象(树)
与上一次得到的虚拟 DOM 对象,使用 Diff 算法 对比(找不同),生成patch补丁对象,得到需要更新的内容
最终,React 只将变化的内容更新(patch)到 DOM 中,重新渲染到页面
react vs vue
- 相同:都采用了vDOM,diff算法
- 都使用组件系统
- 都是单向数据流 - 不同:vue vDom是采用的snabbdom,React则不是
- React 16版本之后采用了新的vdom对比算法 Filber算法
- React 仅仅可以看做是MVC中V,而vue是有完整三个部分的,MVVM
react渲染 - key
- react渲染依赖于vDOM,对于列表元素来说,可能只是改变了位置,但是react并不知道改变了位置,所以它会重新渲染后面的元素,增加了DOM操作,但是如果我们给每一个元素加上一个key作为唯一标识,react就可以知道这两个元素只是交换了位置
- react中的diff算法,当渲染结构发生变化的时候,react会在vDOM中用diff算法进行一次对比,将发生变化的结构改变之后再根据虚拟dom进行真实DOM的渲染,也就是说,如果存在key值,diff算法就会根据这个key值来进行匹配,在遍历新的dom结构的时候,就会知道这个元素只是改变了位置
什么是jsx
JSX是javascript的语法扩展。它就像一个拥有javascript全部功能的模板语言 在里面可以使用js代码{}
单页面和多页面
- 单页面(SPA):通俗来说就是只有一个主页面的应用浏览器一开始会加载所有的HTML,JavaScript,css资源。交互的时候由动态路由程序载入相应页面,单页面的跳转仅刷新部分资源
- 多页面(MPA):一个应用中有多个页面,跳转的时候是整页刷新
单页面和多页面的区别
单页面优点:
用户体验好,快,内容的改变不需要重新加载整个页面,基于这一点spa对服务器压力较小
前后端分离
页面效果会比较炫酷(比如切换页面内容时的专场动画)
单页面缺点:
导航不可用,如果一定要导航需要自行实现前进、后退
初次加载时耗时多
页面复杂度提高很多
vue基础
虚拟DOM为何能提高性能
- 虚拟DOM相当于在JavaScript和真实DOM中添加了一个缓存,在利用diff算法,去除了不必要的DOM操作,从而提高了性能
vue的两大核心
- 数据驱动 – 数据的双向绑定
- 组件系统
- 模板(template)
- 初始数据(data)
- 外部参数(props)
- 方法(methods)
- 生命周期钩子函数(hooks)
- 私有资源(assets)
Vue生命周期
- 初始化阶段:
- 初始化事件和生命周期
- beforeCreate:不能获取数据,也不能操作dom
- 数据挂载,绑定事件
- created:数据可以获取,也可以更改数据,绑定事件
- 组件或实例查找对应模板,生成vDOM
- beforeMount:可以获取数据,和事件绑定
- 虚拟dom已经生成,初始化渲染操作
- mounted:数据挂载完毕,可以操作dom - 运行中阶段:
- beforeUpdate:更改数据会执行这个函数,vDOM会重新渲染
- updated:DOM更新完成,可以操作更新后的DOM - 销毁阶段:
- beforeDestroy:当执行$destroy方法,也就是销毁组件时,就会执行这个函数,在这里可以做清除定时器,事件等操作
- destroyed:只剩下DOM空壳,做善后操作
Vue响应式原理 - 3.0使用proxy
- 采用数据劫持结合发布订阅者模式,通过Object.defineProperty()方法劫持各个属性的getter和setter,属性发生变化时通知订阅者触发监听回调,更新视图。
- 由于JavaScript的限制,不能监听到数据和对象的变化
- 对象采用方法:
- Vue.set(this.obj, ‘c’, 3)
- this.$set(this.obj, ‘c’, 4)
- this.obj = Object.assign({}, this.obj, {c: 6})
- this.obj = {…this.obj, c: 8}
- 数组采用方法:
- Vue.set(this.arr, 1, ‘x’)
- this.$set(this.arr, 1, ‘x’)
- this.arr.splice(2)
MVC、MVVM:都是软件架构思想
- MVC:model、view、control | view -> control -> model -> view
- MVVM:model、view、viewModel | view <-> viewModel -><- model
计算属性、方法、侦听器:
- 计算属性:模板里面要多次使用相同的逻辑、复杂的逻辑
- 计算属性与方法最大的区别是计算属性有缓存,方法没有缓存。
- 侦听器:通过侦听自身的值变化去改变其他的响应式数据,计算属性是侦听其他的响应式数据来改变自身的状态
v-if 、v-for、v-show
v-if和v-show:v-if是条件渲染,也就意味着如果一开始条件为假时是不会渲染当前元素的,直到条件为真时才开始渲染,v-show则是不论开始是否为假都会渲染,只是单纯的进行css切换。因此如果条件切换不是很频繁则使用v-if较好
v-if和v-for一起使用时v-for具有更高优先级,但是不推荐一同使用
Vue修饰符
- .lazy | .number | .trim
- 事件修饰符: .stop | .submit | .prevent | .capture | .self | .once
- 按键修饰符: .xx | .enter | .tab | .delete | .esc | .space | .up | .down | .left | .right | .ctrl | .alt | .shift | .meta
组件传参
- 父子传参:自定义属性和Props
- 子父传参:自定义事件和
自定义指令
使用Vue.directive注册全局自定义指令,也可以添加选项directives注册组件内自定义指令
//全局定义
Vue.directive("change-color",function(params){
//执行代码块
})
前端路由
根据不同URL地址展示不同页面内容;一个URL与对应页面程序之间的映射关系
嵌套路由
以/开头作为根路径,子路由设置在children里
Vue.router的三种模式
- hash - 带#号
- history - 不带#号
- abstract - 在week环境中使用
组件的状态
- 组件内的状态:data
- 组件外的状态:props
- 全局的状态:Vuex的state
服务端渲染
- 早期的时候,由于页面比较简单,前后端分离也不够完善,所以当时的页面渲染还是在服务端完成HTML文件拼接,然后浏览器接收这个文件解析展示。
- 优点:更好的SEO,更快的内容到达时间(首屏渲染速度更快),无需占用客户端资源
- 缺点:更高的开发要求,更高的服务器要求,不利于前后端分离,占用服务端资源
移动端适配
- 手机淘宝方案:flexible.js
- less或者sass的预编译的mixin混合功能,带参数计算
- 使用最新的postcss - npm install postcss-pxtorem --save-dev
Vue的性能优化
- SPA页面采用keep-alive缓存组件
- 在更多的情况下,使用v-if代替v-show
- 第三方模块按需导入
- 服务端渲染SSR
- 压缩代码
- 服务端开启gzip压缩
计算机基础
get和post区别
- 语义:get获取,post传输。
- 安全:get不安全,post安全。
- 长度:get限制长度(4k),post理论上不限制的(2M)。
- 传输数据:get通过地址栏,post通过send和设置请求头。
- 缓存:get有缓存,post没有缓存
http常见状态码
- HTTP状态码(英语:HTTP Status Code)是用以表示网页服务器超文本传输协议响应状态的3位数字代码。
- 200 请求成功
- 301 被请求的资源已永久移动到新位置
- 302 请求的资源临时从不同的 URI响应请求。
- 304 上次请求的资源未被修改
- 401 请求需要身份验证,通常需要加上身份验证相关信息
- 403 服务器已经理解请求,但是拒绝执行它。
- 404 没有找到
- 500 服务器遇到了一个未知情况,导致服务器无法完成对请求的处理。通常是服务器端程序代码出错
- 503 服务器临时维护或过载,无法完成当前请求
- 1开头 : 消息类
- 2开头 : 成功
- 3开头 : 重定向
- 4开头 : 请求错误
- 5开头 : 服务器错误
项目积累
项目中遇到的问题
- react中配置二级路由,地址变化但是界面不更新
- 使用dva/router中的withRouter高阶组件解决 - 图表联动
- 我们只需要把当前被选中图表的事件,直接发给其他图表即可,然后判断被选中的图表是哪个作为区分onTouchEvent(event)普通事件传递 - 要求智能匹配产品
- 找网上类似功能的网站 查看源码 和主管讨论
- 需要一个设计一个投资习惯和风险承受能力测试
- 从后端获取这个客户测试的结果 以及客户平常投资的习惯 生成不同的关键字
- 根据关键字从数据库中匹配产品 展示界面
react移动端兼容问题
- ES6的浏览器兼容问题:babel默认只会转换ES6的语法,而不会转换API,比如promise,Object.assign、array.from等新方法,我们可以引入另外的包来解决这个问题,比如babel-runtime、babel-polyfill来完成
- iOS下的软键盘问题: fixed失效是由于软键盘唤起后,页面的 fixed 元素将失效(ios认为用户更希望的是元素随着滚动而移动,也就是变成了 absolute 定位),既然变成了absolute,所以当页面超过一屏且滚动时,失效的 fixed 元素就会跟随滚动了。解决方案就是让整个页面处于一屏高度就能解决问题的根本
- meta标签对于移动端的一些特殊属性
- 主要I是强制让文档的宽度与设备宽度保持1:1,最大宽度1.0,禁止屏幕缩放:<meta content=“width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no” name=“viewport”>
- 这个也是iphone私有标签,允许全屏浏览<meta content=“yes” name=“apple-mobile-web-app-capable”>
- iphone的私有标签,iphone顶端状态条的样式:<meta content=“black” name=“apple-mobile-web-app-status-bar-style”>
- 禁止数字自动识别为电话号码,这个比较有用,因为一串数字在iphone上会显示成蓝色,样式加成别的颜色也是不生效的:<meta content=“telephone=no” name=“format-detection”>- 页面禁止复制、选中文本
- -webkit-user-select: none;
- -moz-user-select: none;
- -khtml-user-select: none;
- user-select: none; - input的placeholder出现文本位置偏上的问题:PC端设置line-height等于height能够对齐,但是移动端仍然偏上,可以设置为line-height:normal
- 在iOS和Android中,audio和video元素无法自动播放的问题:代码设置为触屏即播
- 页面禁止复制、选中文本
登录注册的实现
- 登录注册做成受控组件,组件中定义state,和表单进行绑定
- redux-saga发送数据请求,发送action修改数据,useEffect中dispatch发送数据请求,后端对比用户名是否重复,返回state
- 前端根据返回的状态判断跳转到登录页
- 登录发送数据请求,与数据库对比用户名密码是否正确,根据后端返回结果跳转到首页
- 使用cookie保存用户名密码
- 做用户体验,考虑实际应该跳转的情况和不应该跳转的情况
Git常用命令
- Git init - 初始化仓库
- Git clone - 拷贝一份远程仓库
- Git add - 添加文件到暂存区(缓存区)
- Git commit - 提交到本地仓库
- Git status - 查看当前仓库状态
- Git diff - 比较暂存区和工作区文件差异
- Git reset - 回退版本
- Git rm - 删除工作区文件
- Git mv - 移动或重命名工作区文件
- Git log - 查看历史提交记录
- Git remote - 操作远程仓库 (ex:Git remote add URL<远程仓库地址>)
- Git fetch - 获取远程仓库代码
- Git pull - 获取并合并远程仓库代码
- Git push - 上传代码到远程并合并
- Git branch - 查看仓库分支
- Git checkout - 切换仓库分支
- 更多详细用法戳这里
git怎么删除远程和本地分支
- 删除本地分支,删除需要删除的分支之前切换到别的分支然后执行,git branch --delete 分支名字
- 删除远程分支,git push origin --delete 分支的名字
关于IE特性
- IE的排版引擎是Trident
- Trident内核的大量bug等安全性问题没有得到及时的解决
- js上它有他自己的想法,有它自己的独立方法,比如事件绑定:attachEvent、比如创建事件:creatEventObject
- css上也有自己的处理方式,如设置透明,低版IE使用滤镜
当一个页面需要渲染的数据太多,可以怎么处理
- 分页
- 懒加载
- 新线程
webpack
什么是webpack?
- WebPack可以看做是模块打包机:它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其打包为合适的格式以供浏览器使用
为什么要使用webpack?
- 如今的很多网页其实可以看做是功能丰富的应用,它们拥有着复杂的JavaScript代码和一大堆依赖包,为了简化开发的复杂度,前端社区出现了一大堆实践方法,比如:模块化(将复杂的程序细小化)、typescript(JavaScript的超集)、scss、less等css预处理器。这些改进确实大大的提高了我们的开发效率,但是利用它们开发的文件我们却往往需要做一些额外的处理才能够让浏览器识别,但是我们手动处理又是非常繁琐的,所以就出现了webpack
- 对于webpack来说,一切都是模块,比如JavaScript代码,css代码或者是字体、图片等等,只要有合适的loader,就能当做模块处理
- webpack还具有热更新机制:不用刷新浏览器而将新变更的模块替换掉旧的模块
webpack的loader和plugin
- webpack的loader可以将文件从不同的语言(如TypeScript)转换为JavaScript,或者将内联图像转换为data URL比如CSS-Loader,Style-Loader可以用来处理样式表,babel-loader优雅降级配置ES高版本转成低版本
- webpack常用loader:style-loader、css-loader、less-loader、sass-loader、babel-loader、coffee-loader 、ts-loader、raw-loader、file-loader 、url-loader、mocha-loader、jshint-loader 、eslint-loader
- plugin:插件是用来拓展Webpack功能的,它们会在整个构建过程中生效,执行相关的任务。在webpack打包编译过程里,在对应的事件节点里执行自定义操作,比如资源管理、bundle文件优化等操作
webpack构建流程
- 初始化参数:从配置文件和shell语句中读取合并参数,得到一个最终的参数
- 开始编译:用得到的最终参数初始化一个对象,加载所有的配置插件
- 确定入口:从配置的entry中找到入口文件
- 编译模块:从入口文件开始,调用对应的loader对模块进行编译,再找到这个模块的依赖模块,一直到所有的入口依赖文件都完成编译
- 完成模块的编译:完成loader的编译后,得到每个模块的翻译内容以及他们之间的依赖关系
- 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表
- 输出完成:配置确定输出的路径和文件名,把文件内容写入到文件系统
webpack的前端优化
- 压缩代码:利用webpack的一些plugin来压缩代码,比如:UglifyJsPlugin
- 利用CDN:将部分静态资源路径改为CDN路径
- 删除无用的代码
- 提出公共代码(重复代码)