POST和GET的区别
- get产生一个tcp数据包,post产生两个
- get请求时会把headers和Data数据一起发送
- post请求时,浏览器先发送headers,服务器100继续,浏览器再发送Data
- get请求在浏览器回退和刷新时是无害的,而post请求会告知用户数据会被重新提交
- get请求可以收藏为书签,post请求不可以
- get请求可以被缓存,post请求不可以被缓存,除非在响应头中包含合适的Cache-Control/Expires字段,但是不建议缓存post请求,启不满足幂等性,每次调用都会对服务器资源造成影响
- get请求一般不具有请求体,因此只能进行url编码,而post请求支持多种编码方式
- get请求的参数可以被保留在浏览器的历史中,post请求不会被保留
- get请求因为是向url添加数据,不同的浏览器厂商,代理服务器,web服务器都可能会有自己的长度限制,而post请求无长度限制
- get请求只允许ASCII字符,post请求无限制,支持二进制数据
- get请求安全性较差,数据被暴露在浏览器的url中,多以不能用来传递敏感信息,post请求的安全性较好,数据不会暴露在url中
- get请求具有幂等性(多次请求不会对资源造成影响),post请求不幂等
- get请求一般不具有请求体,请求中一般不包含100-continue协议,所以只会发送一次请求,而post请求在发送数据到服务端之前允许双方'握手',客户端先发送Expect:100-continue消息,询问服务器是否愿意接受数据,接收到服务器征求的100-continue应答后才会将请求体发送给服务端,服务端再响应200返回数据
浏览器输入一个网址后会有哪些操作
- 应用层DNS解析域名
- 应用层客户端发送HTTP请求
- 传输层Tcp传输报文
- 网络层IP协议查询MAC地址
- 数据到达数据链路层
- 服务器接收数据
- 服务器响应请求
- 服务器返回相应文件
- 浏览器进行HTML渲染
三次握手
sequenceDiagram
客户端->>服务器: 1.询问
服务器-->>客户端: 2.回答询问
客户端->>服务器: 3.回答
- 客户端:你是XX服务器吗?
- 服务器:我是XX服务器。你是客户端吗?
- 客户端:是的,我是客户端
建立连接成功后,就可以进行正式的传输数据
四次挥手
sequenceDiagram
主动方->>被动方: 1. 关闭
被动方->>被动方: 2. 收到
被动方-->>主动方: 3. 关闭
主动方->>主动方: 4. 收到,断开
- 主动方:我方关闭了向你那边的信息发送通道,只能被动接收信息了
- 被动方:收到通道关闭的信息
- 被动方:我现在也关闭了想你那边发送信息的通道
- 主动方:收到信息断开连接
之后双方无法通信
栈
栈是一种特殊的列表
[ ] 数组
后入先出
入栈 push()
出栈 pop() // 永久删除
返回栈顶元素 peek()
清空栈 clear()
empty() // 栈内是否含有元素
空栈.peek() ==> undefined
栈内的元素只能通过列表的一端访问,这一端成为栈顶
pop() this.dataStore[--this.top]
peek() this.dataStore[this.top - 1]
栈内循环取出栈内元素
while(s.length > 0) {
covered += s.pop()
}
回文
指一种现象,一个单词、短语或数字从前往后写和从后往前写都是一样的
数组去重的几种方式
let array = [1, 2, 3, 3, 4, 5, 2, 1]
// 方式1
const res = Array.from(new Set(array))
console.log(res) // [1, 2, 3, 4, 5]
// 方式2
const res = []
const map = new Map()
for(let v of array) {
if(!map.has(v)) {
map.set(v, true)
res.push(v)
}
}
console.log(res) // [1, 2, 3, 4, 5]
// 方式3
const res = []
for(let v of array) {
if(!res.includes(v)) {
res.push(v)
}
}
console.log(res) // [1, 2, 3, 4, 5]
// 方式4
for(let i = 0; i < array.length; i++) {
for(let j = i + 1; j < array.length; j++) {
if(array[i] == array[j]) {
array.splice(j, 1)
j--
}
}
}
console.log(array) // [1, 2, 3, 4, 5]
// 方式5
const obj = {}
const res = array.filter(item => obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true))
console.log(res) // [1, 2, 3, 4, 5]
深拷贝和浅拷贝的理解
浅拷贝:是指创建一个对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,那么拷贝的就是基本类型的值,如果属性是引用类型,那么拷贝的就是内存地址,所以如果其中一个对象修改了某些属性,那么另一个对象就会受到影像。
深拷贝:是指从内存中完整的拷贝一个对象出来,并在堆内存中为其分配一个新的内存区域来存放,并且修改该对象的属性不会影响到原来的对象。
深拷贝和浅拷贝的实现方式
浅拷贝:
- Object.assign()的方式
- 通过对象扩展运算符
// 引用类型,单层可以看成深拷贝,多层是浅拷贝 - 通过数组的splice()方法
- 通过数组的concat()方法
深拷贝:
- 通过JSON.stringify()来序列化对象
- 手动实现递归的方式
Vue生命周期
创建:beforeCreate, created
载入:beforeMount, mounted
更新:breforeUpdate, updated
销毁:beforeDestroy, destroyed
前端性能优化方案
可以从DOM层面,CSS样式层面和JS逻辑层面入手:
- 减少DOM的访问次数,可以将DOM缓存到变量中
- 减少重绘和回流,任何会导致重绘和回流的操作都应减少执行,可将多次操作合并为一次
- 尽量采用事件委托的方式进行事件绑定,避免大量绑定导致内存占用过多
- css层尽量扁平化,避免过多的层级嵌套,尽量使用特定的选择器来区分
- 动画尽量使用css3动画属性来实现,开启GPU硬件加速
- 图片在加载前提前指定宽高或者脱离文档流,可避免加载后的重新计算导致的页面回流
- css文件在
<head>标签中引入,js文件在<body>标签中引入,优化关键渲染路径 - 加速或者减少HTTP请求,使用CDN加载静态资源,合理使用浏览器强缓存和协商缓存,小图片可以使用Base64来代替,合理使用浏览器的预取指令prefetch和预加载指令preload
- 压缩混淆代码,删除无用代码,代码拆分来减少文件体积
- 小图片使用雪碧图,图片选择合适的质量、尺寸和格式,避免流量浪费
原文摘抄
JS中 == 和 === 的区别
== 表示抽象相等,两边值类型不同的时候,会先做隐式类型转换,再对值进行比较
=== 表示严格相等,不会做类型转换,两边的类型不同一定不相等
盒模型
指的是页面在渲染时,DOM元素所采用的布局模式,一个元素占用的空间大小由几个部分组成,内容(content)、内边距(padding)、边框(border)和外边距(margin)。可以通过box-sizing来进行设置,其中IE盒模型的content包含了padding和border,这是区别于W3C标准合模型的地方
选择器优先级
!important > 行内样式 > id选择器 > class选择器 > 标签选择器 > * > 继承 > 默认
forEach、map和filter的区别
forEach遍历数组,参数为一个回调函数,回调函数接受三个参数,当前元素、元素索引、整个数组
map与forEach相似,遍历数组,但其回调函数的返回值会组成一个新的数组,新数组的索引结构和原数组一致,原数组不变
filter会返回原数组的一个子集,回调函数用于逻辑判断,返回true则将当前元素添加的行的返回数组中,否则排除当前元素,原数组不变
var array = [1, 2, 3, 4, 5, 6]
// forEach
array.forEach((item, index, arr) => {
console.log(arr) // [1, 2, 3, 4, 5, 6]
return item
})
// map
let newArr = array.forEach((item, index, arr) => {
return item + 1
})
console.log(newArr) // [2, 3, 4, 5, 6, 7]
// filter
let newArr = array.filter(item => item > 3)
console.log(newArr) // [4, 5, 6]
数据类型
基本数据类型:String、Number、Boolean、null、undefined、Symbol
引用数据类型:function、Object、Array
判断数据类型
typeof:
对于基本数据类型,除null外均返回正确结果
对于引用数据类型,除function外均返回object类型
对于null,返回object
对于function返回function类型
function getType(data) {
if(data === null) return String(data);
return typeof data === 'object'
? Object.prototype.toString.call(data).replace('[object ', '').replace(']', '').toLowerCase()
: typeof data;
}
// Object.prototype.toString.call()(对象原型链判断方法)
// Object.prototype.toString.call("123") ==> [object String]
// Object.prototype.toString.call([]) ==> [object Array]
getType(null) // null
getType(undefined) // undefined
getType({}) // object
getType([]) // Array
getType(123) // number
getType(true) // boolean
getType('123') // string
getType(/123/) // regexp
getType(new Date()) // date
闭包
闭包 ( closure )是指有权访问另一个函数作用域中变量的函数。
是一个存在内部函数的引用关系,该引用指向的是外部函数的局部变量对象(前提是内部函数使用了外部行数的局部变量)
作用:
延长外部函数变量对象的生命周期
使用闭包能够间接的从函数外部访问行数内部的私有变量
function outer() {
var a = 1
function inner() {
console.log(a) // 1
}
inner()
}
outer()