赞
踩
当我们对一个文档进行布局的时候,浏览器的渲染引擎会根据标准之一的css基础的盒模型,将所有的元素表示为一个个的矩形的盒子
一个盒子有四个部分组成,content(实际内容,显示文本和图像)、padding(内边距)、border(边框)、margin(外边距)
盒模型有两种:分别是标准盒模型和怪异盒模型
标准盒模型的总宽度:width+padding+border
怪异盒模型的总宽度:width+padding+border
怪异盒模型是针对我们我们最外部的盒子的宽度进行一个缩减
获取盒子的宽高:document.body document.documentelement,clientWhith,clientHeight(不会计算边框和内边距)
scrollWidth scrollHeight
Css选择器是css规则的一部分,他是元素和其他部分结合起来告诉浏览器哪个html元素应当被选为应用规则中的css属性值的方式
Css属性选择器:
id选择器,类选择器,标签选择器,后代选择器,子选择器,相邻同胞选择器,群组选择器,伪类选择器,伪元素选择器,属性选择器,
优先级:id选择器>类选择器>标签选择器
属性继承:属性继承指的就是我们给父元素设置一些属性,后代属性就会自动拥有这些属性
属性继承主要分为以下几种:字体系列继承,文本系列继承,元素可见性,表格布局属性,列表属性,引用,光标属性
继承中比较特殊的几点:a标签的字体颜色不能继承,h1-h6标签字体的大小也是不能被继承的
没有继承的属性:文本属性,display,盒子模型属性,背景属性,生成内容属性,轮廓样式属性,页面样式属性
利用定位+margin:auto:父相子绝
利用定位+margin:负值
利用定位+transform:translate(-50%, -50%)将会将元素位移自己宽度和高度的-50%
table布局设置父元素为display:table-cell,子元素设置 display: inline-block。利用vertical和text-align可以让所有的行内块级元素水平垂直居中
flex布局
display: flex时,表示该容器内部的元素将按照flex进行布局
align-items: center表示这些元素将相对于本容器水平居中
justify-content: center也是同样的道理垂直居中
grid布局:网格布局
回流:布局引擎会根据各种样式计算每个盒子在页面上的大小与位置
重绘:当计算好盒模型的位置,大小以及其他的属性后,浏览器根据每个盒子的特性进行绘制
回流一定会触发重绘,重绘不会触发回流
在页面初始渲染阶段,回流不可避免的触发,可以理解成页面一开始是空白的元素,后面添加了新的元素使页面布局发生改变。
当我们对 DOM 的修改引发了 DOM 几何尺寸的变化(比如修改元素的宽、高或隐藏元素等)时,浏览器需要重新计算元素的几何属性,这个时候就会触发回流。
当我们对 DOM 的修改导致了样式的变化(color或background-color),却并未影响其几何属性时,浏览器不需重新计算元素的几何属性、直接为该元素绘制新的样式,这里就仅仅触发了重绘。
回流触发的时机:添加或者删除可见的dom元素,元素的位置发生变化,元素的尺寸发生变化(包括外边距,内边距、边框大小,高度和宽度等)内容发生变化,比如文本变化或者图片被另一个不同尺寸的图片所代替,页面一开始渲染的时候,浏览器的尺寸发生变化
重绘触发时机:颜色的改变,文本方向的修改,阴影的修改
浏览器的优化机制:由于每次重排都会造成额外的计算消耗,因此大多数的浏览器都会通过队列化修改并批量的执行优化重排过程,浏览器会将修改操作放入到队列里,直到过了一段时间或者操作达到一个阈值,才清空队列,当你获取布局信息的操作的时候,会强制队列刷新,因此浏览器不得不清空队列,触发回流重绘来返回正确的值
避免重绘和回流:
如果想要设定元素的样式,通过改变元素的class类名,避免设置多项内联样式,应用元素的动画,使用position属性的fixed值或者absolute值,避免使用table布局,table布局中的每个元素的大小以及内容的改动,都会导致整个table的重新计算,使用css3硬件加速
响应式网站设计是一种网络页面设计布局,页面的设计与 开发应当根据用户行为以及设备环境(系统平台,屏幕尺寸,屏幕定向)进行相应的响应和调整
响应式网站常见特点:同时适配pc+平板+手机
标签导航在接近受持终端设备时改变为经典的抽屉式导航
网站的布局会根据视口来调整模块的大小和位置
基本实现原理就是通过媒体查询检测不同的设备屏幕尺寸做处理,为了处理移动端,页面头部必须有meta声明viewport
实现响应式布局有以下几种方式:
媒体查询:
百分比
vw/vh
Rem
弹性盒子:不需要处理像素问题,盒子之间的间距问题
响应式布局优点:面对不同的分辨率设备灵活性强,能够快捷解决多设备显示适应问题
缺点:仅适用布局,信息,框架并不复杂的部门类型网站,兼容各种设备工作量大,效率地下,代码累赘,会出现隐藏无用的元素,加载时间过长,一定程度上改变了网站原有的布局结构,会出现用户混淆的情况
Rem、em,vh/vw、%的区别:
Rem是根据html根节点的字体大小进行设置的,r是root,根的意思
Em是根据我们父节点的字体大小设置的
Vh/vw是把我们的屏幕平分为100等份,进行设置的
百分比是存在缺陷的,他会有参照物,在我们给最大的盒子设置100%高的时候,他会根据我们填充物来设置高度,而且我们无法给字体设置%比
压缩css,减少文件体积
适用link引入css文件
合理设计css布局,注意复用样式,减少渲染上化的时间
少用*选择器
慎用浮动,定位等高性能属性,
减少页面重排和重绘
属性值为0时,不加单位
去除空规则{}
充分利用css继承,减少代码量
选择器优化嵌套,尽量避免层级过深
Css优化主要是4个方面
加载性能:只要是从减少文件体积,减少阻塞加载,提高并发方面入手
选择器性能
渲染性能
可维护性,健壮性
前端是最贴近用户的程序员,比后端,数据库,产品经理,运营安全都近
实现界面交互,提升用户体验,基于nodejs可跨平台开发
前端的能力就是能让产品从90分进化到100分,甚至更好
与团队成员,ui设计,产品经理沟通
做好页面结构,页面重构和用户体验
在js中,我们可以把类型分为两种类型,基本数据类型和复杂数据类型
两者的区别:存储位置不同
基本数据类型:Number,string,boolean,undfined,null,symbol
引用类型:object,array,Function
基本数据类型存储在栈中,在栈中存放的是对应的值
引用数据类型对象存储在堆中,在栈中存放的是指向堆内存的地址
不同的类型数据导致赋值便变量时的不同
简单类型赋值,是生成相同的值,两个对象对应不同的地址
复杂类型赋值,是将保存对象的内存地址赋值给另一个变量,也就是两个变量指向堆内存中的同一个对象
Typeof操作符返回是一个字符串,表示未经计算的操作数的类型
Instanceof运算符用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上
Typeof和instanceof都是用来判断数据类型的方法,区别:
Typeof会返回一个变量的基本类型
Instanceof返回的是一个布尔值
Instanceof可以准确的判断复杂引用数据类型,但是不能正确判断基本数据类型
Typeof也存在弊端,他虽然可以判断基础数据类型,但是引用类型中,除了function类型以外,其他的也无法判断
如果想要通用检测数据类型,可以采用object.prototype.tostring调用该方法,统一返回格式”[onject Xxx]”的字符串
其他数据类型数据类型的方法
Constructor:可以查看目标构造函数,也可以进行数据类型判断,但是不能判断null和undefind,因为这两个特殊类型没有对应的包装对象,constructor和instanceof类似,
Object.prototype.toString,万能方法,终极方法,工作中非常常用并且精准
isArray
一个函数和对周围状态的引用捆绑在一起,这样的组合就是闭包,闭包就是函数嵌套函数,内部函数可以访问外部函数的参数和值
在js中,每当创建一个函数,闭包就会在函数创建的同时被创建出来,作为函数内部与外部连接起来的一座桥梁
缺点:常驻内存,增大内存的使用量,使用不当会造成内存的泄露,闭包会使函数中的变量都会被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,可能会导致内存泄露,解决方式是在退出函数之前,将不使用的变量
优点:变量长期驻扎在内存中,可以重复使用变量,避免全局变量的污染,私有成员的存在
适用场景:
创建私有变量
延长变量的生命周期
倒计时,延迟调用,回调等闭包的应用,核心思想还是创建私有变量和延长变量的生命周期
一般函数的词法环境在函数返回之后就被销毁了,但是闭包会保存对创建时所在词法环境的引用,即使创建时所在的执行上下文被销毁,但创建时的词法环境任然存在,以达到延长变量生命周期的目的
注意事项:如果不是某些特定的任务需要适用闭包,在其他函数中创建函数是不明智的,因为闭包在处理速度和内存消耗方面对脚本性能具有负面影响
闭包的缺点是使用不当的画,会导致内存泄露,内存泄露指的就是指程序中已动态分配的堆内存由于某种原因程序未释放或者无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至程序崩溃等严重后果
Call,apply和bind最大的作用就是改变你函数执行时的上下文,简而言之就是改变函数运行时this指向
区别:
Apply接收两个参数,第一个参数是this的指向,第二个参数是函数接收的参数,以数组的形式传入,改变this指向后原函数会立即执行,且此方法只是临时改变this指向一次
Call方法的第一个参数也是this的指向,后面传入的是一个参数列表,和apply一样,改变this指向后原函数会立即执行,且此方法只是临时改变this指向一次
Bind和call方法很相似,第一个参数也是this指向,后面传入的也是一个参数列表,但是这个参数列表可以分多次传入,改变this指向后不会立即执行,而是返回一个永久改变this的指向函数
实现bind,可以分解为三部分:
修改this指向
动态传递参数
兼容new关键字
首先,js是一门单线程的语言,意味着同一时间内只能做一件事情,但是这并不意味着单线程就是阻塞,而实现单线程非阻塞的方法就是事件循环
在js中,所有的任务都可以分为:
同步任务:立即执行的任务,同步任务一般会直接进入主线程中执行
异步任务:异步执行的任务,比如ajax网络请求,setTimeout定时函数等
同步任务进入主线程,异步任务进入任务队列,主线程内的任务执行完毕为空,会去任务队列读取对应的任务,推入主线程执行,上述过程的不断重复就是事件循环
宏任务和微任务
微任务:一个需要异步执行的函数,执行时机实在主函数执行之后,当宏仁务执行之前
宏仁务:宏仁务的时间粒度比较大,执行的时间间隔是不能精确控制的,对一些高实时性的需求就不太符合
Async和await:async是异步的意思,await则可以理解为等待,放到一起可以理解async就是用来声明一个异步方法,而await是用来等待异步方法执行
正常情况下,await命令后面是一个promise对象,返回该对象的结果,如果不是promise对象,就直接返回对应的值
Dom的全称是Document Object MOdel,是为html和xml提供的api,虽然他们用来标记的标签不同,但是他们的本质的结构是相同的,换句话说,按照dom的标准,html和xml都是以标签为节点构造的树结构,dom将html和xml的相同的结构本质抽象出来,然后通过脚本语言,如js,按照dom里的模型标准访问个操作文档内容
Dom是由三部分进行组成的,包括核心,html接口和xml接口,核心部分是结构化文档比较底层对象的集合,这一部分所定义的对象已经完全可以表达出任何html和xml中的文档中的数据了,html接口和xml接口两部分则是专门为操作具体html文档和xml文档所提供的高级接口
常见的dom操作:
查找节点,创建节点,删除节点,修改节点,插入节点,设置样式
添加节点:innerHtml appendChild
创建节点:createElement createTextNode
修改节点:innerHtml innderText textContent
删除节点:removeChild
Bom,浏览器对象模型,提供了独立于内容与浏览器窗口进行交互的对象
作用就是跟浏览器做一些交互效果,比如对页面进行后退,前进,刷新,浏览器的窗口发生变化,滚动条的滚动,以及获取客户的一些信息
浏览器的全部内容可以看成Dom,整个浏览器可以堪称bom
Dom:文档对象模型,dom就是把文档当成一个对象来看待,dom的顶级对象是document,dom主要学习的是操作页面元素。Dom是w3c标准规范
Bom:浏览器对象模型,把浏览器当作一个对象来解析,bom的顶级对象是window,bom学习的是浏览器窗口交互的一些对象,bom是浏览器厂商在各种浏览器上定义的,兼容性极差
Window,location,navigator,screen,history
Bom的核心对象是window,他表示浏览器一个实例,在浏览器中,window对象有双重角色,浏览器窗口既是一个接口,又是全局对象
js本地缓存的方法主要有以下四种,cookie,sessionStorage,LocationStorage,indexedBD
Cookie:类型为小型文件,之某些网站为了辨别用户身份而存储在用户本地终端的数据,是为了解决http无状态导致的问题,一般不超过4kb,cookie在每次请求中都会被发送,如果不使用https对其进行加密,其保存的信息很容易被窃取,导致安全风险,cookie如果被窃取,他就可以利用你的cookie假扮你来登录网站
localStorage:生命周期,持久化的本地存储,除非主动删除数据,否则数据永远不会过期
存储的信息在同一域中是共享的,大小是5m。localStorage本质上是对字符串的读取,如果存储的内容多的话会消耗内存空间,导致页面变卡,受同源策略限制
sessionStorage
sessionStorage和 localStorage使用方法基本一致,唯一不同的是生命周期,一旦页面(会话)关闭,sessionStorage 将会删除数据
扩展的前端存储方式
indexedDB是一种低级API,用于客户端存储大量结构化数据(包括, 文件/ blobs)。该API使用索引来实现对该数据的高性能搜索
虽然 Web Storage对于存储较少量的数据很有用,但对于存储更大量的结构化数据来说,这种方法不太有用。IndexedDB提供了一个解决方案
优点:
储存量理论上没有上限
所有操作都是异步的,相比 LocalStorage 同步操作性能更高,尤其是数据量较大时
原生支持储存JS的对象
是个正经的数据库,意味着数据库能干的事它都能干
缺点:
操作非常繁琐
本身有一定门槛
关于indexedDB的使用基本使用步骤如下:
打开数据库并且开始一个事务
创建一个 object store
构建一个请求来执行一些数据库操作,像增加或提取数据等。
通过监听正确类型的 DOM 事件以等待操作完成。
在操作结果上进行一些操作(可以在 request对象中找到)
关于使用indexdb的使用会比较繁琐,大家可以通过使用Godb.js库进行缓存,最大化的降低操作难度
二、区别
关于cookie、sessionStorage、localStorage三者的区别主要如下:
存储大小:cookie数据大小不能超过4k,sessionStorage和localStorage虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大
有效时间:localStorage存储持久数据,浏览器关闭后数据不丢失除非主动删除数据;sessionStorage数据在当前浏览器窗口关闭后自动删除;cookie设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭
数据与服务器之间的交互方式,cookie的数据会自动的传递到服务器,服务器端也可以写cookie到客户端;sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存
在了解了上述的前端的缓存方式后,我们可以看看针对不对场景的使用选择:
标记用户与跟踪用户行为的情况,推荐使用cookie
适合长期保存在本地的数据(令牌),推荐使用localStorage
敏感账号一次性登录,推荐使用sessionStorage
存储大量数据的情况、在线文档(富文本编辑器)保存编辑历史的情况,推荐使用indexedDB
他俩的本质就是不一样的,防抖就是多次执行变为最后一次执行,而节流就是多次执行变成每隔一段事件执行,他们都可以使用定时器来实现
防抖:当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发了时间,就重新开始延时
节流:当持续触发事件时,保证一定事件段内只调用一次事件处理函数,节流通俗的解释就是我们把水龙头放水,阀门打开,水就哗哗的往下流,秉着勤俭持家的优良传统美德,我们要把水龙头关小点,最好的是按我们心意在一定规律在某个时间内间隔一滴一滴的往下滴
函数节流是:在固定的时间内触发事件,每隔n秒触发一次
函数防抖是:在频繁触发后,n秒只执行一次
防抖主要是利用定时器实现
节流通过时间戳或者定时器实现
应用场景:防抖:search搜索联想,用户不断的输入值,用防抖来节约请求资源,频繁的点赞和取消点赞
节流:鼠标不断点击触发,mousedowm单位时间内只触发一次
区别?
函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,而函数防抖只是在最后一次事件后才触发一次函数,比如在页面的无限加载场景下,我们需要用户在滚动页面是,每隔一段时间发送一次ajax请求,而不是在用户停下滚动页面操作时才请求数据,这样的场景,就是和用节流技术来实现
通过instanceof判断:instanceof运算符用于检查构造函数的prototype属性是否出现在对象的原型链中的任何位置,并返回一个布尔值
通过constructor判断,实例的构造函数属性指向构造函数,所以是否是数组也可以通过构造函数属性来判断
通过Object.prototype.toString.call()判断,call可以获得不同类型的对象
Array.isArray(),es5新增的isarray()方法就是为了提供一个稳定可用的数组判断方法,为了这个目的的提出更好的东西而不使用它是不可能的,对于之前es5不支持这种方式的问题,我们其实可以做好兼容性,自己可以打包
作用域,即变量和函数生效的区域或集合,换句话说,作用域决定了代码区块中变量和其他资源的可见性
作用域分为全局作用域和局部作用域和块级作用域、词法作用域
全局作用域会在全局起作用,我们可以在全局中访问到我们的变量
局部作用域:可以在局部访问到的属性,不能进行全局访问到,在{}内可以访问到
块级作用域:像我们let一个块级作用域,他只能在let内部进行访问,let存在暂时性死区
当在js中使用一个变量的时候,首先js会尝试在当前作用与下去寻找该变量,如果没有找到,那么会到他的上一级去进行查找,以此类推知道找到该变量或是已经到了全局作用域
如果在全局作用与仍然找不到该变量,它就会在全局范围内隐式声明该变量或是直接报错
JS声明构造函数(用来实例化对象的函数)时,会在内存中创建一个对应的对象,这个对象就是原函数的原型。构造函数默认有一个prototype属性,prototype的值指向函数的原型。同时原型中也有一个constructor属性,constructor的值指向函数对象。
通过构造函数实例化出来的对象,并不具有prototype属性,其默认有一个__proto__属性,__proto__的值指向构造函数的原型。在原型对象上添加或修改的属性,在所有实例化出的对象上都可共享
/*代码基本架构
1.每个函数function都有一个prototype,即显示原型(属性)
2.每个通过函数实例出来的对象都有一个__proto__,可称为隐式原型(属性)
3.对象的隐式原型的值为其对应构造函数的显示原型的值
1.每个函数function 都有一个prototype 即显式原型(属性),默认指向一个空的object对象
2. 每个实例对象都有一个__proto__,可称为隐式原型(属性)
3.对象的隐式原型的值为其对应构造函数的显示原型的值
原型链:当在实例化的对象中访问一个属性时,首先会在该对象内部(自身属性)寻找,如找不到,则会向其__proto__指向的原型中寻找,如仍找不到,则继续向原型中__proto__指向的上级原型中寻找,直至找到或Object.prototype.__proto__为止(值为null),这种链状过程即为原型链。如下图所示好理解(根据代码参考下图)
原型链的作用:查找对象的属性(方法
事件代理,通俗的来讲,就是把一个元素的响应事件的函数委托到另一个元素
事件流都会经过三个阶段,捕获阶段-目标阶段-冒泡阶段,而事件委托就是在冒泡阶段完成
事件委托,会把一个或者一组元素的事件委托到它的府城或者更外层元素上,真正绑定事件的是外层元素,而不是目标元素
当事件响应到目标元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件上,然后在外层元素上去执行函数
事件委托常见的事件有:click,mousedown,mouseup,keydown,Keyup,keypress
事件委托有两大点:减少整个页面所需的内存,提升整体性能
动态绑定,减少重复工作
事件委托也有局限性:focus,blur这些事件是没有事件冒泡机制,所以也无法进行未退绑定事件
Mousemove,mouseout这样的事件,虽然有事件冒泡,但是只能不断的通过位置去计算定位,对性能消耗高,因此不适合事件委托
This总是返回一个对象,this就是属性或方法“当前”所在对象,由于对象的属性可以赋值给另一个对象,所以属性所在的当前对象是可变的,this指向是可变的
使用场合:
在全局环境中,this指向window
在构造函数中,this指向实例对象
对象的方法,如果对象的方法里包含this,this的指向就是放大运行时所在的对象,如果this所在的方法不再对象的第一层,这是this只是指向当前一层的对象,而不会继承更上面的层
箭头函数:
箭头函数不绑定this,箭头函数没有自己的this关键字
如果在箭头函数中使用this,this关键字将指向箭头函数定义位置的this,且箭头函数this永远指向该函数构造时的环境
总结:
This对象总是指向函数的调用者
如果又new关键字,this指向new出来的那个对象
在事件中,this指向触发这个事件的对象,特殊的时,ie中的attachEvent中this总是指向全局对象的window
在js中,new操作符用于创建一个给定构建函数的实例对象
创建了一个空的js对象
将空对象的原型prototype指向构造函数的原型
将空对象作为构造函数的上下文(改变this指向)
对构造函数有返回值的判断
在new的时候,会对构造函数的返回值做一些判断:
如果返回值时基础数据类型,则忽略返回值
如果返回值是引用数据类型,则return返回,也就是new操作符无效
Null值是一个字面量,不想undefind,他不是全局对象的一个属性,null是表示缺少的标识,指示变量未指向任何对象,把null作为尚未创建的对象,也许更好理解,null值的返回类型应是一个对象,但没有关联的值的地方使用
Undefind是全局对象的一个属性,也就是说,他是全局作用域的一个变量,undifind的最终值就是原始数据类型undifind
Null和undifind两者相等,但是当两者做全等比较时,两者又不等
Null:object类型,代表空值,代表一个空对象的指针
Undifind:undifind类型
Undifind和null在if语句中,都会被自动转换为false,相等运算符甚至直接报告两者相等
转为数值时,值不一样,undefind转为数值NaN,null转为数值0
Use strict是一个字符串字面量,用来指定代码运行于严格模式下,在严格模式下运行代码有很多限制,也有很多好处,
变量在使用前必须声明,这可以防止无意中使用了未声明的变量
函数中的this不再是引用全局对象,而是undifind,这可以消除以前代码中的一些古怪行为,代码会变得更加严谨,尤其是当函数是作为构造函数的时候,获得的好处更加明显
他不是一条语句,但是是一个字面量表达式,在js旧版本中会被忽略
同步是阻塞模式,异步是非阻塞模式
同步就是指一个进程在执行某个请求的时候,若该请求需要一段事件才能返回信息,那么这个进程将会一直等下去,知道收到返回信息才继续执行下去
同步就相当于是当客户端发送请求给服务端,在等待服务器响应的请求时,客户端不做其他的事情,当服务器做完了才会返回到客户端,这样的华客户端需要一直等待,用户使用起来会有不友好
异步时指进程不需要一直等下去,而是继续执行下面的操作,不管其他进程的状态,当有消息返回时系统会通知进程进行处理,这样可以提高执行的效率
异步就相当于客户端发送给服务端请求时,在等待服务端响应的时候,客户端可以做其他的事情,这样节约了事件,提高了效率
存在既有道理,异步虽然好,但是有些问题还是需要同步来解决,比如有些东西我们需要的是拿到返回的数据再进行操作,这些是异步无法解决的
一个人一边吃饭一边玩手机,这是异步操作
一个人必须等吃完饭之后再玩手机,这是同步操作
异步:settimeout async await promise 回调函数 事件监听,发布订阅 生成器
外形不同:箭头函数使用箭头定义,普通函数中没有
箭头函数都是匿名函数,普通函数可以有匿名函数,也可以有具名函数,但是箭头函数都是匿名函数
箭头函数不能用于构造函数,不能使用new,普通函数可以用于构造函数,以此创建对象实例
箭头函数中this的指向不同,在普通函数中,this总是指向调用它的对象,如果用于构造函数,this指向创建的对象实例,箭头函数本身不创建this,也可以说箭头函数本身就没有this,但是它的声明时可以捕获其所在上下文的this供自己使用
This一旦被捕获,就不会再发生变化
箭头函数的this永远指向其上下文的this,任何方法都改变不了其指向,如call,apply,bind
普通函数的this指向调用它的那个对象
其他区别:
箭头函数不能Generator函数,不能使用yeild关键字
箭头函数不具有prototype原型对象
箭头函数不具有super
箭头函数不具有new.target
通常我们会用循环的方式来遍历数组,但是循环是导致js性能问题的原因之一
For in 循环
For循环
Foreach:接收两个参数value,index,forEach无法遍历对象,IE不支持该方法,firefox和chrome支持
这两种方法应该非常常见且使用频繁,但实际上,这两种方法都存在性能问题
再方式一中,for-in需要分析出aray的每个属性,这个操作性能开销很大,用在key已知的数组上是非常不划算的,所以尽量不要使用for-in,除非你不清楚要处理哪些属性,像json对象
在for循环中,循环每进行一次,就会检查一下数字的长度,读取属性要比读取局部变量慢,尤其是当array里存放的都是DOM元素,因为每次读取都会扫描一遍页面上的选择器相关的元素,速度会大大降低
跨域产生的原因是因为浏览器的安全策略,同源策略 协议+端口+域名只要有一个不同,那么就会产生跨域
前端解决跨域:document.domain+iframe(只有在主域相同的时候才能使用该方法)
动态创建script
Location.hash+iframe:原理是利用loctaion.hash来进行传值
Window.name+ifranme:name值在不同的页面加载后仍然存在,并且可以支持非常长的name值
Cors:使用自定义的http头部让浏览器于服务器进行沟通,从而决定请求或响应是应该成功还是应该失败
Jsonp:它包含两部分:回调函数和数据,回调函数就是当响应到来时要放在当前页面被调用的函数
数据就是传入回调函数的中的json数据,也就是回调函数的参数了,jsonp只能发送get请求,这是他的缺点
前端代理:通过一个代理服务器和我们的客户端进行交互,我们的客户端和服务器不能直接进行交互,所以我们在我们的客户端和服务器之间创建一个代理服务器,服务器先发送消息给代理服务器,代理服务器再把数据发送到我们的客户端,客户端把响应的数据再发给代理服务器,代理服务器返回数据给服务端
Xml可扩展标记语言,是一种源自sgml的,基于文本的数据格式
Xml是一种专门为了存储数据而创建的标记语言,他的编写方式与html非常相似,能够通过不同的标签来标记不同的内容
Xml旨在传递或保存数据,而不是显示数据,在xml中,没有预定义标签,其实使用的所有的标签都是自定义的,而且所有的标签都是由两个部分组成,分别时开始标签和结束标签,需要注意的时,xml中的标签是区分大小写的
Xml的主要优点时它可以跨平台,跨语言进行传输,另外xml数据可以保存在格式为.xml的文本文件中
Json译为js对象简谱,是一种轻量级的,基于文本的,开放的数据交换格式,与xml相同,js同样可以跨平台,跨语言传递数据
Json的优点在于其结构灵活,所有的浏览器都支持,而且json语言见到那,大多数变成语言都支持json,另外,json数据可以存储在.json格式的文本文件中
处了有许多不同的地方外,json和xml之间有许多相似的地方,最主要的时,他们的用途时相同的,即存储和传输数据,其次,他们都可以存储在文本文件中,程序员无需借助计算机就可以读写他们中的内容
在http请求中,json和xml都能够作为传递数据的类型,在服务器和客户端之间进行传递
Webpack是一个模块打包工具,可以使用webpack管理模块,并分析模块间的依赖关系,最终编译输出模块为html,js,css以及各种静态文件,让开发过程更加高效
Webpack目的时为了实现模块化,目的是为了更好的管理和维护资源
Webpack最初通过文件拆分的模式实现模块化,就是把我们的相关的模块以及数据维护保存到各个json文件中,这种方式存在明显的弊端,模块在全局中使用,造成模块的全局污染,模块和模块之间没有依赖关系,没有私用空间
随着命名空间的出现,规定了每个模块只能暴露一个全局对象,然后模块的内容都挂载在这个对象中,但是这种方式也没有解决第一种方式的依赖问题
再后来,我们使用立即执行函数为模块提供私有空间,通过参数的形式作为依赖声明,但是仍然存在一定的问题,通过script标签引入页面,这些模块的加载不受控制,时间久了维护起来也比较困难
理想的解决方案就是在页面引入一个js入口文件,其余用到的模块可以通过代码控制,按需加载
现代前端开发变得越来越复杂,我们在开发中可能会遇到的问题:
需要通过模块化的方式来开发
使用一些高级的特性来加快我们的开发效率或者安全性,通过es6,ts开发脚本逻辑,使用less ,sass等方式来编写css样式代码
监听文件的变化反映到浏览器上,提高开发效率
开打完成之后我们还需要将代码进行压缩,合并以及其他相关优化
Webpack优点:
编译代码能力,提高效率,解决浏览器兼容的问题
模块的整合能力,提高性能,可维护性,解决浏览器频繁请求文件的问题
万物皆可模块,项目的可维护性增强,支持不同种类的前端模块类型,统一的模块化方案,所有的资源文件,都可以通过代码控制
Webpack打包的原理是根据文件间的依赖关系对其进行静态分析,将这些模块按指定规则生成静态资源,当webpack处理程序时,其中包含应用程序需要的每个模块,将所有这些模块打包称一个或多个bundle
Wbpack有一个智能解析器,几乎可以处理任何第三方库
Webpack有两种组织模块的依赖方式,同步,异步,异步依赖将作为分割点,形成一个新的块,在优化了依赖树之后,每一个异步区块都将作为一个文件被打包
在某个项目进行需求开发中,该项目是基于webpack3进行打包构建的,在开发过程中我发现打包很慢,开发体验不佳,于是做了简单优化
打包速度慢主要是因为样式文件对js文件的处理loader耗时时间较久
的那个文件发生修改,进行重新编译时,重新编译时耗时其实并不久,但是在浏览器上实际上却花费了更多时间在看到了新的修改
进行代码分割,高达6m的入口文件非常影响体验,优化的第一步就是从代码分割开始,代码分割通过项目中的资源模块按照我们设计的规则打包到不同的bundle中,从未讲题应用的启动成本,提高响应速度
在开发过程中进行webpack缓存是极有必要的,我们在处理样式和js文件的loader之前添加cache-loader将结果缓存在磁盘中,可以显著提升二次构建速度
优化搜索时间,开始打包时获取所有的依赖模块的时间
优化解析时间,根据配置的loader解析响应文件所花费的时间
优化压缩时间,即webpack对代码进行优化压缩所花费的时间
优化二次打包时间,即重新打包时所花费的时间
Loader用于对模块的源代码进行转换,在import或加载模块时预处理文件
Webpack做的事情,仅仅时分析出各个模块的依赖关系,然后形成资源列表,最终打包生成指定的文件中
在webpack内部,任何文件都是模块,不仅仅是js文件,默认情况下,在遇到import或require加载模块的时候,webpack只支持对js和json文件打包
像css,scss,png等这些类型文件的时候,webpack则无能为力,这时候就需要我们配置loader进行文件内容的解析
Loader存在的特性:
Loader可以是同步的,也可以是异步的
Loader运行在node.js中,并且能够执行任何操作
处了常见的通过package.json的main来将一个npm模块导入loader,还可以在module.rules中使用loader字段直接引入一个模块
插件plugin可以为loader带来更多特性
Loader能够产生额外的任意文件
常见的loader:
Style-loader:将css添加到DOM的内联样式styles中
Css-loader:允许将css文件通过reuire的方式引入,并返回css代码
Less-loader:处理less
Sass-loader:处理sass
File-loader:分发文件到output目录并返回相对路径
Url-loader:和file-loader类似,但是文件小于设定的limit
Babel-loader:用baabel来转换es6文件到es
Plugin是一种计算机应用程序,他和主应用程序互相交互,以提供特定的功能
是一种遵循一定规范的应用程序接口编写出来的程序,只能运行在程序规定的系统下,因为它需要调用纯净系统提供的函数库或者数据
Plugin赋予各种灵活的功能,例如打包优化,资源管理,环境变量注入,他们会运行在webpack的不同阶段,贯穿webpack整个编译周期
HtmlWebpackPlugin:打包结束后,自动生成一个html文件家,并把打包生成的js模块引入到html中去
Clean-webpack-plugin:删除构建目录
Mini-css-extract-plugin:提取css到一个单独的文件中
definePlugin:允许在编译是创建配置的全局对象,是一个webpack的内置插件,不需要安装
Copy-webpack-plugin:赋值文件或目录到执行区域,如vue打包过程中,我们会将一些文件方法pubilc的目录下,那么这个目录会被赋值到dist文件夹中
Promise是最早由社区提出和实现的一种解决异步编程的方案,比其他传统的解决方案更合理和更加强大
Es6将它写进了语言标准,统一用法,promise对象是一个构造函数,用来生成promise实例
Promise是为了解决异步处理回调金字塔问题而产生的
Promise有两个特点:
Promise对象的状态不受外界影响
Pending初始状态
Fulfilled成功状态
Rejected:失败状态
Promise有三种状态,只有异步操作的结果可以决定当前是哪一种状态,其他操作无法改变这个状态
Promise的状态一旦改变,就不会再变,任何时候都可以得到这个结果,状态不可逆,只能成功或者失败
缺点:
无法取消promise,一旦新建他就会立即执行,无法中途取消
如果不设置回调函数,promise内部抛出的错误,不会反映到外部
当处于pending状态时,无法得知目前进展到哪一个阶段,是刚刚开始还是即将完成
方法:
All:接收一个数组,数组内都是promise实例
Catch:用于指定发生错误时的回调函数
Resolve:根据传入的参数不同有不同的功能
Reject:处于reject状态
Race:接收一个数组,数组内都是promise实例
Async函数就是Generator函数的语法糖,async就是将Generator函数的星号替换成async,将yield替换成await
异步操作js编程是一件麻烦的事情,所以一直有人想视图解决这个问题
从最早的回调函数,到promise对象,再到Generator函数,每次都有所改进,但是又让人觉得不彻底,他们都有额外的复杂性,都需要理解抽象的底层运行机制
异步编程的最高境界,就是根本不用关心他是不是异步
Async函数的优点:
内置执行器,async自带执行器
Async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果
Async函数的await命令后面,可以跟promise对象和原始类型的值
Async函数返回一个promise对象,可以使用then方法添加回调函数,当函数执行的时候,一旦遇到await就会先返回,等到触发的异步操作完成,在接着执行函数体内后面的语句
注意点:
Await命令后面的promise对象,运行结果可能是rejeccted,所以最好把await命令放在try catch代码块中
Await命令只能用在async后面,如果用在普通函数中,就会报错
如果希望多个请求并且触发,可以使用Promise.All方法
vue经历了四个时代:
石器时代:就是一个静态页面,可以理解为就是一个可以网上浏览的报纸
文明时代:jsp出现,但是有一个缺点,就是不太灵活,都是在服务器端执行的,返回给客户端的就是一个html文本
工业革命时代:jquery出现,spa雏形,一批前端框架出现,节约了开发人员的大量精力,降低了开发者和开发过程的门槛,提高了开发效率和迭代速度
百花齐放时代:各种前端框架不断出现,形成百花齐放
Vue是一个用于构建前端用户界面的开源的js框架,也是一个创建单页面应用的web应用框架,vue的核心是数据驱动,mvvm(模型(负责处理业务逻辑以及和服务器进行交互),视图(负责将数据类型转化为ui展示出来,就是html页面),视图模型(用来连接model和view,是model和view之间通信的桥梁))
组件化:就是把各种逻辑抽象为一个统一的概念来实现开发,降低整个系统的耦合度,调试方便,提高可维护性,提高我们代码的复用率
常见的vue的指令:条件指令:v-if 列表渲染指令:v-for 属性绑定指令:v-bind
事件绑定指令:v-on 双向数据绑定指令:v-model
Vue和react的区别:
相同点:
都有组件化思想,都支持服务器端渲染,都有虚拟dom,数据驱动视图,都是单项数据流
不同点:
数据变化的实习原理不同,react使用的是不可变数据,vue是可变数据
组件通信不同:react中我们通过回调函数来进行通信,vue中子组件向父组件传递消息:事件个回调函数
Diff算法不同:react主要使用diff队列保存需要更新哪些dom,得到patch树,在统一的操作批量更新dom,vue使用双向指针,边对比,边更新dom
Spa仅在web页面初始化加载响应的html,js和css,一旦页面记载完成,spa不会因为用户的操作再进行页面的重新加载或跳转,取而代之的是利用路由机制实现html内容的百年换,ui与用户的交互,避免页面的重新加载
优点:
用户体验好,快,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染
Spa相对于服务器压力小
前后端职责分离,结构清晰,前端进行交互逻辑,后端负责数据处理
缺点:
初次加载耗时多,因为是一个单页面应用,所以不能使用浏览器的前进后退功能,所有的页面切换需要自己建立堆栈管理
Seo难度大,所有的内容都在一个页面中动态的替换显示,seo存在弱势
首屏时间:指的就是浏览器从响应用户输入网址地址,到首屏内容渲染完成的时间,此时的整个网页不一定要全部渲染完成,但是需要展示当前视窗需要的内容,首屏加载可以说是用户体验中最重要的环节
首屏加载速度慢的原因:
网络延时问题
资源文件体积是否过大
资源是否重复发送请求去加载
加载脚本的时候,渲染内同堵塞了
解决方案:
减小入口文件体积:常用的手段是路由懒加载,把不同的路由对应的组件分割称不同的代码块,
静态资源本地缓存:http缓存,离线缓存
Ui框架按需引入:elementui antd
图片资源的压缩:适当对图片进行压缩
组件重复打包:在webpack的config文件中,修改CommonsChunkPlugin的配置
开启Gzip压缩
使用ssr:服务器端渲染,
通过改变url,在不重新请求页面的情况下,更新页面视图,目前有两种路由模式
一般路由中,都会用到window.history和window.hash
History对象包含浏览器的历史,history对象在编写时可以不使用window这个前缀
History时实现spa前端路由中的一种主流方法:back() forward() go()push()
History interface 是浏览器历史记录栈提供的接口,通过back()、forward()、go()等方法,我们可以读取浏览器历史记录栈的信息,进行各种跳转操作。
Hash:
直接更改浏览器地址,在最后面增加或改变#hash
通过改变location.href或location.hash的值
通过触发瞄点链接
浏览器的前进后退可能导致hash改变,前提是两个网页地址中hash值不同
Hash实现spa前端路由代码
Hash的作用是加载url种指示网页中的位置,
特点:hash虽然在url中,但是不会被包括在http请求中,他是用来指导浏览器动作的,对浏览器安全无用,hash不会重新加载页面
每一次hash改变,都会在浏览器访问历史中添加一个记录
两种模式比较:
pushState设置的新URL可以是与当前URL同源的任意URL;而hash只可修改#后面的部分,故只可设置与当前同文档的URL
pushState通过stateObject可以添加任意类型的数据到记录中;而hash只可添加短字符串
pushState可额外设置title属性供后续使用
history模式则会将URL修改得就和正常请求后端的URL一样,如后端没有配置对应/user/id的路由处理,则会返回404错误
组件就是把图形,非图形的各种逻辑均抽象为一个统一的概念来实现开发模式,在vue中每一个文件都可以视为一个组件
组件的优势:降低整个系统的耦合度,调试方便,提高可维护性
插件:
插件通常是用来为vue添加全局功能,插件的功能范围没有严格限制,一般分为以下几种:
添加全局方法或者属性
添加全局资源
通过全局混入来添加一些组件选项,
添加一些实例方法
两者的区别?
编写形式:
组件有很多中编写方式,常见的是vue单文件的这种格式,每一个.vue文件就可以看成一个组件
还可以通过template属性来编写一个组件,如果组件内容多,可以再外部定义template
编写插件应该暴露一个install方法,这个方法的第一个参数是vue的构造器,第二个参数是可选对象
注册形式
组件注册分为全局和局部注册,,全局注册通过vue.component方法,
局部注册只需要在用到的地方通过component属性注册一个组件
插件通过vue.use方式注册,注册插件的时候,需要在调用new vue启动应用之前完成
使用场景
组件 (Component) 是用来构成你的 App 的业务模块,它的目标是 App.vue
插件 (Plugin) 是用来增强你的技术栈的功能模块,它的目标是 Vue 本身
简单来说,插件就是指对Vue的功能的增强或补充
组件是vue最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同的组件之间的数据无法进行直接的引用,所以组件之间相互通信非常重要
Props/$emit:父组件通过props向子组件传递数据,子组件通过$emit和父组件进行通信
$emit/$on这种方法是通过一个空的vue的实例作为中央事件总线,用它来触发事件和监听事件,巧妙而轻量的实现任何组件之间的通信,包括父子,兄弟,跨级
Vuex:vuex实习了一个单项的数据流,在全局state中存放数据,当组件要更改state中的数据时,必须通过mutation进行,mutation同时提供了订阅者模式供外部插件调用获取state中数据的更新,而当所有的异步操作或者批量的同步操作需要走action时,action也无法直接修改state,还是需要mutation来修改state的数据,最后,通过state的改变,渲染到视图
Provide/inject允许一个组件组件向其后代所有的子孙注入一个依赖,不论层级多有深,并在上下游关系成立的时间里始终生效,组件组件通过provide来提供变量,然后后代子孙组件通过inject来注入变量
Vue引入diff算法的由来,是因为vue2中为了降低watcher力度,每个组件中只有一个watcher与之对应,所以引入diff算法进行精确的找到变化的地方
Vue中的diff执行的时刻时组件实例执行其更新函数时,他会对比上一次渲染的结果和新的渲染结果进行对比,此过程称为patch
Diff的过程整体遵循深度优先,同层比较的策略,两个节点之间会根据它们是否拥有子节点或者文本节点然后做不同的操作,比较两组节点时算法的重点,
diff算法是一种通过同层的树节点进行比较的高级算法
有两个特点:
比较只会在同级层中进行,不会跨级比较
在diff比较的过程中,循环从两边向中间比较
比较方式:
Diff整体策略为:深度优先,同层比较
比较只会在同层级进行,不会跨层级比较
比较的过程中,循环会从两边向中间收拢
虚拟dom这个概念大家都不陌生,从react到vue,虚拟dom为这两个框架都带来了跨平台的能力
实际上他只是真实dom的一层抽象,以js对象为基础的树,用对象的属性来描述节点,最终可以通过一系列的操作使这颗树映射到真实环境上
在js对象中,虚拟dom表现为一个onject对象,并且最少包含了签名,属性和子元素着三个属性,不同的框架对着三个属性可能会有差别
虚拟dom的好处:
虚拟dom比真实的dom体积小,操作是相对来说消耗性能少,如果在页面中删除一个dom。会引起重绘,影响后面的布局
虚拟dom不会进行重绘和回流操作
虚拟dom进行频繁的修改,然后一次性的比较并修改真实dom中修改的一部分,最后在真实dom中进行重绘和回流,减少过多dom节点回流和重绘
虚拟dom可以跨域,跨平台,
Vue3的最大设计目标就是替换vue2,为了实现这一点,vue3在以下几个方面做了很大的改进
易用性方面主要是api简化,比如v-model在vue3中变成vue2中的v-model和sync修饰符的结合体,用户不用区分两者的不同,也不用选择困难,类似的简化还有用于渲染函数内部生成的vNode,其中props不用考虑区分属性、特性和事件等
开发体验,新组建Teleport传送门,Fragments都会简化特定场景的代码编写,
扩展性:提升了独立的模块
可维护性,更容易编写高可复用性的业务逻辑
性能提升的方面也很显著,编译期优化,基于proxy的响应式系统等,通过数据劫持的方式进行代码优化
Composition Api是vue3最大的特点,通常在vue2开发项目中,会存在以下问题
代码的可读性会随着组件变大而变差
每一种代码复用的方式,都会存在缺点
Typescript支持有限,以上问题通过compositon API都会迎刃而解
Options Api,就是大家常说的选项api,以vue为后缀的文件,通过定义methods、component、watch、data等属性和方法,共同处理页面逻辑
他们的区别主要体现在两大方面
逻辑组织:逻辑复用:
在逻辑组织和逻辑复用方面,componsition api是优于Options Api
因为composition Api几乎是函数,会有更好的类型判断
Componsition Api对tree-shaking友好,代码也更加容易压缩
Compositon Api中见不到this的使用,减少了this指向不明的情况
如果是小型组件,可以继续使用option Api,也是十分友好
Vue的核心之一就包括了响应式系统,响应式,指的就是当数据发生改变后,vue会通知到使用该数据的代码
视图渲染中使用了数据,当修改state时,视图也会自动更新
Vue的响应式,核心机制就是观察者模式,数据是被观察的一方,当数据发生变化时,通知所有的观察者,这样观察者可以做出响应
数据可以有多个观察者,vue通过data和watcher间创建了一个dep对象,来记录这种依赖关系
Dep的结构很简单,除了唯一标识id,另一个就是用来记录所有观察者的subs
记录依赖关系的属性是deps,对应的是由dep对象组成的数组,对应所有依赖的数据
另外,还有一个重要的属性就是cb,记录回调函数,当getter属性返回的值和当前的value不同时被调用
Vue会分别创建对应的dep对象,用来记录依赖该数据的watcher
React是用于构建用户界面的js库,只提供了ui层面的解决方案
遵循组件设计模式,声明式编程范式和函数式编程概念,使前端应用程序更加高效
使用虚拟dom来有效的操作dom,遵循从高阶组件到低阶组件的的单项数据流
帮助我们将界面分成各个独立的小块,每一个块就是组件,这些组件可以组合嵌套,构成整体的页面
React类组件使用一个名为render的方法或者函数组件return,接收输入的数据并返回需要展示的页面
React有许多特性:
Jsx语法
单项数据绑定
虚拟dom
声明式编程
Component
React存在的优势:
高效灵活
声明式的设计,简单使用
组件式开发,提高代码复用率
单向响应的数据流会比双向绑定更加安全,速度更快
虚拟dom不会进行排版和重绘,真实dom会频繁的排版和重绘
虚拟dom的总损耗式虚拟dom的增删改+真实dom差异增删改+排版和重绘,真实dom的总损耗是:真实dom完全增删改+排版和重绘
优缺点:
真实dom:
优点:直接操作dom,易用
缺点:解析速度慢,效率低,内存占用量高,性能差,频繁的操作真实dom,容易导致重绘和回流
虚拟dom:
优点:减少真实dom的频繁更新,减少重绘和回流
内存占用少,跨平台,一套代码多端运行
缺点:页面首次渲染时,由于多了一层虚拟dom的计算,速度比正常慢一点
React生命周期主要分为三个阶段:创建阶段更新阶段,卸载阶段
componentWillMount:组件将要被构建
Render:渲染组件
componentDidMount:组件构建完成
componentWillReceiveProps:组件将要被接收新的属性数据
shouldComponentUpdate:判断组件是否应该更新
compoinentWillUpdate:组件将要更新
Render:渲染组件
componentDidUpdate:组件更新完成
componentWillUnmount:组件将要被销毁
在react生命周期中,即将有三个钩子函数被淘汰,他们分别时componentWillMount和componentWillReceiveProps和componentnWillUpdate
其实这三个方法仍然存在,只要在前者加上UNSAFE前缀,同时增加两个新的生命周期钩子
getDerivedStateFromProps getSnapshotBeforeUpdate
setState是同步执行的,但是state并不一定会同步更新
一个组件的显示形态可以由数据转来和外部参数决定,而数据的状态就是state
当需要修改里面的值的装态需要通过setState来修改,从而达到更新组件内部数据的作用
在更新时,setState分为同步更新和异步更新
同步更新:在setTimout或操作原生dom事件中,是同步更新
在组件生命周期或react合成事件中,setState是异步
函数组件是一个纯函数,他接收一个props对象返回一个react元素,类组件需要去继承React.Component并且创建render函数返回react元素,函数组件没有生命周期和状态state,而类组件有
函数组件也称无状态组件,顾名思义就是以函数形态存在的react组件,在hooks出自按之前,react中函数组件通常只考虑ui渲染,没有自身的状态,没有业务逻辑,是一个纯函数 ,他的输入的数据完全是由参数props决定,不受任何因素的影响
类组件就是居于es6语法,通过继承React.component得到的组件,类组件有自己的状态,可以通过state自己管理自己的数据,在state中定义数据,然后渲染到页面,通过setState进行修改state的状态
差异:
类组件有生命周期,函数组件没有
类组件需要继承class,函数组件不需要
类组件可以获取实例化的this,并且基于this做各种操作,函数组件不行
类组件内部可以定义state并进行维护,函数组件是无状态组件,没有this指向,没有state
函数组件跟类组件进行比较,函数更加轻量高效,便于逻辑的拆分和复用
在react中,我们一般使用函数组件比类组件使用的多,因为函数组件比类组件更加灵活简便,便于逻辑的拆分和使用,但是函数组件是无状态组件,没有state,在没有hooks之前,函数组件主要是用来渲染页面的,而他的数据来源于我们props传递过来的数据,而hooks的出现就是为了解决函数组件没有state这一问题
我们常见的hooks有许多
useState:跟类组件中state类似,方便我们定义初始化的数据,接收两个参数,一个是初始化数据,另一个是修改数据的方法
useEffect:副作用函数,只有使用之后,render之后触发,才会产生副作用,他接受两个参数,一个是函数,另一个是要监听的数据,可以是[],表示只执行一次,也可以传参,传参之后只要当我们的数据发生变化时才会触发,如果不写,那么发生一次变化就会执行一次
useMemo:数据缓存,rener之前触发,当我们进行组件通信时,如果我们父组件中的数据发生变化,那么我们的子组件也会随着进行更新,不管我们更新的数据是否跟我们的子组件的数据有关系,他都会进行更新操作,这时候,就会存在更新性能的浪费,我们可以使用ysememo来进行缓存,减少不必要的更新操作,他的缓存的参数是一个字符串,如果是一个函数的话,那么我们的usememo就会失效,这时候就需要使用useCallback进行数据的缓存操作
useRef:可以监听我们的输入框数据的变化,获取输入框中的值
React是用于构建用户界面的,帮助我们解决渲染dom的过程
每个组件的state都是由自身进行管理,包括组件定义自身的state,组件之间的通信通过props传递,通过context实现数据共享
如果我们让每个组件都自己管理自身的状态,不会影响应用的运行,但是在后续开发过程中和维护中,我们需要花费大量的精力去查询状态的变化过程
Redux遵循三大原则:
必须是单一的数据源
State必须是只读的,不能修改,只能通过action中的dispatch进行修改
Reducer必须是纯函数
工作原理:
Redux要求我们把数据都放在store中公共存储空间,一个组件改变了store中的数据内容,其他组件就能感知store中的变化,再来取数据,从而实现数据的传递
我们通过getState获取store中的数据,然后同伙action中的dispatch进行修改,把修改后的数据传到reducer中,reducer把数据传递store,然后再渲染到页面
1、使用纯组件;
2、使用 React.memo 进行组件记忆(React.memo 是一个高阶组件),对 于相同的输入,不重复执行;
3、如果是类组件,使用 shouldComponentUpdate(这是在重新渲染组件之前触发的其中一个生命周期事件)生命周期事件,可以利用此事件来决定何时需要重新渲染组件;
4、路由懒加载;
5、使用 React Fragments /ˈfræɡmənts/
避免额外标记;
6、不要使用内联函数定义(如果我们使用内联函数,则每次调用“render”函数时都会创建一个新的函数实例);
7、避免在Willxxx系列的生命周期中进行异步请求,操作dom等;
8、如果是类组件,事件函数在Constructor中绑定bind改变this指向;
9、避免使用内联样式属性;
10、优化 React 中的条件渲染;
11、不要在 render 方法中导出数据;
12、列表渲染的时候加key;
13、在函数组件中使用useCallback和useMemo来进行组件优化,依赖没有变化的话,不重复执行;
14、类组件中使用immutable对象;
Angular 是一个应用设计框架与开发平台,用于创建高效、复杂、精致的单页面应用。
提供非常干净和维护方式来创建单页应用,可进行单元测试,使用依赖注入和利用关注点分离,可重用组件,视图都是存html页面,并且用js编写业务处理
React 是一个用于构建用户界面的 JavaScript 库,灵活性可响应能力,组件化开发模式,单项数据流,使用虚拟dom提供跨域支持
Vue 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
模板和渲染函数的弹性选择,简单的语法和项目配置,更快的渲染速度和更小的体积,生命周期
三者比较
相同点
1. 都是基于javascript/typescript的前端开发库,为前端开发提供高效、复用性高的开发方式
2. 都有组件和模板的开发思想
3. 各自的组件都有生命周期,不用的组件可以卸载,不占用资源
4. 都支持指令,如样式、事件等的指令
不同点:
创始和发行不同:angular是由googl提供支持,初始发行于2016年9月,react是由facebook维护,初始化于2013年3月,vue是由google人员船舰,初始发行于2014年2月
Angular支持开发native应用程序,spa单页应用程序,混合应用程序和web应用程序,react支持开发spa和移动应用程序,vue支持开发高阶spa,
模型不同:angular基于mvc,react和vue基于Virtual Dom
数据流流向不同:angular使用的是双向数据绑定,react是单项数据流,vue两项都支持
框架和库:angular是一个框架而不是一个库,因为它提供了关于如何创建应用程序的强有力的约束,并且提供了开箱即用的功能,react和vue是一种库,可以和各种包搭配使用
Ts是microsoft开发和维护的一种面向对象的编程语言,他是js的超集,包含了js所有的元素,可以载入js代码运行,并扩展js的语法,ts有以下几个特点:
增加了进来类型,类,模块,接口和类型注释
更加适合开发大型的应用
区别:
Ts从核心语言方面和类概念的模塑方面对js对象模型进行扩展
Js代码可以在无需任何修改的情况下于ts一同工作,同时可以使用编译器将ts转换为js
Ts通过类型注释提供编译时的静态类型检查
Ts中的数据要求带有明确的类型,js不要求
Ts为函数提供了缺省参数值
Ts引入了js中没有类的概念
Ts中引入了模块的概念,可以把声明,数据函数和类封装在模块中
是一种程序设计语言的一种风格或是范式
泛型允许我们在强类型程序设计语言中编写代码时使用一些以后才指定的类型,在实例化时作为参数指明这些类型,在ts中,定义函数、接口或者类的时候,不预先定义好具体的类型,而在使用的时候指定类型的一种特性
泛型的真正意义时可以让一个组件、方法支持多种类型的数据
设计泛型的关键目的时在成员之间提供有意义的约束,这些成员可以是:类的实例成员,类的方法,函数 参数和函数的返回值
应用场景:
在ts中,在定义函数、接口或者类的时候,不预先定义好具体的类型,而在使用的时候指定类型的一种特性的时候,这种情况下就可以使用泛型
2017年,微信正式推出了小程序,允许外部开发在微信内部运行自己的代码,开展业务
截至目前,小程序已经成为国内前端的一个重要的业务,跟web和手机app有着同等的重要性
小程序是一种不需要下载安装即可即用的应用,它实现了触手可及的梦想,用户扫一扫或者搜一下就可以打开应用
用户不需要关心安装太多应用的问题,应用无处不在,随时可用,无需安装
除了微信小程序外,还有支付宝小程序、抖音小程序、百度小程序,都是每个平台自己开发的
优点:
是一种不需要下载就可以使用的应用,即用即走
开启速度和运行速度非常快
入门门槛低
缺点:
源码打包不超过2m
不能随时随地的上线,因为需要微信团队审核
暂时不能分享到朋友圈
个人账号限制非常大,很多功能无法实现
观察这模式定义了对象之间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都将会得到通知,并自动更新
观察者模式属于行为型模式,行为型模式关注的时对象之间的通讯,观察者模式就是观察者和被观察者之间的通讯
例如在生活中,我们可以使用报纸期刊来形象的说明,当订阅一份报纸,每天都会有一份最新的报纸送到你手上,有多少人订阅报纸,报社就会发多少分报纸,报社和定报者之间就形成了一对多的依赖关系
发布订阅模式
发布订阅是一种消息范式,消息的发送者称为发布者不会将消息直接发送给特定的接收者,而是将发布的消息分为不同的类型,无需了解哪些订阅者可能存在
同样的,订阅者可以表达一个或多个类别的兴趣,只接收感兴趣的消息,无需了解哪些发布者的存在
区别:
观察者:某公司给员工发月饼,是由公司的行政部门发送的,这件事不适合交给第三方,原因是公司和员工是一个整体
发布订阅:某公司要给其他人发各种快递,因为公司和其他人是独立的,其唯一的桥梁就是快递,所以这件事适合交给第三方快递来解决
在观察者模式中,观察者是知道subject的,subject一直保持对观察者进行记录,然而,在发布订阅模式中,发布者和订阅者不知道对方的存在,他们只有通过消息进行通信
在发布订阅模式中,组件是松散耦合的,正好和观察者模式相反
观察者模式在大多时候是同步的,比如当事件触发,subject就会去调用观察者的方法,而发布订阅模式在大多时候是异步的
减少http请求数量,加载进行优化,数据优化
压缩源码和图片
源码优化
选择合适的图片格式
项目打包优化
合并静态资源
开启服务器端的Gzip压缩
使用cdn
延长静态资源缓存时间
把css放在页面头部,把js放在页面底部
解析heml构建的dom树,并请求css/image/js
Css文件下载完成,来时构建cssom
Cssom构建结束之后和dom一起生成render Tree(渲染树)
布局,计算出每个节点在屏幕中的位置,显示通过显卡把页面画到屏幕中
Dom树和渲染树的区别:
Dom树与html标签一一对应,包括head和隐藏元素
渲染树不包括head和隐藏元素,大段文本的每一个行都是独立节点,每一个节点都有对应的css属性
高复用低耦合,这样的文件下,好维护,可扩展
具有可用型,健壮性,可靠性,宽容性等特点
遵循设计模式的六大原则
代码可读性好,容易理解,容易维护,别人接手不骂你
首先,在浏览器地址栏输入url
浏览器现查看浏览器缓存,系统缓存-路由器缓存,如果缓存中有,会直接在屏幕中显示页面内容,如果没有,则跳到第三步操作
在发送http请求前,需要域名解析,解析获取响应的ip地址
浏览器向服务器发送tcp链接,与服务器建立tcp三次握手
握手成功后,浏览器向服务器发送http请求,请求数据包
服务器处理收到的请求,将数据返回至浏览器
浏览器收到http响应,根据情况选择关闭tcp链接或者保留重用
如果得到的资源可以缓存,进行缓存
读取页面的内容,浏览器渲染,解析html源码
生成dom树,解析css样式,js交互
Ajax异步处理,可以在不重新加载整个网页的情况下,对网页的某部分进行更新
http请求报文主要是由请求行,请求头部和请求正文三部分组成
请求行用于描述客户端的请求方式,请求的资源名称,以及使用的http协议版本号
消息头用于描述客户端请求的哪台主机,以及客户端的一些环境信息等
请求正文,是可选部分,get,post请求体中存放的是表单提交的键值对,例如json格式
状态行分为:协议版本,状态码,状态码描述,之间由空格组成
状态码由三位数字组成,顶一个数字定义了响应的类别,由五种取值
1xx:指示信息,表示请求已经接收,继续处理
2xx成功,表示请求已经被成功接收,理解,接受
3xx重定向:要完成请求需要进一步的操作
4xx客户端错误,请求由语法错误或请求无法实习那
5xx服务端错误,服务器未能实习那合法的请求
常见的状态码有:
200:请求成功
301:永久重定向,搜多引擎将删除源地址保留重定向地址
302:展示重定向,重定向地址由响应头中location属性指定
304:缓存文件并未过期,可以继续使用,无需在次重故武器获取
400:客户端请求有语法错误,不能被服务器辨识
403:服务器接受到请求,但是拒绝提供服务
404:请求资源不存在
500:服务器内部错误
Session:客户端a访问服务器,服务器存储a的数据value,把key返回给客户端,客户端a下次带着key来访问服务器,服务器就能给出客户端a的数据,如果负载均衡,客户端a访问了另一个服务器,那么服务器没有客户端a的数据
Cookie:客户端a访问服务器,服务器返回cookie给客户端a,客户端a存储cookie,下次需要带着cookie访问服务器,服务器返回相应的数据
Token令牌:客户端a访问服务器,服务器给了客户端token,客户端a拿着token访问服务器,服务器验证token,返回数据
Token是服务器生成的一串字符串,用来作为客户端请求的一个令牌,当第一次登录成功后,服务器生成token返回给客户端,以后客户端只需要带上token进行请求数据即可,不需要带上用户名和密码进行请求
区别:
Session和cookie的区别:
数据存放位置不同,session数据存放在服务器中,cookie数据存放在浏览器中
安全程度:cookie放在服务器中不是很安全,session存放在服务器中,相对安全
性能使用程度:session放在服务器上,访问增多会占用服务器的性能,考虑到减轻服务器性能方面,使用cookie
数据存储大小,cookie保存的数据不超过4k,session存储在服务端,大小根据服务器决定
Token和session的区别:
Token是开发定义的,session是http协议规定的
Token不一定春初,session存放在服务中
Token可以跨域,session不可以跨域,他和域名是绑定的
跨域资源共享是一种机制,它允许浏览器向跨域服务器发出xmlhttpReuqest或者fetch请求,并且整个cors通信过程都是浏览器自动完成的,不需要用户参与,
这种跨域资源共享的前提是,浏览器必须支持这个功能,并且服务器也必须同意这种跨域请求,因此实现cors的关键是服务器
Cors需要浏览器和服务器同时支持,目前,所有的浏览器都支持该功能,ie浏览器不能低于IE10
跨域产生的原因是浏览器的同源策略的限制,由于我们的端口+域名+协议不同,从而产生的跨域
古老的跨域,jsonp,他只能发送get请求,他发送的不是ajax请求,而是利用script标签加载机制,
Cors的请求分为两类:简单请求和非简单请求,
对于简单的请求,浏览器直接发出cors请求,具体来说,就是在头信息中,增加了一个origin字段,
非简单请求是那种对服务器有特殊要求的请求,比如请求方法是put或者是delete,非简单的请求,会在正式通信前,增加一次http查询请求,称为预检请求
浏览器现询问服务器,当前网页所在的域名是否在服务器的许可名单中,以及可以使用哪些htto动词和头信息字段,只有得到肯定的答复,浏览器才会正式发出xmlHttpRequest请求,否则会报错
Mvvm是一种设计思想,是model view viewmodel的缩写
View是视图层,也就是用户界面,前端只要是由html和css构建
Mode层指的是数据模型,泛指后端进行的各种业务逻辑处理和数据操控,对于前端来说就是后端提供的api接口
Viewmodel层是视图数据层,一个同步的view和mode的对象
在mvvm框架下,view和mode之间没有直接的联系,而是通过viewmodel进行交互,model和viewmodel之间的交互是双向的,因此view数据的变化会同步到model中,而model数据的变化也会反应到view上
viewModel通过双向数据绑定把view和model层链接起来,而view和mofel之间的同步工作完全是自动的,无需人为干涉,因此开发者只需要关注业务逻辑,不需要手动操作dom,不需要关注数据状态的同步问题,复杂的数据状态维护完全由mvvm来统一管理
版本控制,是维护工程蓝图的标准做法,能追踪工程蓝图从诞生到一直定案的过程,此外版本控制也是一种软件工程技巧,借此能在软件开发过程中,确保由不同人所编辑的同一程序文件都能得到同步
透过文档控制,能记录任何工程项目内各个模块的改动历程,并且为每次改动编上序号
版本控制能提供项目的设计者,将设计恢复方法哦之前任以状态的选择权
版本控制系统可以分为本地版本控制系统,集中式版本控制系统,分布式版本控制系统
本地版本控制系统:
优点:简单很多系统中有内置,适合管理文本如系统配置
缺点:不支持远程操作,因此不适合多人版本开发
集中式版本控制系统:
优点:适合多人团队协作开发,代码集中化管理
缺点:单点故障,必须联网,无法单机工作
分布式版本控制:
优点:适合多人团队协作开发,代码集中化管理,可以离线工作,每个计算机都是一个完整的仓库
版本管理工具有
Git,世界上最先进的分布式版本控制系统
Hg免费的分布式源代码管理工具
Git式一个分布式版本管理控制软件,最初的目的式为了更好的管理linux内核开发而设计的
分布式版本控制系统的客户端并不只提取最新版本的文件快照,而是把代码仓库完整的镜像下来,这么一来,任何一处协同工作用的服务器发生故障,时候都可以用任何一个镜像出来的本地仓库恢复
Git可以实现团队协作,只有一台电脑充当服务器的角色,其他的每个人都从这个服务器仓库clone一份到自己的电脑上,并且把各自的提交到服务器仓库中,也从服务器仓库中拉取别人的提交
Github实际上就可以充当这个服务器的角色,他是一个开源的协作社区,提供git仓库托管服务,既可以让别人参与你的开源项目,也可以参与别人的开源项目
Git有四个部分组成:工作区,暂存区,本地仓库、远程仓库
Git push --force 强制推送
Git init 初始化
Git clone 地址 克隆远程仓库
Git clone -b 分支名 地址 克隆分支的代码到本地
Git status 查看状态
Git add 文件名 将某个文件存入暂存区
Git checkout --file 撤销工作区的修改
Git add . 将所有文件提交到暂存区
Git commit -m提交到仓库
Git stash -u -k 提交部分文件到仓库
Git commit -m 添加备注信息、
Git log 文件名 查看该文件的提交
多个分支代码合并到一个分支
多个分支向同一个远端分支推送分支
冲突发生的原因是我们在同一个文件的同一行代码中添上了不同的代码,那么他就会产生冲突
解决冲突最好的办法就是手动的解决冲突,把我们想要留下的代码进行保留,不想要的代码进行删除
也可以在当前分支上,直接修改冲突代码 add--commot
在本地房前分支上,修改冲突代码 add --commit--push
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。