5月份换了工作,整理了一些面试题,记录一下。
如有不太准确或者错的地方,记得cue我
它不是html标签,它为浏览器提供一种信息声明,告诉浏览器html是用什么版本编写的,用来表示html的版本
新增用于绘画的’canvas’元素
用于媒介回放的video和audio元素
本地缓存有更好支持(localStorage和sessionStorage)
块级元素: div、form、table、p、h1-h6、dl、li、ul、ol等
内联元素: a、strong、br、img、i、span、label、input、textarea、select等
flex布局:弹性布局,设置间距相同的布局、单行单列布局的时候相当好用,设置display:flex的时候,子元素的float、clear、vertical-align属性都将全部失效
容器属性:
属性 | 作用 | 值 |
---|---|---|
flex-direction | 设置主轴的排列方向,有 row(竖直向下排列) | row(竖直向下排列)、row-reverse(竖直向上排列)、column(垂直向右排列)、column-reverse(垂直向左排列) |
flex-wrap | 设置是否排列在一条线上 | nowrap、wrap和warp-reverse三个选项 |
flex-flow | flex-direction和flex-wrap | |
justify-content | 定义项目在主轴上的对齐方式 | flex-start, flex-end , center ,space-between ,space-around |
align-items | 定义交叉轴的对齐方式 | flex-start ,flex-end , center , baseline , stretch |
项目属性:
属性 | 作用 |
---|---|
align-self | 改项目的对齐方式 |
order | 改项目的对齐方式 |
flex-grow | 项目放大比例 |
flex-shrink | 项目缩小比例 |
flex-basis | 在分配多余空间时,项目占据的主轴空间 |
方法 | 作用及使用方法 |
---|---|
toUpperCase | 把小写字母转成大写 |
toLowerCase | 把大写转小写 |
charAt | 通过索引获取字符 |
charCodeAt | 通过索引获取对应字符的Unicode编码 |
substr(startIndex,length) | 第二个参数是截取字符串的长度(从起始点截取某个长度的字符串),eg:let str = ‘hello’ console.log(str.substr(0, 4)) // hell |
substring(startIndex, endInde) | 第二个参数是截取字符串最终的下标 (截取2个位置之间的字符串,‘含头不含尾’)eg:let str = ‘hello’ console.log(str.substring(0, 4)) // hell |
slice(m,n) | string.slice(start,end)从索引start开始,截取到索引end,不包含end (支持负数) ,返回一个新的字符串(一般不用) |
split(separator,howmany) | 以某个字符串分割成数组 eg:let str = ‘h,e,llo’ console.log(str.split(",", 3)) // [“h”, “e”, “llo”] console.log(str.split(‘hah’)) // [“h,e,llo”] |
indexOf | 检测字符在字符串中第一次出现的索引位置; 不存在为-1 |
lastIndexOf | 检测字符在字符串中最后一次出现的索引位置 |
replace(regexp,str) | 替换;原有字符串不变;用新字符替换旧的字符 eg:str="Visit Microsoft!"str.replace(/Microsoft/, “W3School”) |
concat() | 拼接 |
trim | 去空格 : 去除字符串中左右的空格 |
方法 | 作用及使用方法 |
---|---|
join | 就是把数组转换成字符串,然后给他规定个连接字符,默认的是逗号( ,) |
push() | 尾插入 |
pop() | 尾出 |
shift() | 头删 |
unshift() | 头插 |
sort() | 将数组里的项从小到大排序 |
reverse() | 反转数组项的顺序 |
concat() | 将参数添加到原数组中 |
slice() | 返回从原数组中指定开始下标到结束下标之间的项组成的新数组。但不包括结束位置的项 |
splice(开始位置, 删除的个数,元素) | 删除:指定 2个参数:要删除的第一项的位置和要删除的项数。书写格式:arr.splice( 1 , 3 )插入:可以向指定位置插入任意数量的项,只需提供 3 个参数:起始位置、0(要删除的项数)和要插入的项。书写格式:arr.splice( 2,0,4,6 )替换:可以向指定位置插入任意数量的项,且同时删除任意数量的项,只需指定 3 个参数:起始位置、要删除的项数和要插入的任意数量的项。插入的项数不必与删除的项数相等。书写格式:arr.splice(1,1,2,4)let arr = [1, 2, 3, 4]arr.splice(0,2)// [3,4]删除arr.splice(2, 0,4) //[1, 2, 4, 3, 4] 增加arr.splice(1,1,8) //替换 |
indexOf() | 接收两个参数:要查找的项和(可选的)表示查找起点位置的索引。其中, 从数组的开头(位置 0)开始向后查找。书写格式:arr.indexof( 5 ) |
lastIndexOf | 接收两个参数:要查找的项和(可选的)表示查找起点位置的索引。其中, 从数组的末尾开始向前查找。 书写格式:arr.lastIndexOf( 5,4 ) |
基本数据类型: Number(NaN 是 Number 中的一种,Number 中的特殊数值)、String、Boolean、undefined、Null,symbol
引用数据类型:object(包含Data、function、Array等)
Typeof检测数据类型:
number、string、boolean、undefined、object、function
typeof不能分辨出来是对象还是数组。
强制(parseInt、parseFloat、number)
隐式(== ===)
函数声明在js解析时就会进行函数提升,因此在同一作用域中,不管函数声明在哪定义,该函数都可以调用,函数表达式只有在执行到那一块后,才可以调用 函数对象
举例:
function add () {
//类数组对象
console.log(typeof arguments); //object
console.log(arguments); //[10 , 20 ,callee:f, symbol:f]类数组对象
console.log(arguments.length) //2
}
add(10,20);
add.length; //0
计算机是通过二进制来存储东西, 0.1 在二进制中是无限循环的一些数字,其实不只是 0.1,其实很多十进制小数用二进制表示都是无限循环的。循环数字被裁剪后失去精度。
解决办法:parseFloat((0.1 + 0.2).toFixed(10)) === 0.3 // true
那么可能你又会有一个疑问,既然 0.1 不是 0.1,那为什么 console.log(0.1) 却是正确的呢?
因为在输入内容的时候,二进制被转换为了十进制,十进制又被转换为了字符串,在这个转换的过程中发生了取近似值的过程,所以打印出来的其实是一个近似值,你也可以通过以下代码来验证
console.log(0.100000000000000002) // 0.1
箭头函数的this绑定看的是this看函数定义在哪个对象下,就绑定哪个对象。如果有嵌套的情况,则this绑定到最近的一层对象上this指向的固定化,并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,导致内部的this就是外层代码块的this。正是因为它没有this,所以也就不能用作构造函数。
怎么改变this的指向呢?
1.使用es6的箭头函数;
2.在函数内部使用that = this;
3.使用apply,call,bind;
4.new实例化一个对象
闭包是JavaScript的优秀的特性,指的是一个函数可以记忆住定义时所处的作用域,即使这个函数不在定义时所处的作用域运行,它依然能够访问定义时作用域的变量。
最常见的闭包演示就是一个外部函数return了一个内部函数。被return的这个内部函数,放到了全局作用域下运行,依然可以得到当初定义时外部函数中的变量。
工作中,经常使用闭包实现私有化封装。比如一个变量,我们不希望它能够自由的被更改,而是按照某些API函数更改,此时可以将这个变量放入一个外部函数中,这个外部函数return一些操作这个变量的函数,就是一些API。这样要向访问或者更改这个变量,必须通过暴露出的API,别无他法,达到了私有化封装的目的,也实现了可预测,提升了安全性。除此之外外,我们还可以用闭包实现批量为元素添加监听。
闭包的缺陷:
1.闭包的缺点就是常驻内存会增大内存使用量,并且使用不当容易造成内存泄漏
3:闭包只能获取到外部函数中任何变量的最后一个值
4:this对象的指向可能与预期的不一致
es5:son.prototyp= new Father()student.protype
ES6 : son extends father
重点:让新实例的原型等于父类的实例。
特点:实例可继承的属性有:实例的构造函数的属性,父类构造函数属性,父类原型的属性
缺点:
1、新实例无法向父类构造函数传参。
2、继承单一。
3、所有新实例都会共享父类实例的属性。
重点:用.call()和.apply()将父类构造函数引入子类函数
特点:
1、只继承了父类构造函数的属性,没有继承父类原型的属性。
2、解决了原型链继承缺点1、2、3。
3、可以继承多个构造函数属性(call多个)。
4、在子实例中可向父实例传参。
缺点:
1、只能继承父类构造函数的属性。
2、无法实现构造函数的复用。(每次用每次都要重新调用)
3、每个新实例都有父类构造函数的副本,臃肿。
重点:结合了两种模式的优点,传参和复用
特点:
1、可以继承父类原型上的属性,可以传参,可复用。
2、每个新实例引入的构造函数属性是私有的。
缺点:调用了两次父类构造函数(耗内存),子类的构造函数会代替原型上的那个父类构造函数
事件流描述的是从页面中接受事件的顺序,事件捕获阶段-> 处于目标阶段-> 事件冒泡阶段
DOM0级事件【onxxx】
DOM0级事件如有某一个元素添加某一个事件多次【后者覆盖前者】
谁触发事件,函数的上下文就是谁
没有兼容问题,只有冒泡阶段
DOM2级事件【addEventListener】
div.addEventListener(eventType,callBack,布尔值);
参数 | 作用 |
---|---|
eventType | 事件类型【不加on,如单击,双击…】 |
callBack | 回调函数【事件处理函数】 |
布尔值 | 布尔值【true-捕获阶段 ,false-冒泡阶段,默认为false】 |
有兼容性问题,第三个参数与可以省略,默认false-冒泡阶段
某一个元素多次添加某一类型事件多次【依次完成、不会后者覆盖前者】
场景 | 写法 |
---|---|
低版本IE浏览器移除事件 | div.detachEvent(“onclick”, 要移除的函数名); |
DOM0级移除事件 | div.onclick = null; //置空 |
DOM2级移除事件 | div.removeEventListener(“mouseenter”,要移除的函数名); |
哪些事件不支持冒泡事件:
鼠标事件:mouserleave mouseenter
焦点事件:blur focus
UI事件:scroll resize
阻止默认事件
JS当中对象分为两种:
第一种就是狭义对象【就是大花括号,普通对象】
第二种对象就是广义对象;
new操作符创建了一个空对象,这个对象原型指向构造函数的prototype,执行构造函数后返回这个对象(return this)。
1:当构造函数用关键字new执行的时候;函数的上下文指向了一个空的狭义对象
2:可以给狭义对象动态的添加属性、方法
3:虽然构造函数没有关键字return,但是系统自动将狭义对象返回
4:当前这一次的函数返回狭义对象之后,函数上下文和这一次的狭义对象没有任何关系了;
注意:我们经常管构造函数叫做类【People类】,将返回的狭义对象【类的实例】
若手动添加return发生了什么?
1:return之后的语句不执行
2:返回的不再是狭义对象
( ) 函 数 是 j Q u e r y ( ) 函 数 的 别 称 , 批 量 选 择 可 以 使 用 c l a s s , 标 签 选 择 如 () 函数是 jQuery()函数的别称,批量选择可以使用class,标签选择如 ()函数是jQuery()函数的别称,批量选择可以使用class,标签选择如(‘div’)
$(document).ready()函数: ready()
函数用于在文档进入ready状态时执行代码。当DOM 完全加载(例如HTML被完全解析DOM树构建完成时)
window.onload 事件和 jQuery ready 函数区别:
window.onload事件等待 DOM 被创建还要等到包括大型图片、音频、视频在内的所有外部资源都完全加载,可能会有明显延迟。
ready() 函数只需对 DOM 树的等待,而无需对图像或外部资源加载的等待,从而执行起来更快。
jQuery 事件处理程序里返回了 false会阻止事件向上冒泡
document.getElementbyId(“myId”) 比 $("#myId")高效,因为直接调用了 JavaScript 引擎
同源策略:
它是浏览器的一种约定,脚本只允许访问同一站点的资源,协议相同,域名相同,端口号相同,就是同一站点
原理:动态创建一个script标签。利用script标签的src属性不受同源策略限制, 因为所有的src属性和href属性都不受同源策略的限制,可以请求第三方服务器资源内容
步骤:
1.去创建一个script标签
2.script的src属性设置接口地址
3.接口参数,必须要带一个自定义函数名,要不然后台无法返回数据
4.通过定义函数名去接受返回的数据
WebSocket协议是HTML5一种新的协议。它实现了浏览器与服务器全双工通信,同时允许跨域通讯,Socket.io,它很好地封装了webSocket接口,提供了更简单,灵活的接口,也对不支持webSocket的浏览器提供了向下兼容
普通跨域请求:只服务端设置Access-Control-Allow-Origin即可,前端无须设置,若要带cookie请求:前后端都需要设置。
Promise 是异步编程的一种解决方案(解决回调黑洞):从语法上讲,promise是一个对象,从它可以获取异步操作的消息;从本意上讲,它是承诺,承诺它过一段时间会给你一个结果。promise有三种状态:pending(等待态),fulfiled(成功态then方法),rejected(失败态catch方法);状态一旦改变,就不会再变。创造promise实例后,它会立即执行。调用.then都会返回一个promise对象,这也是它可以连续打点使用的原因。
从表面上看,Promise只是能够简化层层回调的写法,而实质上,Promise的精髓是“状态”,用维护状态、传递状态的方式来使得回调函数能够及时调用
all的用法:将多个Promise实例包装成一个新的Promise实例,同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。Promise.all获得的成功结果的数组里面的数据顺序和Promise.all接收到的数组顺序是一致的
使用场景:Promse.all在处理多个异步处理时非常有用,比如说一个页面上需要等两个或多个ajax的数据回来以后才正常显示,在此之前只显示loading图标
race的用法:赛跑,谁跑的快,以谁为准执行回调Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。
transition:实现效果的属性名,过渡时间,过渡动画函数,是否延迟
animation:绑定的动画名称,动画时间,动画效果函数,延迟时间,执行多少次,是否可以反向执行动画
区别
1:transition需要改变状态才会随时间改变其CSS属性;
2:animation在不需要任何状态改变,也可以随时间变化来改变CSS属性。
3:transition是一次性,除非一直触发;animation可以设置循环次数或不停的执行动画
4:transition只能定义开始状态和结束状态,不能定义中间状态,只有两个状态。
animation通过控制keyframes(关键帧)来控制动画的每一步,类似flash的关键帧来 声明动画。(0%,10%,70%,100%),或(from,to)
1.使用flex
在父盒子设置display: flex; justify-content: center;align-items: center
2.使用css的transform
父盒子设置:display:relative
Div 设置: transform: translate(-50%,-50%);position: absolute;top: 50%;left: 50%;
3.display:table-cell (文字垂直居中)
父盒子设置:display:table-cell; text-align:center;vertical-align:middle;
Div 设置: display:inline-block;vertical-align:middle;
HTTP是无连接,当我们访问一个服务器的时候,页面请求回来、图片请求回来之后,会立即断掉HTTP,没有和服务器之间的持久通路。这样一来,第二次访问同一个服务器,服务器不知道我们是谁。这样就造成了用户的识别问题,从而不可能开发登录功能、站内信、聊天室等私有功能。
Cookie就是为了解决客户端和服务器之间的识别问题由服务器在HTTP的响应头部携带Set-Cookie字段,之后每一次浏览器访问同一个服务器的时候,都会在HTTP请求头部携带同样的Cookie上去,Cookie是在客户端存储的,并且是明文传输的,并且有过期时间,如果不设置过期时间,cookie 是存在内存里,关闭浏览器即可丢失。若是设置过期时间,则存在于硬盘里。直到设置的期限到了
Cookie在本地存储被发明之前充当着本地存储的作用。浏览器可以读写Cookie,使用document.cookie去读写cookie。此时不需要服务器干预,前端页面自己能够记录一些数据。在localStorage和sessionStorage被发明之后,Cookie就不作为本地存储的功能使用了。
Session是特殊的Cookie,依赖Cookie,解决了Cookie的安全性问题,采用服务端存储、密文传输。当客户端第一次访问服务器的时候,服务器会下发一个Set-Cookie,值是随机乱码,这个随机乱码在服务器的内存中做了映射表,从session不活动的时候开始计算,如果session一直活动,session就总不会过期。从该Session未被访问,开始计时; 一旦Session被访问,计时清0;在任何编程语言中,Session都是对程序员透明的,程序员不用参与随机乱码的生成、Set-Cookie的下发、Cookie的识别、比对 。每隔900秒刷新一下自己,为了和服务器通讯一下,保持session不会丢
localStorage和sessionStorage都是HTML5中新增的本地存储功能。它们的API非常简单,都是setItem和getItem,只能存储k、v对信息,且值只能是字符串。要想存储数组、对象等信息,必须进行JSON.parse()和JSON.stringify()。没有过期时间
localStorage持久时间更长,只要用户不刻意清除浏览器缓存,会一直保存着数据,不怕关机、重启、断电;但是sessionStorage当用户关闭浏览器就会清除缓存。
sessionStorage通常用户多页面通信,A页面想要将信息告诉B页面,此时就可以让A页面写sessionStorage,B页面就能够读取这个信息
强缓存: 浏览器在请求某一资源时,会先获取该资源缓存的header信息,判断是否命中强缓存. 使用强缓存时,浏览器不会发送请求到服务端,通过更新页面中引用的资源路径,让浏览器主动放弃缓存,加载新资源。query值不同,也就是页面引用的资源路径不同了,之前缓存过的资源就被浏览器忽略了,因为资源请求的路径变了
协商缓存:ETag标签,由服务器判断返回是不是304,由服务器里判断缓存资源是否可以用。
1:DNS解析:先进行DNS缓存查找,先检查本地有无缓存:浏览器缓存—》操作系统缓存—》路由器缓存----》根域名服务器查询,递归过程,
2:发起TCP连接:三次握手,四次挥手
3:发送HTTP请求:请求行, 请求报头和请求正文
4:服务器处理请求并返回HTTP报文:状态码
5:浏览器解析渲染页面:解析HTML形成DOM树,解析CSS形成CSSOM 树合并DOM树和CSSOM树形成渲染树
6:连接结束
Http:超文本传输协议, 以明文方式发送内容,不安全。基于TCP(应用程序)/IP(计算机)协议之上
HTTPS:HTTP下加入SSL层
主要区别:
1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
4、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全
SSL/TLS:对称加密与非对称加密
对称加密:加密解密都用同一把钥匙
非对称加密:公钥加密的密文只能用私钥解密,私钥加密的密文只能用公钥解密(可能存在中间人攻击,攻击人让客户端和服务端认为连接是正确的)
Keys 是 React 用于追踪哪些列表中元素被修改、被添加或者被移除的辅助标识。在开发过程中,我们需要保证元素的 key 在同级元素中具有唯一性,在 React Diff 算法中 React 会借助元素的 Key 值来判断该元素是新创建的还是被移动而来的元素,从而减少不必要的元素重渲染。
setState通过一个队列机制来实现state的更新。当执行setState时,会需要更新state合并后放入状态队列,而不会更新this.state,队列机制会高效批量更新state。如果不放如setState则不会进入队列合并,造成无法预知的错误。
在代码中调用 setState 函数之后,React 会将setState 里传入的参数对象与组件当前的状态合并,然后触发所谓的调和过程。 经过调和过程,React 会以相对高效的方式根据新的状态构建 React 元素树并重新渲染整个 UI 界面。在 React 得到元素树之后,React 会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最小化重渲染,保证了按需更新,而不是全部重新渲染
1:
在生命周期的函数场景下,setState是异步的,相同的状态属性多次更新会合并成一次,且最后一次会生效保留,相同的状态属性(不同的状态属性不会影响)多次更新会合并成一次,最后一次会保留。传入对象不算是个事务,会进行批量更新
2:
在定时器、原生DOM事件场景下是同步:会依次更新
被setTimeout包裹后,传入function算一个单独事务
。
getDerivedStateFromProps(nextProps, prevState):替换componentWillReceiveProps()老版本中的componentWillReceiveProps()方法判断前后两个 props 是否相同,如果不同再将新的 props 更新到相应的 state 上去。这样做一来会破坏 state 数据的单一数据源,导致组件状态变得不可预测,另一方面也会增加组件的重绘次数。
getSnapshotBeforeUpdate(prevProps, prevState):代替componentWillUpdate。
ps:在页面中使用了setTimout()、addEventListener()等,要及时在componentWillUnmount()中销毁
1:尽量少用状态组件,尽可能用无状态组件,无状态组件不会被实例化
2:自定义的有状态组件尽量继承自pure component,这样系统会自动在shouldComponentUpdate中默认做一层浅比较(直接拿两个对象做比较,对象中的子元素不做比较)
3:对于同层级的相同类型的组件,要给每个组件指定唯一的key值
4:FlatList和SectionList做列表
5:用FlatList替换scrollView,因为在用scrollView的时候它会一下子把他上面的所有子组件都渲染出来,而FlatList可以设置首屏渲染的行数,这样就不会导致在刚进入这一页的时候出现卡顿现象。
shouldComponentUpdate 这个方法用来判断是否需要调用 render 方法重新描绘 dom。它接受两个参数:nextProps和nextState,分别表示下一个props和下一个state的值。并且,当函数返回false时候,阻止接下来的render()函数的调用,阻止组件重渲染,而返回true时,组件照常重渲染。
使用情况:对于props和state没有变化的组件,不重新渲染
虚拟 dom 相当于在 js 和真实 dom 中间加了一个缓存,利用 dom diff 算法避免了没有必要的 dom 操作,从而提高性能。
用 JavaScript 对象结构表示 DOM 树的结构;然后用这个树构建一个真正的 DOM 树,当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异把 2 所记录的差异应用到步骤 1 所构建的真正的 DOM 树上,视图就更新了。
1: 把树形结构按照层级分解,只比较同级元素。
2: 给列表结构的每个单元添加唯一的 key
属性,方便比较。
3: React 只会匹配相同 class 的 component(这里面的 class 指的是组件的名字)
4: 合并操作,调用 component 的 setState 方法的时候, React 将其标记为 dirty.到每一个事件循环结束, React 检查所有标记 dirty 的 component 重新绘制.
5: 选择性子树渲染。开发人员可以重写 shouldComponentUpdate 提高 diff 的性能。
钩子,获取页面上的元素
JSX代码经过babel编译之后变成React.createElement的表达式,这个表达式在render函数被调用的时候执行生成一个element。
在首次渲染的时候,先去按照规则初始化element,接着ReactComponentWrapper通过递归,最终调用ReactDOMComponent的mountComponent方法来帮助生成真实DOM节点。
类组件(也像容器组件)允许你使用更多额外的功能,如组件自身的状态和生命周期钩子,也能使组件直接访问 store 并维持状态
当组件(类似展示组件)仅是接收 props,并将组件自身渲染到页面时,该组件就是一个 '无状态组件,可以使用一个纯函数来创建这样的组件
高阶组件是一个以组件为参数并返回一个新组件的函数
十一:(在构造函数中)调用 super(props) 的目的是什么
在 super() 被调用之前,子类是不能使用 this 的,在 ES2015 中,子类必须在 constructor 中调用 super()。传递 props 给 super() 的原因则是便于(在子类中)能在 constructor 访问 this.props。
在 React 组件中,应该在 componentDidMount 中发起网络请求。这个方法会在组件第一次“挂载”时执行,仅会执行一次。更重要的是,你不能保证在组件挂载之前 Ajax 请求已经完成,如果是这样,也就意味着你将尝试在一个未挂载的组件上调用 setState,这将不起作用。在 componentDidMount 中发起网络请求将保证这有一个组件可以更新了。
React.createElement():创建 React 元素的。它接受三个参数,第一个参数是一个标签名。如 div、或者 React 组件。第二个参数为传入的属性。第三个以及之后的参数,皆作为组件的子组件。
React.cloneElement():第一个参数是 React 元素,而不是标签名或组件。新添加的属性会并入原有的属性,传入到返回的新元素中,而旧的子元素将会被替换。
React.createClass()、ES6 class 和无状态函数
区别:
1:函数的绑定
使用createClass, 每一个函数属性都会被React自动绑定。
在ES6的class中,函数不再被自动绑定。需要手动绑定,一般在构造 函数 里。或者直接使用箭头函数指向组件的实例
2:调用super()
ES6类的constructor需要接收props并且调用super(props)。 createClass没有
3:调用React.createClass并传入一个对象,另一个则是使用class继承 React.Component。
this.props.children
的值有三种可能:
1.当前组件没有子节点,它就是 undefined;
2.有一个子节点,数据类型是 object
3.有多个子节点,数据类型就是 array 。系统提供React.Children.map()方法安全的遍历子节点对象
React 函数组件内一类特殊的函数(通常以 “use” 开头,比如 “useState”)
1:Dom解构简单
2:复用组件麻烦
三种:
State hooks (在 function component 中使用 state)
Effect hooks (在 function component 中使用生命周期和 side effect)
Custom hooks (自定义 hooks 用来复用组件逻辑)
使用方法:自带useState函数,声明状态变量,接收两个参数,第一个状态初始值(没有规定数据类型),它返回了一个数组,这个数组的第[0]项是当前当前的状态值,第[1]项是可以改变状态值的方法函数。
1:Router 与Route 一样都是 react 组件,它的 history 对象是整个路由系统的核心,它暴 露了很多属性和方法在路由系统中使用,是声明式的写法
2:Router 与Route 一样都是 react 组件,它的 history 对象是整个路由系统的核心,它 暴露了很多属性和方法在路由系统中使用;
3:Redirect 是一个重定向组件,有 from 和 to 两个属性
4:Route 的onEnter 钩子将用于在渲染对象的组件前做拦截操作,比如验证权限
每一个路由(Route)中声明的组件(比如 SignIn)在渲染之前都会被传入一些的props
1:history 对象:函数的第一个参数是 state 对象,第二个是路径;
2:location 对象:可以简单的认为是 URL 的对象形式表示
1:在shouldComponentUpdate判断是否渲染
2:缓存 React 事件监听器
1:阻止合成事件间的冒泡,用e.stopPropagation();
2:阻止合成事件与最外层document上的事件间的冒泡,用e.nativeEvent.stopImmediatePropagation()
3:阻止合成事件与除最外层document上的原生事件上的冒泡,通过判断e.target来避免
Redux是针对JavaScript应用的可预测状态容器,它也可以支持其他框架
含义:
1:可预测:用了reducer与纯函数,每个新的state都会由旧的state建来一个全新的 state,
2:状态容器:store即是状态集合。
Redux包含三个概念:Actions、Reducers 和 Store
action:store来说是唯一的信息来源,携带type属性指示它是什么作用的函数,进而修改reducer里面的数据
reducer:纯函数,reducer就是根据action的type来处理不同的事件;唯一可以修改state的地方,它接收一个初始状态的state和action当做参数,并且返回新的state
store:store就是把action和reducer联系到一起的对象,store本质上是一个状态树,保存了所有对象的状态。持有数据、可以通过调用getState()来得到里面的state值、可以通过dispatch()分发action来更改state.
applyMiddleware : 是一种增强redux能力的途径。
combineReducers():实际工作中一个store中会有很多reducer,现在要用combineReducers()函数统筹在一起。
bindActionCreators():将 Actions 和 dispatch组合起来生成mapDispatchToProps需要生成的内容。【隐式调用dispatch】
Connet函数接收2个参数:
第一个参数mapStateToProps 表示映射store中的state到组件的props。
第二个参数mapDispatchToProps 分发action
流程:首先,用户(通过View)发出Action,发出方式就用到了dispatch方法。然后,Store自动调用Reducer,并且传入两个参数:当前State和收到的Action,Reducer会返回新的State
State一旦有变化,Store就会调用监听函数,来更新View
在 reducers 中的所有操作都是同步的并且是纯粹的,reducer 都是纯函数(一个函数的返回结果只依赖于它的参数,并且在执行过程里面没有副作用)。但是很多时候我们 可以需要请求服务器,这是一个异步操作,有副作用。redux-saga 就是用来处理副作用(异步任务)的一个中间件,拦截dispatch,处理之后发出新的dispatch。
拦截
worker saga:做所有的工作,如调用 API,进行异步请求,并且获得返回结果
watcher saga:监听被 dispatch 的 actions,当接收到 action 或者知道其被触发时, 调用 worker saga 执行任务
root saga:立即启动 sagas 的唯一入口
将所有的异步流程控制都移入到了 sagas,UI 组件不用执行业务逻辑,只需 dispatch action 就行,增强组件复用性
比redux多了一个saga.js处理副作用
分为四种情况:1:父子 2:子父 3:爷孙 4:兄弟
1:父子:当做参数this.props.XXX接收
2:子父:父亲传来修改值的函数
3:爷孙:
a:使用 context 对象 :context 相当于一个全局变量,是一个大容器,我们 可以把要通信的内容放在这个容器中,使用方法:上级组件要声明自己支持 context,并提供一个函数来返回相应的 context 对象,而子组件要声明自己 需要使用 context
b:中间组件层层传递 props
4:兄弟:利用二者共同父组件的 context 对象进行通信或者使用自定义事件的方式 (events包)
React.PureComponent 与 React.Component 几乎完全相同,但是PureComponent通过prop和state的浅比较来实现shouldComponentUpdate,某些情况下可以用PureComponent提升性能.
如果state和prop一直变化的话,还是建议使用Component,并且PureComponent的最好作为展示组件.就是不要在PureComponent中使用shouldComponentUpdate,因为根本没有必要,只要是继承于React.PureComponen会自动进行浅比较,没有更新就不render.
不同地方:继承PureComponent时,不能再重写shouldComponentUpdate,否则会引发警告。
React-Native和 React的编程思路有些不同,React是以WebView(浏览器)为后端,操作Virtual DOM进行视图渲染的,而React-Native是以ios或者anroid原生控件为后端
JSX 源码通过 React 框架最终渲染到了浏览器的真实 DOM 中,而在 React Native 框架中,JSX 源码通过 React Native 框架编译后,通过对应平台的 Bridge 实现了与原生框架的通信。如果我们在程序中调用了 React Native 提供的 API,那么 React Native 框架就通过 Bridge 调用原生框架中的方法
#Vue
1: 简述vue的响应式原理
当一个Vue实例创建时,vue会遍历data选项的属性,用 Object.defineProperty 将它们转为 getter/setter并且在内部追踪相关依赖,在属性被访问和修改时通知变化。
每个组件实例都有相应的 watcher 程序实例,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新
2:路由跳转
This.$router.push()
3:生命周期
beforeCreate,created,beforeMount,mounted,beforeUpdate,updated,beforeDestroy,destroyed
CMD是一种规范,
Webpack并不是仅仅是个打包工具,而是为了几届浏览器的JS文件支持CMD规范。webpack适用于大型复杂的前端站点构建
Entry:入口(需要打包的文件)
Output:出口(打包完到处到哪)
Rules:loader(对高级语法进行转换,让webpack拥有了加载和解析非JavaScript文件的能力。)
file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件url-loader:和 file-loader 类似,但是能在文件很小的情况下以 base64 的方式把文件内容注入到代码中去source-map-loader:加载额外的 Source Map 文件,以方便断点调试image-loader:加载并且压缩图片文件babel-loader:把 ES6 转换成 ES5css-loader:加载 CSS,支持模块化、压缩、文件导入等特性style-loader:把 CSS 代码注入到 JavaScript 中,通过 DOM 操作去加载 CSS。eslint-loader:通过 ESLint 检查 JavaScript 代码
Plugins:插件,常用插件:压缩插件,HotModuleReplacementPlugin热更新插件,html-webpack-plugin根据模板自动生成html代码,自动并引用css和js
比如reacct自带的create-react-app本身的webpack配置文件存在于node_modules/react-scripts/目录下面,但是这个目录是node_modules/,里面的源码都是不建议修改的。
但是特殊时候我们可能需要手动配置脚手架:调用npm run eject项目里多一个config文件夹,里面有webpack的配置文件
不推荐大家这么做,因为这个步骤无法逆转!
压缩代码。删除多余的代码、注释、简化代码的写法等等方式。
可以利用webpack的UglifyJsPlugin和ParallelUglifyPlugin来压缩JS文件, 利用cssnano(css-loader?minimize)来压缩css
利用CDN加速。在构建过程中,将引用的静态资源路径修改为CDN上对应的路径。可以利用webpack对于output参数和各loader的publicPath参数来修改资源路径
删除死代码(Tree Shaking)。将代码中永远不会走到的片段删除掉。可以通过在启动webpack时追加参数–optimize-minimize来实现
提取公共代码。
1.异步流程的控制。express采用callback来处理异步,koa2采用的是async/await
2.错误处理。express采用callback捕获异常,对深层次的异常捕获不了。koa采用try/catch
2:expresss
const app = express();
app.use(express.static("./"));
接口书写:
1:创建app,使用app.get方法,传入两个参数,第一个是req ,接收的参数,第二个是res,根据数据库查找数据,返回给前台json数据(res.json())
Ps:若是post请求,需要使用formidable这个包来获得前端传递过来的参数
数据库查找:
1:创建数据模型,调用find函数,查询数据库,接收两个参数,第一个是查询条件,第二个是回调函数,回调函数接收两个参数,第一个是err ,第二个就是返回的数据
常用包:url ,path,mongoose,formidable,session,gm等
Callback:将一个函数当做参数传到另一个函数里,当那个函数执行完后,再执行传进去的这个函数;就是先处理本体函数,再处理回调的函数
promise 对象用于一个异步操作其结果的表示。
Generator:在以前一个函数中的代码要么被调用,要么不被调用,还不存在能暂停的情况。
generator让代码暂停成待执行,定义一个生成器很简单,在函数名前加个*号,使用上也与普通函数有区别。
generator函数不能直接调用,直接调用generator函数会返回一个对象,只有调用该对象的next()方法才能执行函数里的代码。要配合key yield,才能真正发挥generator的价值。
yield能将生Generator函数的代码逻辑分割成多个部分,下面改写上面的生成器函数
async-await:语法糖,基于promise,本质并不是同步代码,它只是让你思考代码逻辑的时候能够以同步的思维去思考,避开回调地狱。
声明不会被提升,重复声明报错,不绑定全局作用域
const所说的一旦声明值就不能改变,实际上指的是:变量指向的那个内存地址所保存的数据不得改动
简单类型(number、string、boolean):内存地址就是值,即常量(一变就报错).
复杂类型(对象、数组等):地址保存的是一个指针,const只能保证指针是固定的(总是指向同一个地址),它内部的值是可以改变的(不要以为const就安全了!)
#其他
首先前端工程化主要应该从模块化、组件化、规范化、自动化四个方面来思考。
模块化:模块化就是将一个大文件拆分成相互依赖的小文件,再进行统一的拼装和加载,只有这样,才有多人协作的可能。而js的模块化制定了一些模块加载方案,如CMD用Webpack+Babel将所有模块打包成一个文件同步加载.
组件化:组件化≠模块化。模块化只是对资源的拆分;而组件化是在设计层面上,对UI(用户界面)的拆分。从UI拆分下来的每个包含模板(HTML)+样式(CSS)+逻辑(JS)功能完备的结构单元,我们称之为组件。其实,组件化更重要的是一种分治思想。
规范化:规范化其实是工程化中很重要的一个部分,项目初期规范制定的好坏会直接影响到后期的开发质量。如编码规范,前后端接口规范,Git分支管理,视觉图标规范等。其中编码规范最好采取ESLint。
自动化:项目代码结束后,有很多很麻烦的工作,如测试,css合并等。但是现在我们可以使用许多前端,自动化测试,自动化部署工具。如glup等等。
在MVC里,View是可以直接访问Model的,从而,View里会包含Model信息,一些业务逻辑,MVVM,MVVM就是由Model、View、VM三部分组成,而vm就是由View抽象出来的数据模型。在概念上是真正将页面与数据逻辑分离的模式并且可以实现数据双向绑定。React官方文档第一句话说react是用于构建用户界面的 JavaScript 库。但是react应该也算是MVVM框架,但是与传统的MVVN框架不同的是,react默认数据绑定方式是单向绑定,实现数据绑定只能value,onchange(){},而vue可以使用v-modelzid自动双向绑定;react使用虚拟DOM配合JSX,应组件中的JSX,它实质上是Virtual DOM的语法糖.React负责维护 Virtual DOM以及对其进行diff运算,而React-dom 会把Virtual DOM渲染成浏览器中的真实DOM.
1.React严格上只针对MVC的view层,Vue则是MVVM模式
2.virtual DOM不一样,vue会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树.
而对于React而言,每当应用的状态被改变时,全部组件都会重新渲染,所以react中会需要shouldComponentUpdate这个生命周期函数方法来进行控制
3.组件写法不一样, React推荐的做法是 JSX + inline style, 也就是把HTML和CSS全都写进JavaScript了,即’all in js’;Vue推荐的做法是webpack+vue-loader的单文件组件格式,即html,css,jd写在同一个文件;
4.数据绑定: vue实现了数据的双向绑定,react数据流动是单向的
5.state对象在react应用中不可变的,需要使用setState方法更新状态;
1:利用ES6 Set去重
Array.from(new Set(arr))或者[…new Set(arr)],arr为要去重的数组
2:indexOf去重,indexOf === -1即不存在,可push新数组
3:includes,是否包含这个值,为false才push
4: Map数据结构去重 ,利用map不会出现相同的key值
浅克隆
深克隆
一层对象:Object.assign(target, source)
多层:懒人版(Json.parse(Json.stringfy(obj)))
递归版:
var xhr= new XMLHttpRequest();
xhr.open(提交方式,地址);
xhr.onreadystatechange = function () {
if (xhr.readyState==4 &&ajax.status==200) {
console.log(xhr.responseText); }
}
xhr.send();
如果是post请求:xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
1.class Promise {
2. constructor (executor){
3. //默认状态是等待状态
4. this.status = 'panding';
5. this.value = undefined;
6. this.reason = undefined;
7. //存放成功的回调
8. this.onResolvedCallbacks = [];
9. //存放失败的回调
10. this.onRejectedCallbacks = [];
11. let resolve = (data) => {//this指的是实例
12. if(this.status === 'pending'){
13. this.value = data;
14. this.status = "resolved";
15. this.onResolvedCallbacks.forEach(fn => fn());
16. }
17.
18. }
19. let reject = (reason) => {
20. if(this.status === 'pending'){
21. this.reason = reason;
22. this.status = 'rejected';
23. this.onRejectedCallbacks.forEach(fn => fn());
24. }
25. }
26. try{//执行时可能会发生异常
27. executor(resolve,reject);
28. }catch (e){
29. reject(e);//promise失败了
30. }
31.
32. }