JavaScript部分
1.ES6的新特性
(1)let: 块级作用域
(2)const: 常量; 块级作用域; 一旦声明则无法进行更改
(3)模板字符串: 使用 `${}` 可以将字符串和其它变量进行拼接, 比使用 + 进行拼接更方便
(4)解构赋值: let { name, age } = { name: '小明', age: 18 }
(5)箭头函数: let fun = ()=>{} 没有属于自己的this, 其this是继承了其所在上下文中的this, 也不能进行实例化(对象的创建)
(6)Promise: 异步编程的一种方案, 用来解决原生 AJAX的回调地狱, 但是其 then 的链式调用还是会形成多层的嵌套
(7)ES6模块: 是对外部的引用,CommonJS是对外部的复制
2.闭包
闭包函数: 声明在一个函数中的函数, 叫做闭包函数(即形成函数的嵌套)
闭包: 内部函数可以访问外部函数中声明的变量
特点: 1) 函数中的变量会长期存在内存当中
2) 避免全局变量的污染
3) 由于其长期存在内存当中, 会增大内存的使用量
4) 使用不当会造成内存泄漏
3.对Promise的理解
Promise是异步编程的一种解决方案,它是一个对象,可以获取异步操作的消息,Promise解决了原生AJAX回调地狱的问题。
(1)Promise的实例有三个状态: pending(进行中)、Resolved(已完成)、Rejected(已拒绝)。
当把一个事件交给Promise时,它的状态就是pending,任务成功完成就是Resolved。
(2)Promise实例有两个状态的改变:
pending -> resolve // 成功返回结果
pending -> reject // 没有成功返回结果
Promise从一个状态已经变成另一种状态时,其状态就不可能再发生改变。结果成果返回时就会执行resolve回调,没有成功返回结果就会执行rejected回调。
(3)Promise的缺点:
无法中途进行取消,Promise一旦建立就必定会执行成功或者失败结果的回调
如果不在Promise内部设置回调函数,则其内部抛出的错误并不会反应到外部
当处于pending状态时,无法得知目前事件进展到了哪一步(是刚刚开始还是即将完成)
4.async/await
带有async关键字的函数其返回值是一个promise对象
其原理就是用迭代器将promise进行了再一次的封装,使得promise可以中间暂停。当函数内部执行到一个await语句的时候,如果语句返回一个promise对象,那么函数将会等待promise对象的状态变为resolve后再继续向下执行。
因此async/await可以将异步逻转化为同步的顺序来进行书写,使得代码更具有可读性。
5.for...in和for...of的区别
(1)for...in是遍历对象的键名; for...of是遍历对象的键值
(2)for...in会遍历整个对象的原型链, 所以for...in的性能要比for...of差
一般对对象的遍历使用for...in,对数组的遍历使用for...of
6.遍历对象的方法
(1)for...in: 遍历对象的键名
(2)for...of: 遍历对象的键值
(3)Object.keys(): 该方法返回一个包含对象自身的所有可枚举属性的数组
(4)Object.values(): 该方法返回一个包含对象自身的所有可枚举属性的值的数组
(5)Object.entries(): 该方法返回一个包含对象自身的所有可枚举属性的键值对数组
7.get与post的区别
get:
(1)一般用于数据资源获取;
(2)浏览器会对get进行缓存;
(3)参数会暴露在url中并且url会被保存在历史记录当中,所以不安全;
(4)对请求的长度有限制(不同浏览器的最长上限不一样),所以不能进行大文件的上传
(5)在历史回退时get并不会向服务器重心发送请求
(6)请求速度比post更快,因为get请求会把header和data一起发送过去,而post会先发送header当服务器响应100的时候再把data发送过去
post:
(1)一般用于对服务器资源产生影响的情景
(2)对请求长度没有限制,其参数是放在request body中,所以相对于get会更加安全
(3)在历史回退时会重新向服务器发送请求
8.箭头函数
箭头函数并没有属于自己this,其当中的this是捕获所在上下文当中this作为自己this的值;
箭头函数不能new出一个对象
9.内存泄漏
1.原理:是指不再使用的内存(变量),未能释放;
2.常见内存泄漏情况:
(1) 意外的全局变量:使用了未声明的变量,而意外创建了一个全局变量,这个变量就会一直留在内存当中无法被收回;
(2) 被遗忘的定时器:在开启了一个定时器用完之后没有清除定时器(setTimeout会自动清除,但是setInterval需要手动进行清除);
(3) DOM元素的引用:当引用了一个DOM元素,后面将DOM元素被删除,但是由于引用一直存在所以此内存也不会被自动收回;
(4) 闭包:闭包会一直常驻于内存当中,用完不清除也会造成内存泄漏;
10.防抖与节流
-
节流:如果事件在规定时间内多次触发,并不会重新计时,只要达到了规定时间就会被触发,并且只触发一次。
-
防抖:如果事件是在规定的时间内再次被触发,则计时器会重新计时,并且只会执行最后一次。
CSS部分
1.文字默认最小为12px,怎么比12px更小
使用缩放:transform: scale(0.5) // 缩小50%,变成6px
2.translate有什么用
根据当前的元素的位置移动元素(根据X轴和Y轴进行移动)
3.transition有什么用
transition是过渡, 元素从一个位置到另一个位置的过渡(并不会直接闪现到终点位置, 而是有动画样的平滑过渡到终点位置)
Vue部分
1.Vue3中父组件调用子组件中的方法
在子组件标签中设置添加ref属性 --> 定义一个ref响应式数据,变量名必须与上一步设置ref的属性值相同 --> 变量名.value.子组件中的方法
在子组件中:
<script setup>
function childFun(){
alert('子组件中的内容被调用了')
}
defineExpose({ // 在子组件中需要用 defineExpose 将需要被调用的变量或方法暴露出去
childFun
})
</script>
在父组件中:
<template>
<div>
<Child ref="child"/>
<button @click="handleClick">点我调用子组件中的方法</button>
</div>
</template>
<script setup>
import { ref } from 'vue';
import Child from './components/Child.vue';
const child = ref() // 变量名必须与 ref 的值相同(获取DOM元素)
function handleClick(){
child.value.childFun() // 调用子组件中的方法
}
</script>
2.在组件全局作用域中箭头函数/对象中的箭头函数/父组件调用子组件全局作用域的箭头函数/父组件调用子组件对象中的箭头函数,此时this的指向
全部指向undefined,因为在Vue中默认开启了严格模式
3.插槽
slot又名插槽,是Vue的内容分发机制,组件内部的模板引擎使用slot元素作为承载分发内容的出口。slot是子组件的的一个模板标签元素,而这个元素是否显示、怎么显示由父组件决定。
slot分为三类:默认插槽、具名插槽和作用域插槽。
默认插槽:当slot没有指定name属性值的时候为默认插槽;
具名插槽:slot带有name属性称为具名插槽;
作用域插槽:当子组件中有数据通过插槽传递给父组件时就称为作用域插槽;
4.父子组件之间传参的方式
1. props传参:父传子、通过传递方法设置返回值也可以实现子传父。
2.Vuex/Pinia传参:任意组件之间都可进行传参。
3.依赖注入provide()/inject():父组件向其任意后代组件中传递参数。
5.生命周期顺序
-
beforeCreate:创建之前;此时data和methods都还未创建,此处无法访问到data、computed、watch、methods中的数据;
-
created:创建完毕; 此时data和methods都创建完毕,此处可以访问data中的数据,也可以使用methods中的方法;
-
beforeMount:挂载之前;此时内存中已经编译好了所有内容,data中的数据和模板已经生成了html,但还html还没有挂载到页面上;
-
mounted:挂载完成;html被渲染到页面上,真正DOM元素,此时可以操作DOM;
-
beforeUpdate:更新之前;响应式的数据被更新是调用,但此时只是数据被更新了,真实DOM还没有被渲染到页面上;
-
updated:更新完成;DOM已经被渲染到页面上,可以对DOM进行操作;
-
beforeDestroy:销毁之前;所有Vue实例被销毁的前一步,此时所有实例均还可以被使用;一般在此时清除开启的定时器;
-
destroyed:销毁完成;此时所有Vue均已经被销毁;
6.子组件和父组件生命周期执行的顺序
加载过程:父组件beforeCreate --> 父组件created --> 父组件beforeMount --> 子组件beforeCreate --> 子组件created --> 子组件beforeMount --> 子组件mounted --> 父组件mounted
更新过程:父组件beforeUpdate --> 子组件beforeUpdate --> 子组件updated --> 父组件updated
销毁过程:父组件beforeDestroy --> 子组件beforeDestroy --> 子组件destroyed --> 父组件destroyed
7.v-for和v-if的优先级
v-for的优先级大于v-if,所以在同一个标签当中同时使用v-for和v-if和会在每次f循环当中都执行一次判断语句,降低了运行效率;所以一般会将v-if放在v-for的父级标签上进行使用。
8.Pinia与Vuex
Pinia与Vuex都是Vue全家桶中的一部分,Pinia其实就是Vuex的迭代版本。虽然Pinia和Vuex都能用在Vue2和Vue3中,但是更加推荐Vue3中用Pinia,Vue2中用Vuex。
-
Vuex
Vuex有五大核心属性:
-
state:用来存放数据,与组件中的data相似。
-
getters:相当于组件中的计算属性。
-
mutation:相同于组件中的methods,但是异步方法不能在这里执行;mutation是修改state中属性值的唯一途径。
-
action:异步操作,专门用来执行异步方法的地方。
-
modules:模块化,如果Vuex中的内容太多,可以将其进行拆分,将拆分的部分整合到modules当中。
-
Pinia
Pinia将Vuex中的五大属性减少到了三个:
-
state:用来存放响应式数据的地方。
-
getters:相当于组件中的计算属性。
-
actions:将Vuex中的mutation和action进行了整合,actions当中既能运行同步方法也能运行异步方法。
-
注意:在Pinia中可以在任何地方对state中的响应式数据进行更改。
9.Vue3与Vue2的区别
-
Vue3中使用slot必须使用v-slot的形式,而Vue2中可以直接使用slot。
-
Vue3中v-for与v-if不会相互冲突,只会把当前v-if当做v-for中的一个判断语句,而Vue2中优先级高的是v-for指令,不建议一起使用。
-
Vue3中app组件中可以没有根标签。
-
数据的响应式原理不同:Vue3使用了Proxy代理,而Vue2使用了Object.defineProperty。
-
生命周期的不同:Vue3中减去了beforeCreate和created使用setup替代了这两个。
-
Vue2使用的是选项式API (Options API) ,Vue3引入了组合式API (Composition API)。
-
Vue2只能有一个根节点,Vue3可以通过 Fragment(<></>)包裹多个根节点。
10.Vue3的优点
Vue3中的Composition API可以更好地组织代码,使代码更加清晰易懂。它可以将相关的逻辑组合在一起,而不是按照生命周期函数进行组织。这使得代码更加易于维护和重用。
Vue3中的TypeScript支持更加完善,可以更好地进行类型检查。Vue3中的API都是使用TypeScript编写的,因此可以更好地与TypeScript集成。这使得开发人员可以更早地发现类型错误,并减少调试时间。
Vue3中的性能比Vue2更好,可以更快地渲染页面。Vue3中使用了Proxy代理对象来实现响应式系统,这比Vue2中使用的Object.defineProperty()方法更快。此外,Vue3中还使用了静态提升和hoist静态节点等技术来优化渲染性能。
实际场景题
如何防止用户在未登录的情况下通过直接输入URL地址绕过登录页面
通过添加前置路由守卫,进行是否进行过登录的判断,如果成功登录过则放行,没有登录过则重定向指定页面。
在这个判断中并不是所有的页面跳转都需要进行判断(例如:进入登录页面就不需要进行是否已经登录的判断),这种情况下就可以设置一个白名单,白名单中的地址就可以直接放行,无需进行判断。
如何实现大文件的上传
将文件进行切片,切成若干个小的片段,将小片段一片一片的发送给后端。