赋值 浅拷贝 深拷贝
区别是 浅拷贝会相互影响[修改对象中的复杂数据类型中的内容会相互影响]
深拷贝 改变新对象不会影响原对象,他们之间不会互相影响.
const newObj = {} for (let attr in obj) {newObj[attr] = obj[attr]
}
// 这叫改内容
// newObj.info.name = 'yyy'
// 这叫改引用地址,不会影响原来的
newObj.info = { name: 'yyy' }
console.log(obj.info.name) // 'xxx'
方法 浅拷贝的方法
(1) object.assign()
- //浅拷贝
- let obj1 = { name: '张三', action: { say: 'hi'};
- let obj2 = Object.assign({}, obj1);
- obj2.name = '李四';
- obj2.action.say = 'hello'
- console.log('obj1',obj1)
- // obj1 { name: '张三', action: { say: 'hello'}
- console.log('obj2',obj2)
- // obj2 { name: '李四', action: { say: 'hello'}
(2) 展开运算符...
- //浅拷贝
- let obj1 = { name: '张三', action: { say: 'hi'};
- let obj2 = {... obj1};
- obj2.name = '李四';
- obj2.action.say = 'hello'
- console.log('obj1',obj1)
- // obj1 { name: '张三', action: { say: 'hello'}
- console.log('obj2',obj2)
- // obj2 { name: '李四', action: { say: 'hello'}
concat() 和slice()也属于浅拷贝
深拷贝的方法
JSON.parse(JSON.stringify())
- //深拷贝
- let obj1 = { name: '张三', action: { say: 'hi'};
- let obj2 = JSON.parse(JSON.stringify(obj1));
- obj2.name = '李四';
- obj2.action.say = 'hello'
- console.log('obj1',obj1)
- // obj1 { name: '张三', action: { say: 'hi'}
- console.log('obj2',obj2)
- // obj2 { name: '李四', action: { say: 'hello'}
如果图片进入可视区域,就把图片上装地址的某个属性值给图片真实的src
图片顶部距离窗口数值 小于或等于 可视区文档的高度 说明进入了可视区域
getBoundingClientRect()用于获得页面中某个元素的左,上,右和下分别相对浏览器视窗的位置。
- class="imgBox">
- <img src="" data-img="https://www.itcast.cn/images/newslide/homepageandphone/20224109184146299.jpg" alt="" />
- <script>
- const oImg = document.querySelector('img')
-
- window.addEventListener('scroll', function () {
- // 图片顶部距离窗口数值
- // 可视区文档的高度
- if (oImg.getBoundingClientRect().top <= document.documentElement.clientHeight)
- oImg.src = oImg.dataset.img
- })
- script>
图片进入页面的可视区域时,才加载图片 通过导入useIntersectionObserver方法
通过 isIntersection 判断是否进入可视区 当图片进入可视区后把url给 图片真正的src属性
通过浏览器提供的 IntersectionObserver 对象创建一个实例,调用实例的 observe 方法可以观测某个 img 元素;
在 IntersectionObserver 的参数回调里面可以通过 isIntersecting 属性来判断这个 img 元素是否进入可视区;
如果进入就把 img 元素上装地址的某个属性给图片真正的 src 属性。
- class="imgBox">
- <img src="" data-img="https://www.itcast.cn/images/newslide/homepageandphone/20224109184146299.jpg" alt="" />
- <script>
- const oImg = document.querySelector('img')
- 开始观察
- const observer = new IntersectionObserver(([{ isIntersecting }]) => {
- if (isIntersecting) {
- oImg.src = oImg.dataset.img
- //停止观察
- observer.unobserve(oImg)
- }
- })
- observer.observe(oImg)
- script>
全局注册指令
全局注册指令需要使用Vue.directive接口
局部注册指令
对于局部注册 我们需要在钩子函数directives中声明
一 直接注册
1.新建文件夹 2.在文件夹下建立 index.vue 3.在main.js中 引入并注册为全局组件
二 注册为插件
Vue官方提供的插件有 Vue Router、Vuex和Vue 服务端渲染三个 Vue.use可以接受一个对象,Vue.use(obj) 对象obj中需要一个 install 函数 在 Vue.use(obj)时,会自动调用该 install 函数,并传入到 Vue构造器
1. 新建文件夹 2.在文件夹中建立index.vue和index.js 3.在index.js中 引入文件 通过install 函数来注册和导出插件 4.在main.js中 use使用插件
在src/components文件夹下新建yyy文件夹,在yyy文件夹下新建index.vue文件
- <div>
- 通过注册插件的方式,注册全局组件
- div>

在全局前置路由守卫(beforeEach)里面设置
如果有token就放行,如果没有token 先判断是否在白名单中,如果在白名单中直接放行.如果不在白名单中就返回登录页 处理token失效问题 在响应拦截器中判断状态码401 是就跳转到登录页
1.用户登录后 ,后端返回当前用户的标识.
2.前端拿到这个标识后,筛选出 有权限的路由(动态路由)
3.接下来做了两件事
3.1.页面级别权限 通过addrouters或者 addrouter将路由添加在路由表中,一旦添加到这个路由表中 这个用户也就有了访问某个路由的权限.
3.2.把筛选后的 路由也添加一份到vuex中 为了后面对左侧菜单栏的渲染
封装一个全局的指令 这个方法只做一件事 ,接受一个功能标识,看一下这个标识在不在后端返回的数据列表中,如果有的话就返回一个true ,如果没有的话就返回一个false .
在做权限控制的地方,调用这个方法并传递过去当前的功能标识,根据这个方法泛会所true还是false,对当前的按钮进行隐藏或显示操作 禁用或启用操作
是什么
promise是ES6新增语法 用来解决回调地狱
怎么用
一般作为一个构造函数来使用,需要new一下来创建一个Promise实例 ,它里面有三种状态 分别是pending(进行中) fulfilled(已成功) rejected(已失败),成功会触发then 失败会触发catch,finally是永远都会触发
Promise的静态方法
1.Promise.race():接收多个Promise实例,可以得到最先处理完毕的结果(结果可能是成功的也可能是失败的)
2.Promise.all():接收多个Promise实例,都成功了会触发then,有一个失败的就会出发catch
3.Promise.any():接收多个Promise实例,可以得到最先处理成功的结果,都失败才会触发catch
解决问题
解决了回调地狱的问题
替代方法
Promise虽然解决了回调地狱问题,但是不能简化代码,所以一般工作中,我会配合async/await来使用
1.创建一个空对象
2.this指向这个对象
3.执行构造函数的代码,给空对象增加属性方法
4.返回这个对象
原型链:多个对象之间通过 `__proto__` 链接起来的这种关系就是原型链。
兼容性
还是兼容到IE8 history兼容到IE10
实现原理
hash模式是通过监听onhasgchange事件做的处理
history模式是利用H5新增的History相关的API实现例如onpopstate事件,pushState,replaceState等
刷新页面时,对于后端的表现
刷新页面是,还是地址也就是(#后面的内容)不会作为资源发送到服务端,后端拿到的都是/这个地址
https://www.baidu.com/#/news https://www.baidu.com/#/user
刷新页面时,history地址对于服务端来说是一个新的请求,后端拿到的是不同的请求地址,也就意味着需要服务端对这些请求做处理,否则会 404。
https://www.baidu.com/news https://www.baidu.com/user
做什么处理呢?匹配到相关 GET 请求,统一返回 index.html,index.html 加载的有路由相关的代码,所以也就转换为由前端路由来处理啦。
1.将图片的域名解析为ip地址
2.http三次握手建立起安全的网络协议,保证http传输的可靠性
3. 建立起http连接
(1) 客户端发送请求
(2) 服务器处理请求
(3)服务器响应请求
4.渲染引擎
(1)解析html :将得到dom树
(2)解析css :将得到样式树
(3)将dom树 + 样式树 合并成 渲染树
(4)绘制渲染树
(5)呈现页面
项目开发中遇到的问题
当项目打包上线后,需要修改一些数据时,用户需要刷新才能获取到最新的数据
如何使用户不刷新也能拿到最新的数据
这和浏览器的缓存机制和webpack的打包机制有关
hash一般是结合CDN缓存来使用,通过webpack构建之后,生成对应文件名自动带上对应的MD5值。如果文件内容改变的话,那么对应文件哈希值也会改变,对应的HTML引用的URL地址也会改变,触发CDN服务器从源服务器上拉取对应数据,进而更新本地缓存。
1.在浏览器缓存机制中,获取数据分为强缓存和协商缓存,协商缓存的数据保存在浏览器缓存中,用户获取数据时 只能从以及保存的缓存中获取文件名未修改,即使里面内容发生了修改,获取数据时还是从缓存中修改,无法获取到操作后的数据
2. 在webpack打包机制中 配置output出口时配置 filename 来打包文件名,此时我们只需要将文件吗修改,便可以解决这一问题. 将配置改为 filename:'[name].[contexthash].js' 操作可以修改文件名
Vue出于对性能的考虑,对应的路由组件会被复用,也就意味着,几遍路由参数发生了变化,路由组件生命周期钩子也就只会触发一次(路由地址会发生变化),但是加载的组件是同一个,所以路由只会获取到旧数据

在路由出口处 加:key 检测key的变化,通过$route.fullpath

watch监听路由地址变化,根据地址变化后的新值来发送请求
- watch(()=>route.params.id,
- (newId)=>{
- getDetail(newId as string)
- })

vue内置方法,当路由参数发生变化时,执行钩子函数,走对应的回调,to 表示要到达的路由对象
- onBeforeRouteUpdate((to)=>{
- getDetail(to.params.id as string)
- })
em相对于元素自身字体大小的一个单位,rem是相对于根元素字体大小的一个单位
元素字体大小的单位
解决移动端适配问题
原理 利用媒体查询或js动态检测设备宽度,不同宽度下设置对应的根元素的字体大小,根元素字体大小发生变化,所有使用rem做单位的元素也发生变化
开发中有使用VW/ rem做适配是对vw的模拟
全局的状态管理的js库
解决了非关系性组件之间的传递和数据共享的问题,其中有state mutations,actions getters
一般用来存储token和用户信息
当组件中关系比较清晰时,会利用其他方式 父子组件 在父组件中的子组件标签上利用自定义属性来传递数据 在组件中通过props来接收传递过来的数据 祖孙组价中 proviede 提供数据 inject获取数据.
把要绑定的事件绑定给他的祖先元素
原理是事件冒泡
好处;性能搞 2.对后续新增的元素同样具有绑定的效果
防抖 持续触发不执行,停止触发后一段时间才会执行 节流 持续触发频率变低
防抖应用场景 input输入框事件
节流应用场景onload下拉加载事件
1.第一个参数都是用来改变this指向
2.都可以利用后续参数来传参
不同点
call和apply会直接调用函数,而bind返回的是一个新函数
call和bind可以传递任意多个参数,而apply只能传递两个参数(第二个参数是数组或者伪数组)
call和apply是立即执行,而bind是获取到修改后的this后才执行
对箭头函数的理解
箭头函数是ES6新增语法
1.箭头函数没有原型对象 prototype,不能作为构造函数使用(不能被new)
2.箭头函数没有arguements ,可以使用...拿到所有实参的集合数组
3.箭头函数中的this在定义时就已经确定,取决于父级的环境
4.箭头函数不能通过call,apply,bind来修改他的this指向
evenloop 事件循环
js代码分同步代码和异步代码 ,先执行同步代码后执行异步代码
同步代码会直接在执行栈中执行,异步代码添加到异步任务队列中,同步代码执行完毕后 执行异步代码中的微观,后执行宏观任务
常见的宏观任务 settimeout定时器 fs.readFile读取文件 ajax请求 事件
常见的微观任务 async /await promise.then