前端小结

90 阅读8分钟

POST和GET的区别

  1. get产生一个tcp数据包,post产生两个
  2. get请求时会把headers和Data数据一起发送
  3. post请求时,浏览器先发送headers,服务器100继续,浏览器再发送Data
  4. get请求在浏览器回退和刷新时是无害的,而post请求会告知用户数据会被重新提交
  5. get请求可以收藏为书签,post请求不可以
  6. get请求可以被缓存,post请求不可以被缓存,除非在响应头中包含合适的Cache-Control/Expires字段,但是不建议缓存post请求,启不满足幂等性,每次调用都会对服务器资源造成影响
  7. get请求一般不具有请求体,因此只能进行url编码,而post请求支持多种编码方式
  8. get请求的参数可以被保留在浏览器的历史中,post请求不会被保留
  9. get请求因为是向url添加数据,不同的浏览器厂商,代理服务器,web服务器都可能会有自己的长度限制,而post请求无长度限制
  10. get请求只允许ASCII字符,post请求无限制,支持二进制数据
  11. get请求安全性较差,数据被暴露在浏览器的url中,多以不能用来传递敏感信息,post请求的安全性较好,数据不会暴露在url中
  12. get请求具有幂等性(多次请求不会对资源造成影响),post请求不幂等
  13. get请求一般不具有请求体,请求中一般不包含100-continue协议,所以只会发送一次请求,而post请求在发送数据到服务端之前允许双方'握手',客户端先发送Expect:100-continue消息,询问服务器是否愿意接受数据,接收到服务器征求的100-continue应答后才会将请求体发送给服务端,服务端再响应200返回数据

浏览器输入一个网址后会有哪些操作

  1. 应用层DNS解析域名
  2. 应用层客户端发送HTTP请求
  3. 传输层Tcp传输报文
  4. 网络层IP协议查询MAC地址
  5. 数据到达数据链路层
  6. 服务器接收数据
  7. 服务器响应请求
  8. 服务器返回相应文件
  9. 浏览器进行HTML渲染

三次握手

sequenceDiagram
客户端->>服务器: 1.询问
服务器-->>客户端: 2.回答询问
客户端->>服务器: 3.回答
  1. 客户端:你是XX服务器吗?
  2. 服务器:我是XX服务器。你是客户端吗?
  3. 客户端:是的,我是客户端

建立连接成功后,就可以进行正式的传输数据

四次挥手

sequenceDiagram
主动方->>被动方: 1. 关闭
被动方->>被动方: 2. 收到
被动方-->>主动方: 3. 关闭
主动方->>主动方: 4. 收到,断开
  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]

深拷贝和浅拷贝的理解

浅拷贝:是指创建一个对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,那么拷贝的就是基本类型的值,如果属性是引用类型,那么拷贝的就是内存地址,所以如果其中一个对象修改了某些属性,那么另一个对象就会受到影像。
深拷贝:是指从内存中完整的拷贝一个对象出来,并在堆内存中为其分配一个新的内存区域来存放,并且修改该对象的属性不会影响到原来的对象。

深拷贝和浅拷贝的实现方式

浅拷贝:

  1. Object.assign()的方式
  2. 通过对象扩展运算符 // 引用类型,单层可以看成深拷贝,多层是浅拷贝
  3. 通过数组的splice()方法
  4. 通过数组的concat()方法

深拷贝:

  1. 通过JSON.stringify()来序列化对象
  2. 手动实现递归的方式

Vue生命周期

创建:beforeCreate, created
载入:beforeMount, mounted
更新:breforeUpdate, updated
销毁:beforeDestroy, destroyed

前端性能优化方案

可以从DOM层面,CSS样式层面和JS逻辑层面入手:

  1. 减少DOM的访问次数,可以将DOM缓存到变量中
  2. 减少重绘和回流,任何会导致重绘和回流的操作都应减少执行,可将多次操作合并为一次
  3. 尽量采用事件委托的方式进行事件绑定,避免大量绑定导致内存占用过多
  4. css层尽量扁平化,避免过多的层级嵌套,尽量使用特定的选择器来区分
  5. 动画尽量使用css3动画属性来实现,开启GPU硬件加速
  6. 图片在加载前提前指定宽高或者脱离文档流,可避免加载后的重新计算导致的页面回流
  7. css文件在<head>标签中引入,js文件在<body>标签中引入,优化关键渲染路径
  8. 加速或者减少HTTP请求,使用CDN加载静态资源,合理使用浏览器强缓存和协商缓存,小图片可以使用Base64来代替,合理使用浏览器的预取指令prefetch和预加载指令preload
  9. 压缩混淆代码,删除无用代码,代码拆分来减少文件体积
  10. 小图片使用雪碧图,图片选择合适的质量、尺寸和格式,避免流量浪费
    原文摘抄

JS中 == 和 === 的区别

== 表示抽象相等,两边值类型不同的时候,会先做隐式类型转换,再对值进行比较
=== 表示严格相等,不会做类型转换,两边的类型不同一定不相等

盒模型

指的是页面在渲染时,DOM元素所采用的布局模式,一个元素占用的空间大小由几个部分组成,内容(content)、内边距(padding)、边框(border)和外边距(margin)。可以通过box-sizing来进行设置,其中IE盒模型的content包含了padding和border,这是区别于W3C标准合模型的地方

image.png

选择器优先级

!important > 行内样式 > id选择器 > class选择器 > 标签选择器 > * > 继承 > 默认

forEach、map和filter的区别

forEach遍历数组,参数为一个回调函数,回调函数接受三个参数,当前元素、元素索引、整个数组
mapforEach相似,遍历数组,但其回调函数的返回值会组成一个新的数组,新数组的索引结构和原数组一致,原数组不变
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()