本文最后更新于 128 天前,其中的信息可能已经有所发展或是发生改变。
共同点都是存储在浏览器本地的,都遵循同源原则(sessionStorage还必须是同一个页面) cookie是由服务端写入的,后两者是前端写入的。 cookie的生命周期是服务端设置好的,sessionStorage在浏览器关闭后就被删除,localStorage生命周期一直存在除非手动删除 cookie的存储空间只有4KB,后两者为5M 在前端请求后端时会自动携带cookie,后两者不会 cookie一般用于存储登录的信息(如sessionId,token),sessionStorage可以用于检测用户是否时页面刷新进入的,localStorage一般用于存储不易改变的数据
基本数据类型:Number、Boolen、String、NaN、Symbol、Null、Undefined、BigInt 复杂数据类型:Object(function),也被称为引用类型,常见的有数组、对象、Math函数等 区别:基本数据类型存储在栈中,数据结构简单,占用空间小,使用比较频繁。复杂数据类型存储在堆中,数据结构复杂,占用空间较大。在栈中存储的是指向堆中的指针地址。
闭包指的是有权访问另一作用域中变量的函数。 闭包会造成内存泄露的问题。 闭包应用:防抖节流
<!-- 防抖节流 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test</title>
</head>
<style>
#btn,
#btn2 {
width: 60px;
border: 1px solid #676767;
padding: 5px 10px;
text-align: center;
user-select: none;
cursor: pointer;
margin-bottom: 10px;
}
</style>
<body>
<div id="btn" title="防抖:一定时间内多次触发事件则重新计时">点击我</div>
<div id="btn2" title="节流:一定时间内多次触发事件只生效一次">点击我</div>
</body>
<script>
let btn = document.getElementById('btn')
// 防抖事件
function fd(fn, time, immediate=false) {
let timer = null;
let isImmidiate = false; // 是否立刻执行
return function () {
if (timer) clearTimeout(timer)
if (!isImmidiate && immediate) {
fn.call(this, arguments)
isImmidiate = true
} else {
timer = setTimeout(() => {
fn.call(this, arguments)
isImmidiate = false
}, time)
}
}
}
// 节流事件
function jl(fn, time) {
let lastTime = 0;
return function () {
let nowTime = new Date().getTime();
let remainTime = time - (nowTime - lastTime);
if (remainTime <= 0) {
fn.call(this, arguments);
lastTime = nowTime;
}
}
}
btn.addEventListener('click', fd(function () {
console.log(this);
console.log('123');
}, 1000, true))
btn2.addEventListener('click', jl(function () {
console.log(this);
console.log('456');
}, 1000))
</script>
</html>
promise是异步编程的解决方案,可以解决回调地狱的问题 有三种状态,分别是pending(执行中)、resolved(成功,也可以是fulfilled)、rejected(失败),一旦状态发生改变就不会再变。 使用new Promise((resolved,rejected)=>{}).then(res=>{}).catch(err=>{})
网页中请求地址的协议、域名、端口号不同,就会产生跨域。 jsonp,通过script标签可以跨域请求资源的特性,将回调函数作为参数拼接在url中,后端收到请求调用该函数,并将数据作为参数返回即可实现跨域。 cors,res.setHeader(‘Access-Control-Allow-Origin’, ‘*’);res.setHeader("Access-Control-Allow-Methods", "GET, PUT, OPTIONS, POST"); nginx反向代理,利用代理服务器和页面同源的特性来实现跨域。 postmessage,H5新增的Api,通过发送和接收API实现跨域。
BFC,块级格式化上下文。页面中独立的渲染区域,不会影响其它的元素。 条件:float是left或right,position是absolute或fixed,overflow不是visible
vuex是vue的状态管理工具。包括actions、state、mutations、getters、module。 其中,state存放数据(通常以对象方式);actions包含异步操作(ajax); mutations包含改变state中数据的方法(同步方法),可通过store.commit调用actions,通过store.dispatch触发getters; getters中定义store的计算属性,可通过store.getters调用;module将store划分成模块。
typeof,可用于判断基本数据类型,判断引用数据类型时,除了函数返回function,其他返回object。 instanceof,不能用于检测symbol,undefined,null。 Object.prototype.toString.call(),判断对象原型链 constructor,用于检测引用数据类型
!important > 行内样式 > 嵌入样式/外链样式(比较同级后面会覆盖前面的)> ID选择器 > Class选择器/伪类选择器/属性选择器 > 标签选择器 > 通配符选择器
回调函数、定时器、迭代器和生成器函数、async/await
1、使用ES6新增语法set 2、使用indexof 3、使用数组方法includes
null指的是变量定义并赋值成null,undefined指的是变量定义但未赋值 console.log(null == undefind) // true console.log(null !== undefind) // true
浮动float常用属性是left、right、none
设置了浮动的元素会脱离文档流,会导致盒子坍塌。
清楚浮动的方法:
1、标签法,在浮动的元素下方添加一个标签,并设置样式clear: both
2、给父元素设置样式overflow: hidden
3、通过伪元素清除浮动。设置样式div::after{content: ''; display: table; clear: both}
箭头函数是ES6新增语法。简化了函数定义,是一种匿名函数。当函数体是单条语句可以省略{}和return。 箭头函数没有自己的this,只能够继承外部函数的上下文,没有arguments,不能够作为构造函数(不能new) 当使用call和apply方法时只传递一个参数(第一个参数也就是this会被忽略) 箭头函数没有原型,没有super,不能使用yield关键字,不能够作为生成器(generator)
都可以改变this的指向。call和apply可以直接调用。 call(this,a,b,c),第二个参数表示具体的函数参数。 apply(this,arr),第二个参数表示函数参数数组。 bind(this),返回一个执行上下文的函数,需要自行调用。 使用场景:call用于对象继承,伪数组转真数组;apply用于找出数组的最大值和最小值以及数组合并;bind用于vue和react中函数指向。
语义化:根据页面结构选择合适的标签。 作用:有利于SEO(搜索引擎优化)、代码可读性更高、利于页面内容的结构化
普通函数指向window,严格模式下为undefined,node环境下指向global 箭头函数本身没有this。继承函数所在上下文 函数中的this,随调用指向谁。
px:绝对像素 em:相对父元素像素 rem:相对根元素像素 vw:视口宽度 vh:视口高度
1、使用弹性盒布局 2、使用transform布局 3、使用table-cell布局
变量提升是指使用var关键字声明的变量在解析时会被提升到最前面。变量声明会被提升,赋值不会被提升。变量提升后在初始化变量后返回的是undefined。 let、const不存在变量提升。let和const声明的变量会形成暂时性死区,为赋初始值直接访问会报错。
两者都是前端路由,hashrouter是监听location的hash值进行实现,特点是地址中含有#,historyrouter是浏览记录的api实现。 相同的url,哈希路由不会添加进历史记录中,history路由会被添加到历史记录中。 historyrouter需要配合后端不然会出现跳转页面返回出现404问题,hash路由不会。 通过window.onhashchange获取url中hash值。 通过history.pushState使用它做页面跳转不会触发页面刷新,使用window.onpopstate监听浏览器的前进和后退
map会改变原数组,返回一个长度和原来一样的新数组。
foreach不会改变原数组,返回undefined。
map处理速度更快,而且可以链式调用。如:arr.map(v=>v*v).filter(v=>v>10)
在js代码执行过程中,遇到同步任务,直接推到调用栈中执行,遇到异步任务,将其挂起,等到有返回值将它推到任务队列中。 当调用栈中所有的同步任务执行完成后,再将任务队列中的异步任务一个一个的推入并执行。 异步任务分为宏任务和微任务,每个宏任务都包含一个微任务队列。 常见的宏任务有:script标签中的代码,定时器,ajax,setImmediate,I/O。 常见的微任务有:promise,Object.observe。
diff算法主要是在虚拟dom树发生改变后,生成dom树的一种更新方式。 通过对比他们之间的差异,将更新补丁直接作用在真实dom树上。以最小成本完成视图更新。 框架会将所有节点转化成vnode,在发生更改后将vnode和更改前oldnode比较,然后以vnode为基准,在oldnode上进行更改。 原本没有新版有则添加,反之,则删除。
用户在访问并登录网站A后会产生一个cookie,用户在没退出网站A继续访问网站B, 网站B收到用户请求返回代码获取用户浏览器上登录网站A的cookie,浏览器直接以用户的权限将cookie返回网站B
攻击者将脚本放在网站A上,在用户访问完网站A的时候运行脚本并获取用户的cookie。
computed有缓存,依赖于其他属性值,只有其他属性值发生改变才会重新计算 watch无缓存,可以进行异步操作,每当坚挺的值发生变化后就会立即回调进行后续操作
为了立刻获取更新后DOM。 Vue中更新DOM是异步的,当数据发生变化后,vue会开启一个异步更新队列,队列中的所有数据更新完才会更新视图。 \$nextTick就解决了这个问题。原理是返回一个promise
浏览器将html文件解析成DOM树,将css解析成stylesheet,然后将DOM树和style结合形成Render树,之后浏览器通过Render树计算出每个元素节点的位置并将其绘制出来
两者都是异步的,区别在于何时执行script脚本。 defer是在加载完JS并且HTMl解析完成后再执行JS脚本 async是在加载完JS就执行JS脚本,会阻塞HTML的渲染
判断是搜索内容还是url 查找本地缓存,如果本地存在直接访问页面(304),反之,进入网络请求阶段 DNS域名解析 三次握手建立TCP连接 合成请求头信息,发送http请求 处理响应数据 四次挥手释放TCP连接 浏览器渲染页面(将html解析成dom树,将css解析成stylesheet,并生成render,通过render计算各个节点位置并绘制到页面上)
盒模型包括标准盒模型和怪异盒模型(IE盒模型) 标准盒模型:box-sizing: content-box(盒子的宽度=width+margin+padding+border) 怪异盒模型:box-sizing: border-box(盒子的宽度=width+margin)
keep-alive是vue的内置组件。通常将数据量多且不易变动的组件放在keep-alive中,起到缓存的作用。 防止因为dom重复渲染,减少资源消耗。 keep-alive有3个属性: include 需要保存的组件 exclude 不需要保存的组件 max 最多能保存的组件数
1、创建一个新的对象。 2、为该对象添加_proto_属性,该属性链接到构造函数的原型对象。 3、为新创建的对象作为this。 4、如果函数有返回值则返回,没有返回值则返回this。
token可以放在cookie中。token一般是用来判断用户是否登录的,它内部包含的信息有:uid(用户唯一的身份标识)、time(当前时间的时间戳)、sign(签名,token 的前几位以哈希算法压缩成的一定长度的十六进制字符串) token可以存放在Cookie中,token是否过期,应该由后端来判断,不该前端来判断,所以token存储在cookie中只要不设置cookie的过期时间就行了,如果 token失效,就让后端在接口中返回固定的状态表示token失效,需要重新登录,再重新登录的时候,重新设置cookie中的token就行了。
token验证流程: 客户端使用账号密码请求登录,服务端收到请求会验证账户名和密码,验证成功后服务端会签发一个token,并发送给客户端。客户端收到token后会把他存储下来。每次客户端发送请求都会携带token,服务端会对它进行验证,验证通过则返回数据。
作用:都是控制元素隐藏和显示的指令 区别: v-show: 控制的元素无论是true还是false,都被渲染出来了,通过display:none控制元素隐藏 v-if: 控制的元素是true,进行渲染,如果是false不渲染,根本在dom树结构中不显示 应用: v-show: 适合使用在切换频繁显示/隐藏的元素上 v-if: 适合使用在切换不频繁,且元素内容很多,渲染一次性能消耗很大的元素上
constructor:完成了数据的初始化。 render:render()函数会将jsx生成的dom插入到目标节点中。在每次组件更新时,react通过diff算法比较更新前和更新之后的dom节点,找到最小的有差异的dom位置并更新,花费最小的开销。 componentDidMount:组件第一次渲染完成,此时dom节点已经生成,在这里调用接口请求,返回数据后使用setState()更新数据后重新渲染。 componentDidUpdate:组件更新完成。每次react重新渲染之后都会进入这个生命周期,可以拿到更新之前的props和state。 componentWillUnmount:在这个生命周期完成组件的数据销毁和卸载,移除所有的定时器和监听。
getDerivedStateFromProps(nextProps,prevState): 代替老版的componentWillReceiveProps()。官方将更新state与触发回调重新分配到了componentWillReceiveProps()中,让组件整体的更新逻辑更加清晰,并且在当前生命周期中,禁止使用this.props,强制让开发者们通过比较nextProps和PrevState去保证数据的正确行为。 shouldComponentUpdate(): return true可以渲染,return false不重新渲染。 getSnapshotBeforeUpdate(prevProps,prevState): 代替componentWillUpdate(),核心区别在于getSnapshotBeforeUpdate()中读取到的dom元素状态是可以保证和componentDidUpdate()中的一致。
一般来说,localstorage定义的数据是默认永久保存在浏览器中的,知道手动删除。 要实现数据的过期(有效时间),可以使用惰性删除和定时删除,原理相差不大。 惰性删除: 惰性删除是指某个键值过期后,该键值不会被马上删除,而是等到下次被使用的时候,才会被检查到过期,此时才能得到删除。实现方法是,获取数据的时候,从存储的数据对象中拿到存储的时间和当前时间做对比,如果超过过期时间就清除Cookie。 定时删除:每隔一段时间执行一次删除操作,并通过限制删除操作执行的次数和频率,来减少删除操作对CPU的长期占用。另一方面定时删除也有效的减少了因惰性删除带来的对localStorage空间的浪费。实现过程,获取所有设置过期时间的key判断是否过期,过期就存储到数组中,遍历数组,每隔1S(固定时间)删除5个(固定个数),直到把数组中的key从localstorage中全部删除。 LocalStorage清空应用场景:token存储在LocalStorage中,要清空。
重排:当DOM的变化影响了元素的几何信息(元素的的位置和尺寸大小),浏览器需要重新计算元素的几何属性,将其安放在界面中的正确位置,这个过程叫做重排 重绘:当一个元素的外观发生改变,但没有改变布局,重新把元素外观绘制出来,这个过程叫做重绘。 重排一定重绘,重绘不一定重排。 可以使用GPU加速(transform)、脱离文档流(定位)、样式集中改变来避免。
为了性能优化 因为vue是虚拟DOM,更新DOM时用diff算法对节点进行一一比对,比如有很多li元素,要在某个位置插入一个li元素,但没有给li上加key,那么在进行运算的时候,就会将所有li元素重新渲染一遍,但是如果有key,那么它就会按照key一一比对li元素,只需要创建新的li元素,插入即可,不需要对其他元素进行修改和重新渲染。 加分回答 key也不能是li元素的index,因为假设我们给数组前插入一个新元素,它的下标是0,那么和原来的第一个元素重复了,整个数组的key都发生了改变,这样就跟没有key的情况一样了。
数组对象中:
字母/文字按照A-Z(a-z)顺序: sorter: (a, b) => a.introduction.localeCompare(b.introduction),
数字按照大小排序:sorter: (a, b) => a.number - b.number,
在javascript中也可以使用这类方法。
import styles from './index.less'
let tbody = data.map(item,index) => {
<tr key={index}>
<td className={index === 6 && item.number < 0 ? styles.orange : (index === 7 && item.number <= 0 ? styles.red : (index === 6 || index === 7 || index === 8 ? styles.black : ''))}>{item.number}
</td>
</tr>
}
这里表示第7行的值如果小于0为橙色,第8行的值如果小于等于0为红色,其他的值为黑色