文章目录
基础:HTML、CSS
在浏览器中输入url之后会发生那些操作
- 解析出url中的域名、协议、主机、端口、路由,并构造一个http请求(强缓存、协商缓存)
- DNS域名解析(DNS:域名系统,将主机号解析成ip地址)
- 建立TCP连接(三次握手)
- 发出http请求
- 服务器处理http请求,并返回http报文
- 浏览器渲染页面
- 断开TCP连接(四次挥手)
强缓存、协商缓存
强缓存:在加载资源时,为避免资源未过期,用户就再次刷新拉取数据,就设置一个资源过期时间,如果客户点击刷新时,资源未过期,那么就不向服务器发送请求。
相关服务:泰国服务器
协商缓存:当用户点击刷新时,资源已经过期了,那么就向服务器发送资源拉取请求,这是会发送在上一次跟服务器交流时在header 里配置好的 etag和 last-modified,服务器进行对比,看资源是否已经更改,如果有更改,就带着新的 etag和 last-modified和资源发送给客户端。
三次握手
第一次:客户端向服务器发送一个SYN(TCP协议的第一个报文,告诉服务器,客户端已做好会话准备),并进入SYN_SEND状态,等待服务器响应
第二次:服务器接收到然后返回一个SYN_ACK(ACK:表示响应),然后服务器进入SYN_RECEIVE状态;
第三次:;客户端再向服务端发送一个ACK包建立响应连接
握手完成后,开始传输数据
四次挥手
第一次:客户端发送FIN(关闭连接)包,进入FIN_WAIT_1状态,这时候客户端数据传输完毕,服务器端的数据可能还在传输。
第二次:服务器收到FIN后,会返回一个ACK报文响应,表示知道客户端数据传输完毕;客户端接收到ACK状态改变为FIN_WAIT_2状态。
第三次:当服务器数据传输完毕,给前端发送FIN报文,表示数据发送完毕,服务器状态改变为LAST_ACK状态。
第四次:客户端收到FIN报文,会改变成TIME_WAIT状态,不直接关闭,以防出错,客户端还会再发一次ACK消息给后台,等待特定时间没有收到服务器回应,则关闭连接.
盒子模型有哪些
两种:
- W3C盒子模型(标准盒子模型):box-sizing:content-box(元素默认)
-width=设置的宽度+border+padding - ie盒子模型(怪异盒子模型):box-sizing:border-box
- 实际宽度=设置的宽度(设置了padding和border的话,从实际宽高中减去,减去后才是实际宽度)
web安全有哪些
CSRF攻击
跨站请求伪造
这就是类似于钓鱼网站的原理,利用浏览器的漏洞。用户发送请求时,服务器会验证用户信息,如果信息不符合,就会对该请求不作回应。但是如果有心人做了一个链接,你点进去向服务器发送请求,恰好这时你浏览器还存有请求所需的验证信息,那么这次请求就成功了,但是用户本身不知情。
解决:
- 在请求中添加一个token,这个token是随机产生的,服务器在收到请求之后对其进行验证
- 双重cookie:在请求中加一个csrfcookie的字段,用于验证。
cookie安全:
如果用cookie检验用户是否登录,存的name为用户信息,那么可以恶意伪造name,造成已经登陆的假象;
- 解决
- 我们可以多设置一项,但是这一项的值必须是随机的,没有任何规律可循的。
xss攻击:
XSS攻击使用Javascript脚本注入进行攻击
三类:DOM型、反射性型、存储型
- 比如评论功能,直接将评论的内容放在表里显示的时候,就可能会受到恶意
- 在url中拼接js代码
- 解决
- 不需要展示HTML标签的表单内容,入库时直接转成实体显示
- 可以用正则检测输入框必须为合法数据
- 需要展示HTML标签的部分, 仅允许展示有限的标签,如p,a,img等;如strip_tags 来过滤html标签
sessionstorage和localStorage的区别和相同
区别
1.生命周期
- localStorage是永久存在的,只要不手动删除,就会一直存在
- sessionStorage的生命周期是一次会话,随着浏览器窗口关闭消失
共同点:
- 大小:5M
- 存储数据类型:字符串
- 存储位置:客户端,不与服务器通信
gitee常用命令
git clone:克隆
git add:添加到暂存区
git commit:上传至本地仓库
git push:上传至远程仓库
git branch fenzhi1:创建本地分支
git chea
kout fenzhi1:切换分支
git merge fenzhi1:合并分支
svg与canvas
svg:可伸缩矢量图形,不依赖分辨率,常用于静态图形绘制;基于对象绘制图像。
canvas:基于HTML5的画布,使用js动态绘制像素点,常用于动态图像绘制。
grid布局与flex布局
flex布局:
- 是一维布局,只在一个方向上定义布局方式。
- 属性:justify-content,flex-wrap,flex-direction,align-item等
grid布局: - 二维布局,在行和列的方向上布局,有容器、单元格、单元格线等。
- 属性:grid-template-rows(单元格行高),grid-template-columns(单元格列宽), grid-template-areas(每个单元格命名)
<!DOCTYPE html>
<html lang="en">
<style>
#page {
display: grid; /* 1.设置 display 为 grid */
width: 100%;
height: 250px;
grid-template-areas:
"head head"
"nav main"
"nav foot"; /* 2.区域划分 当前为 三行 两列 */
grid-template-rows: 50px 1fr 30px; /* 3.各区域 宽高设置 */
grid-template-columns: 150px 1fr;
}
#page > header {
grid-area: head; /* 4. 指定当前元素所在的区域位置,从 grid-template-areas 选取值 */
background-color: #8ca0ff;
}
#page > nav {
grid-area: nav;
background-color: #ffa08c;
}
#page > main {
grid-area: main;
background-color: #ffff64;
}
#page > footer {
grid-area: foot;
background-color: #8cffa0;
}
</style>
<body>
<section id="page">
<header>Header</header>
<nav>Navigation</nav>
<main>Main area</main>
<footer>Footer</footer>
</section>
</body>
</html>

自适应方案
viewport方案:使用postcss插件,最后运行出来的代码会将配置好的元素中的px转化为rem
使用rem:根据根元素的字号自动调整大小
解决父元素内容塌陷
使用伪元素法:
div::after {
display: block;
content: "";
clear: both;
}
添加属性:overflow:hidden
添加元素法:在元素后面添加一个空白标签,并添加属性clear:both
JS、ES
数据类型转换
转成String
symbol只能强制转换(隐式,比如与字符串相加会出错)
对象:[object Object]
转成数值:
undefined:NaN
null:0
true——1,false——0
string——只要包含非数字的字符,就是NaN;全是数字,直接转换;空为0
symbol:报错
Object:先转化为基本数据类型,再转换
转成布尔:
假:undefined,null,false,+0,-0,NaN,“” ——false
包装类型:
调用基本数据类型的属性或方法时,会在后台隐式地将基本数据类型转化为对象
const a='abc'
a.length//3
a.toUpperCase()//'ABC'
隐式数据类型转换:
+:双方至少有一个string,就转化为string;其他情况都转为number
-、*、/:
结果可能是NaN,NaN也是一个数字
==:尽量转化为number
<、>:两边都是字符串,比较字母顺序;其他情况都是转化为数字
undefined与null
undefined——未定义
null——空对象
数字相加是二进制相加,会出现误差
解决四舍五入:(0.1+0.2).toFixed()
==会携带隐式数据类型转换,转换后再比较
string会转换成number在比较
boolean会转换成number再比较
object会转换成基本数据类型再比较
new一个实例的步骤
1.创建一个空对象作为this
2.this.proto指向构造函数的prototype
3.运行构造函数
4.返回this(如果函数没有return,有的话如果是对象,则返回这个对象,如果是其他数据类型,则返回该数据类型的原型)
源码:
function myNew(Fn,...args){
// 1.新建空对象
let o = {};
// 2.对象的__proto__ 属性指向原型
o.__proto__ = Fn.prototype;
// 3.以对象为this,执行构造函数
let res = Fn.apply(o,args);
// 4.返回合法值
return res instanceof Object? res : o;
}
let p1 = myNew(Person,'pxx',18);
console.log(p1);
防抖
思路:在第一次触发事件时,不立即执行函数,而是给出一个期限值比如200ms,
然后:
- 如果在200ms内没有再次触发滚动事件,那么就执行函数
- 如果在200ms内再次触发滚动事件,那么当前的计时取消,重新开始计时
如果短时间内大量触发同一事件,只会执行一次函数。
定义:对于短时间内连续触发的事件(上面的滚动事件),防抖的含义就是让某个时间期限(如上面的1000毫秒)内,事件处理函数只执行一次。
节流
效果:如果短时间内大量触发同一事件,那么在函数执行一次之后,该函数在指定的时间期限内不再工作,直至过了这段时间才重新生效。
闭包
定义:闭包就是能够读取另一个函数作用域的变量的函数
闭包作用:闭包的作用 防止函数内部的变量或函数被污染,同时函数内部的变量不会被垃圾回收机制回收
一个闭包的使用:
for (var i = 0; i < 10; i++) {
//这里的i被强制滞留再内存里
(function (j) {
setTimeout(() => {
console.log(j);
}, j * 1000)
})(i)
}
Blob
定义:Blob类型的对象表示不可变的类似文件对象的原始数据,其实就是二进制对象,类似文件的二进制对象,文件也是由它继承而来
$http.get('/receivePDFUrl', {responseType: 'arraybuffer'}) // 设置$http get请求的responseType为arraybuffer
.success(function(data){
var file = new Blob([data], {type: 'application/pdf'}); // 使用Blob将PDF Stream 转换为file
var fileUrl = URL.createOjectURL(file);
window.open(fileUrl); // 在新的页面中打开PDF
})
ES6数组新增方法
- JSON转数组:
Array.from()——只留下key值 - 将一堆文本或变量合并成数组:
Array.of() - 寻找符合条件的第一个元素:
find(),是一个实例方法,需要实例调用。参数是一个匿名函数,匿名函数三个参数
- value:当前查找的值
- index:当前查找的下标
- arr:当前查找的数组
let arr=[1,2,3,4,5,6,7,8,9];
console.log(arr.find(function(value,index,arr){
return value > 5;
})) //输出6 注意:在函数中如果找到符合条件的数组元素就return,并停止查找
- 填充数组:
fill(),是一个实例方法,三个参数
- 第一个:填充的变量
- 第二个:起始位置
- 第三个:填充到的位置 - 遍历数组:
for...of
注意,有时候需要数组的索引
let arr=['js','java','python','c','c++'];
for (let index of arr.keys()){
console.log(index);//0 1 2 3 4
}
arr.keys()//是对key值得遍历
arr.values()//是对value值的遍历
arr.entries()//是对键值对的遍历
let arr=['js','java','python','c','c++'];
for (let [index,val] of arr.entries()){
console.log(index,val); //0 'js' 1 'java' 2 'python' 3 'c' 4 'c++'
}
es6新增
let、const
变量的解构赋值、模板字符串、
新增字符串方法:
includes():返回布尔值,表示是否找到了参数字符串。
startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。
repeat():返回一个新字符串,表示将原字符串重复n次
padStart()用于头部补全,padEnd()用于尾部补全
trimStart()消除字符串头部的空格,trimEnd()消除尾部的空格。(trim()两者结合)
replaceAll()方法,可以一次性替换所有匹配。
Object新增方法
Object.is(a,b):比较a和b是否严格相等。
- 与‘===’不同之处:
- ===的-0=+0,NaN!=NaN
- 该方法的-0!=+0,NaN=NaN
Object.assign():方法用于对象的合并,将源对象(source)的所有可枚举属性(浅拷贝)- 可以处理数组,但是会处理成对象,key为下标,所以如果两个数组的话,同下标的会被合并项覆盖
- 当合并项是函数时,会取函数的返回值
Object.getOwnPropertyDescriptor()方法会返回某个对象属性的描述对象
onst obj = {
foo: 123,
get bar() { return 'abc' }
};
Object.getOwnPropertyDescriptors(obj)
// { foo:
// { value: 123,
// writable: true,
// enumerable: true,
// configurable: true },
// bar:
// { get: [Function: get bar],
// set: undefined,
// enumerable: true,
// configurable: true } }
__proto__,Object.setPrototypeOf(),Object.getPrototypeOf()——都是处理原型
es5遍历数组
forEach()方法(ES5):
不可打断循环
filter()方法(ES5):
返回一个满足条件的子集
//eg:1
let arr=['js','java','jquery'];
arr.filter(x=>console.log(x));//js java jquery 返回一个空数组
//eg:2
a = [5,4,3,2,1];
values = a.filter(function(x){return x<3});// [2,1]
some():有一个满足条件返回true
every():所有满足条件返回true
//some方法
let arr=['js','java','jquery'];
arr.some(x=>console.log(x)); //js java jquery 返回false
let a = [1,2,3,4,5];
a.some((x)=>{return x<5}) // true 存在一个满足条件返回true
//every方法
let arr=['js','java','jquery'];
arr.every(x=>{console.log(x)}); //js 返回false
let a = [1,2,3,4,5];
a.every((x)=>{return x<10}) // true 所有的满足条件返回true
map()方法
//eg:1
let arr=['js','java','jquery'];
console.log(arr.map(x=>'web')); //["web", "web", "web"]
//eg:2
a = [1,2,3];
b = a.map(function(x){return x*x;}); //[1,4,9]
map与filter区别
filter执行返回的结果要么是自身,要么是自身的子集
map返回的结果可能是经过处理过的,新的数组
数据类型检测
typeof:
数组、对象、null都判断为Object(都是Object的实例)
typeof NaN——Number
instanceof:
原理:原型链上找该数据的类型
原型链:引用类型(数组、对象)都有一个_proto_(隐式原型)属性,这个属性的值是一个对象的构造函数,原型链就是当访问该引用数据的时候会一直往上寻找,这就形成了一个原型链
var a=[1,2,3]
//true
a._proto_===Array.prototype
//Object的原型的_proto_是null
Object.prototype.__proto__ === null//true
instanceof只能正确判断引用数据类型(数组、函数、对象)
也可以判断某个实例对象是否在某个构造函数的原型链上
function C () {}
var o = new C()
console.log(o instanceof C, o.__proto__ === C.prototype) //true
constructor
判断数据的类型
a.constructor===Array
Object.prototype.toString.call()
Object.prototype.toString.call(2)//Number
深拷贝的源码

扩展运算符深浅拷贝
第一层数据数深拷贝,如果第一层数据里嵌套引用数据类型,那么里面的数据就是浅拷贝
let outObj = {
inObj: {
a: 1,
b: 2
},
c: 1
}
let newObj = { ...outObj }
newObj.inObj.b = 3
newObj.c = 4
console.log(newObj);//inObj:{a:1,b:3},c:4
console.log(outObj);//inObj:{a:1,b:3},c:1
//inObj:里面的a、输入浅拷贝
//c:深拷贝
Object.assign({}, outObj)
对象的结构是按照属性名来解构的
```javascript
let stu={
name:'Bob',
age:18
}
const {age,name}=stu
//age:18
//name:'Bob'
扩展运算符字符串——>数组
[...'he']=>['h','e']
判断是不是数组
方法一:原型上的toString().call()方法
Object.prototype.toString.call(obj).slice(8,-1) === 'Array';
原型链:obj._proto_===Array.prototype
ES6:Array.isArray(obj)
instanceof:obj instanceof Array
原型函数:Array.prototype.isPrototypeOf(obj)
判断空对象
JSON.stringify(Obj)=='{}'
es6:Object.key(Obj).length<0
let、const、var的区别:
块级作用域:let、const有块级作用域;var没有块级作用域
变量提升:let、const不存在变量提升;var存在变量提升
给全局添加属性:浏览器的全局对象——window,Node——global;var声明之后会变成全局变量,并且成为全局对象的属性;
重复声明:var允许,let、const不允许
暂时性死区:声明之前不可用,var不存在
初始值设置:const必须设置初始值
指针指向:const不允许改变指针指向
箭头函数
箭头函数不能new(没有prototype、this、arguments)
箭头函数不能改变继承来的this指向(call()、apply()、bind()也不行)
不能作为构造函数
对象的this无法形成一个块级域,里面的箭头函数的this依然是全局(window)
改变this指向
call()、apply()、bind()
Object.assign(obj1,obj2)用于对象得合并,返回一个新对象
将obj2的所有可枚举对象复制到obj1,若有重复,则覆盖
正则
1. \d:数字(相当于[0-9])
2. \D:非数字
3. \s:空格
4. \S:非空
5. \b:单词边界
6. \B:非单词边界
7. \w:单词(a-z,A-Z,0-9)
8. \W:非单词
具有特殊意义的符号(用之前都需要转义)
1. |:或
2. []:这里面的东西都是原本含义,除了^和-
- /a[ab]/——aa或ab
- /a[a|b]/——a或|或b
- /[0-39]/——0-3或9
3. .:任意字符
4. ^:除了
- /[^a-z]/:除了小写字母
5. [\u4e00-\u9fa5]:汉字范围
20. $:结束限制
21. g:全局
22. m:多行
23. i:忽略大小写
排序算法
冒泡排序法:
相邻的两个元素作比较,排列顺序错误的交换位置,正确的不处理。
外层循环次数是数组长度-1:减去第一个
内层循环次数是长度-i-1:i是减去前面已经处理过的,-1是除去第一个
处理结果:第一次全部循环完会找出最大(小)的数字,放在最后(前)面
代码:
function maopao(arr){
for(let i=0;i<arr.length-1;i++){
for(let j=0;j<arr.lenth-i-1;j++){
if(arr[j]>arr[j+1]){
let tmp=arr[j]
arr[j]=arr[j+1]
arr[j+1]=tmp
}
}
}
return arr
}
选择排序法:
将第n个数字与所有后面位置上的进行比较,比第n个小,就交换位置,否则不换。
实现:
外层循环长度-1:除去最后一个
内层循环:起始i+1——i之后里面寻找,i之前已经排好了;结束长度——要与i之后的所有比较
内层的目的是找出i之后的最小的数的下标
function xuanze(arr){
let minIndex
for(let i=0;i<arr.length-1;i++){
minIndex=i
//找出i之后的最小的下标
for(let j=i+1;j<arr.length;j++){
if(arr[j]<arr[minIndex]){
minIndex=j
}
}
let tmp=arr[i]
arr[i]=arr[minIndex]
arr[minIndex]=tmp
}
}
二分查找:
先找到中间值,大的放右边小的放左边,两边又找中间值……
插入排序法:
认为第一个已经排好序了,从第二个元素开始,与已排好的数列从后向前比较,知道找到比他小或等于它的数字,就将该数字的后面所有元素向后挪一个位置,再将该数字插入到数列
function insertSort(arr){
for(let i=1;i<arr.length;i++){
//将要插入的第i个数据存起来
let tmp=arr[i]
//从已排的第i-1个数据开始比较
let j=i-1
//如果还没比较完,且第i个数还小于这个数
while(j>=0&&arr[j]>tmp){
//已排数列增加一个位置,后移一位
arr[j+1]=arr[j]
j--
}
arr[j+1]=tmp
}
return arr
}
快速排序法:
通过一趟排序,将待排记录分割成独立的两部分,其中一部分记录的关键字均比另外一部分记录的关键字小,则可分别对着两部分记录继续进行排序,以达到整个序列有序的目的。
时间复杂度:
冒泡和捕获
冒泡:点击子节点,会从触发的节点冒泡到document
捕获:点击会从document触发至点击的节点
js原生阻止冒泡和捕获:e.stopPropagation()、e.preventDefault()(取消目标元素默认行为,比如提交按钮等)和 return false
w3c规定,若一个节点同时绑定了捕获和冒泡,会先执行捕获,再执行冒泡
nh hy
react的事件处理机制采用合成事件处理机制,将所有事件委托至document
优点:
- 兼容性强,适应多个浏览器
- 统一事件处理,节省内存
react阻止冒泡和捕获:e.preventDefault()
当同时绑定原生事件和react合成事件时,会先执行原生事件,因此,如果原生事件阻止了冒泡,可能会影响到react合成事件,因为react事件需要冒泡到document上执行。
promise
什么时promise:promise就是将异步操作以同步的流程表达出来,从而解决异步带来的问题(比如多层异步嵌套,ajax),是异步编程的一种解决方案。
里面保存着某个未来才会结束的事件的结果。
三个状态:pending、filfulled(匹配resolve())、rejected(匹配rejected())
promise的缺点:
1. promise不可以中断
2. 如果没有回调函数,promise内部抛出的错误不会反应到外部
3. 如pending状态的时候,无法得知当前进展
promise的方法:
- Promise.prototype.then:返回一个新的Promise对象
- Promise.prototype.catch:指定发生错误时的回调函数
- Promise.all方法
let p=Promise.all([p1,p2,p3])
//
一个基础的promise写法
function promiseClick(){
let p = new Promise(function(resolve, reject){
setTimeout(function(){
var num = Math.ceil(Math.random()*20); //生成1-10的随机数
console.log('随机数生成的值:',num)
if(num<=10){
resolve(num);
}
else{
reject('数字太于10了即将执行失败回调');
}
}, 2000);
})
return p
}
promiseClick().then(
function(data){
console.log('resolved成功回调');
console.log('成功回调接受的值:',data);
},
function(reason){
console.log('rejected失败回调');
console.log('失败执行回调抛出失败原因:',reason);
}
);
async awite
async awite是一种promise的语法糖,更直观的替代promise处理异步问题的能力
promise与async的区别
- 处理方式:promise使用promise/catch的方式处理异步,async采用async函数和awite关键字来处理异步
- 错误捕获:async采用try/catch捕获错误,promise采用catch捕获错误
- 可读性:async可读性更强
- 性能:promise性能稍强,不过总体差不多
webpack
原理:把所有依赖打包成一个 bundle.js 文件,通过代码分割成单元片段并按需加载。
它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Sass,TypeScript等),并将其转换和打包为合适的格式供浏览器使用。
4、什么是bundle,什么是chunk,什么是module
bundle: 是由webpack打包出来的文件
chunk: 是指webpack在进行模块依赖分析的时候,代码分割出来的代码块
module: 是开发中的单个模块
vue
v-show原理
display:none||block
路由传参
params:
<Link to='/home/dx'>首页</Link>
<Route path="/home/:name" component={Home}>
//使用
this.props.match.params
//或者
let a = useParams()
console.log(a.name)
search
<Link to='/home?name=dx'>首页</Link>
//使用
this.props.location.search
//或者
this.props.location.query
//或者
let [a]=useSearchParams()
a.get('name')
隐式路由state传参
<Link to={{
pathname: 'about',
state: {
name: 'dx'
}
}}>关于</Link>
//使用
this.props.location.state
组件间传参
<Link to='/test'>测试</Link>
<Route path='/test' render={(routeProps) => {
//routeProps就是路由组件传递的参数
return (
//在原先路由组件参数的情况,扩展绑定父组件对子组件传递的参数
<Test {...routeProps} name='dx' age={18} />
)
}}></Route>
//this.props获取来自父组件传递的参数和路由组件自带的参数
vue实现路由守卫
在哪里实现,路由配置文件里
全局路由守卫
//前置路由守卫
router.beforeEach((to, from, next)
//后置路由守卫
router.afterEach((to, from) => {})
组件内路由守卫
//前置
beforeRouteEnter:(to,from,next)=>{}——到达
//点击其他组件时,判断是否离开
beforeRouteLeave:(to,from,next)=>{}——离开
独享路由守卫:单个页面使用
beforeEnter:(to,from,next)=>{}
类组件与函数组件的区别
共同点:它们都可以接收属性并且返回React元素
- 开发时理念不同:类组件面向对象编程,函数组件的内核时函数式编程。
- 内存占用:类组件需要创建实例,会占用内存,函数组件不需要,所以节约内存。
- 生命周期:类组件有生命周期的概念,而函数组件没有,通过HOOK实现。
- 性能优化:类组件——shouldComponentUpdate和pureComponent阻止渲染来提升性能,函数组件——依靠React.memo缓存渲染结果来提升性能
vue和react的区别
相同:
- 都使用虚拟DOM的方式渲染页面
- 都使用组件化思想
-
- 机制方面:
- 在react是函数式的思想,把组件设计成纯组件,是单向数据流,数据更新是手动的,但是性能更好,节约资源去监控数据,采用mvc模式,m:数据层(模型),v:用户界面,c:控制器 ,流程:v->c->m->v
- vue是响应式的,是双向数据流的,数据更新是自动的,mvvm模式,m:数据层,v:用户界面,vm:双向数据流的实现,流程:v<->m<->m,原理:Object.definePrototype - 操作:
- react通过js生成html,使用jsx语法
- vue将html、css、js组合到一起,采用各自的处理方式,html采用模板引擎 - 生命周期不同
- react:componentDidMount()、componentWillUnmount()、componentDidUpdate()
- vue:beforCreate()、created()、beforeMount()、mounted()、beforeUpdate()、updated()、beforDestoryed(),destoryed() - 事件处理:
- react:小驼峰命名法,需要传入一个事件处理函数,不是字符串,使用与普通DOM元素相似
- vue:使用v-on(@),接收方法名称 - 构建工具
- react:Create React App
- vue:vue-cil

- diff算法:
- 节点对比处理方式:vue比对节点,当节点元素类型相同,但是className不同,认为是不同类型元素,删除重建,而react会认为是同类型节点,只是修改节点属性
- 列表对比方式:vue的列表比对,采用从两端到中间的比对方式,而react则采用从左到右依次比对的方式。
vuex
state:
用来定义数据,存放公共数据
其他地方获取数据:$store.state.data
getters
类似computed,可以在里面进行运算,可以是函数
其他地方获取数据:$store.getter.data
mutations
更改mutations:{state.a++}
是修改state的唯一方法5
写法:
mutations:{functionName(state.a){state.a++}}
其他地方使用:this.$store.commit('functionName')
actions
用于提交mutation
action可以包含任意异步操作
例如:当数据是state里面的,就有action发送请求
写法:
action:{
functionName(context){
//异步操作
//提交,context代表上下文,本质就是store
context.commit('mutation里面的函数名')
}
}
其他地方接收使用:
this.$store.dispatch('functionName')
modules
将store分开写,写在另一个js文件,然后再modules里面注册
const newStore={
state:{},
getters:{},
mutations:{},
actions:{}s
}
export default user
import newStore from '......'
......
modules:{}
......
proxy监听数据
target代表需要添加代理的对象,handler用来定义操作,get、set
express有哪些模块
日志模块、路由模块、数据库模块、multer (文件上传模块)、
express-session( session处理)
配置webpack,解决跨域
再config.env.js文件里配置代理
diff算法
为什么使用:渲染真实DOM的带价是非常昂贵的,有时候改变一个地方,我们就要把整个DOM树进行重绘和重排。但是我们需要改变的只有一小块地方,diff算法就实现了这一目标
核心:将更新前和更新后的DOM树进行对比
重绘和重排、回流
语法糖
通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会,它对语言本身的编辑结果和功能没有影响和改变。
虚拟dom
一种描述真实DOM的js对象
特点:
- 没有浏览器兼容问题,可以实现跨平台开发
- 避免操作真实DOM(diff算法)
- 内部自行解决了xss问题
setState是同步还是异步
setState在原生方法中是同步的,但是,在React的事件处理机制的环境中,是异步的。因为每一次的setState都会触发更新,采用异步的方式可以提升性能
react的路由模式
hash模式:通过监听 hashchange 事件, 在回调里拿到 window.location.hash 的值。
history模式:利用history API实现url地址改变,网页内容改变。window.history 属性指向 History 对象,它表示当前窗口的浏览历史。
react常用钩子
- useState()、useEffct()
- useContext():组件之间共享状态
import { useState, createContext, useContext } from 'react';
import { Button } from "antd";
const ContContext = createContext()
function TestCom() {
//拿到共享的count
let count = useContext(ContContext)
return (
<h2>
测试子组件:{count}
</h2>
)
}
function Demo04() {
const [count, setCount] = useState(0)
return (
<div>
<h1>{count}</h1>
<Button onClick={() => { setCount(count + 1) }}>点击按钮+1</Button>
<ContContext.Provider value={count}>
<TestCom />
</ContContext.Provider>
</div>
)
}
export default Demo04
useRef():获取组件的实例;
time slicing——时间分片
为什么使用:同步模式会造成任务进程卡顿,因为每一次的任务要将当前任务完成之后才能进行下一次进程。
原理:通过中断任务循环(将任务进行分片),每一个进程都是可打断的,会优先处理紧急任务,不会阻塞进程。
好处:
- react在渲染时,不会阻塞进程
- 如果设备足够快,会感觉时同步的,如果设备非常慢,也不会觉得泰国卡顿
- 虽然是异步渲染,但是会看到完整的代码
redux
三个层面:
view的要获取state要从store中获取,而要改变view中的state必须构建action,在store中修改,这三个层面是单向的,actions->store->view->actions
三个原则:
- 单一事件源
- 状态只读
- 使用纯函数修改
定义:redux是一个专门做状态管理的js库
特点:
- 单一数据源:整个项目只有一个store
- 只有store能改变state,reducer函数只能通过当前state和action计算出新的state
- 使用纯函数reducer进行状态改变(纯函数:出参由入参决定,没有副作用)
redux使用
引入:
npm install redux --save
基本配置:
import { createStore } from 'redux'
// 创建 action,对象中需包含 type 字段,说明此次变动
const action = {
type: 'add_val',
value: 2
}
// reducers 纯函数
function reducers (state = { val: 0 }, action) {
// 根据 action type 编写处理逻辑
switch (action.type) {
case 'add_val':
// 注意先深拷贝,不能直接改变 state 的值
const newState = JSON.parse(JSON.stringify(state))
newState.val += action.value
return newState
default:
return state
}
}
// 传入 reducers 创建 store
const store = createStore(reducers)
// 获取状态
const value = store.getState().val
// 订阅 store 的变动,执行回调
store.subscribe(() => {
console.log('store 更新啦')
})
// 调用 dispatch 来更新状态
store.dispatch(action)
redux thunk作用
action是一个函数,使一个action中可以进行多次的dispatch。
redux的工作流程
- 用户通过view发出action,发出时使用dispatch方法
- store调用reducer,并传入两个参数,一个是原来的state,一个是收到的action,reducer经过计算返回新的state。
- state一旦有变化,store就会调用监听函数,更新view
redux与mobx区别
- 数据存储位置: redux将数据保存在单一的store中,而mobx将数据保存在分散的多个store中。
- 是否响应式:redux需要手动处理变化后的操作;mobx使用observable保存数据,数据变化后自动处理响应的操作。
- 数据改变方式:redux使用的是不可变状态,意味着状态只是只读的,不能直接去修改它,而是应该返回一个新的状态,同时使用纯函数;mobx中的状态是可变的,可以直接对其进行修改。
- 编程思维:mobx在使用时比较简单,它是面向对象的编程思维,而redux是函数式编程思维。
- 调试:mobx有更多的抽象和封装,调试更加复杂,redux调试起来更加简单
面试记录:
- 实现动态路由:
- 全局存储变量怎么实现的:放在根原型上
- 跨域怎么解决:代理
什么是跨域:
跨域指的是浏览器不能执行其它网站的脚本,它是由浏览器的同源策略造成的
什么是同源策略:所谓同源是指"协议+域名+端口"三者相同
解决:
JSONP 方式
需要后台配合,利用了html种一些地方是不需要同源的,比如img的src也是不需要同源的
后端返回的是可执行的js代码
动态加载 script的src,把参数放在src里面
只能get请求,因为src中只能是get请求
1 $.ajax({
2 type:"get",
3 async:false,
4 url:"http://localhost:8080/JavaWeb01/getPassWordByUserNameServlet?userName=Tom",
5 dataType:"jsonp",//数据类型为jsonp
6 jsonp:"backFunction",//服务端用于接收callBack调用的function名的参数
7 success:function (data) {
8 alert(data["passWord"]);
9 },
10 error:function () {
11 alert("error");
12 }
13
14 });
代理:只需要前台配置
cors( 跨域资源共享):只需要后台配置
nginx代理跨域:nginx反向代理,将请求分发到部署到相应项目的tomcat服务器
- 如果前后端在不同的服务器上面,最后项目怎么打包?
将前端打包之后,得到的打包文件,上传至服务器。 - 实现动态监听数据: Object.definePropety()
css怎么实现左右菜单栏布局——原生和flex
原生:
calc():父组件必须有宽度
.left1{width: 100px;background: yellow;}
.right1{background: #09c;width:calc(100% - 100px);}
margin-left
.left2{float: left;background: yellow;width: 100px;}
.right2{background: #09c;margin-left: 100px;}
position
#box5{position: relative;}
.left5{position: absolute;left: 0;top:0;width: 100px;background: yellow;}
.right5{position: absolute;left: 100px;top:0;right: 0;width: 100%;background: #09c;}
flex
#box6{display: flex;display: -webkit-flex;}
.left6{flex:0 1 100px;background: yellow;}
.right6{flex:1;background: #09c;}
- 浅拷贝和深拷贝。深拷贝有哪些方式:JSON.stringify()、解构、用json的方法

斐波那契数列:第n项的值等于(n-1)项的值加上(n-2)项的值
function climbStairs(n) {
//使用裴波那契法(可以使用递归,但是可能超时)
if(n === 1 || n === 2){
return n;
}
let result; //用来保存结果
let preTwo = 1; //需要记忆两个数
let preOne = 2;
for(let i = 3; i < n + 1; i++){
result = preOne + preTwo;
preTwo = preOne;
preOne = result;
}
return result;
}








