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>
<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>
<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替代了这两个。

10.Vue3的优点

Vue3中的Composition API可以更好地组织代码,使代码更加清晰易懂。它可以将相关的逻辑组合在一起,而不是按照生命周期函数进行组织。这使得代码更加易于维护和重用。

Vue3中的TypeScript支持更加完善,可以更好地进行类型检查。Vue3中的API都是使用TypeScript编写的,因此可以更好地与TypeScript集成。这使得开发人员可以更早地发现类型错误,并减少调试时间。

Vue3中的性能比Vue2更好,可以更快地渲染页面。Vue3中使用了Proxy代理对象来实现响应式系统,这比Vue2中使用的Object.defineProperty()方法更快。此外,Vue3中还使用了静态提升和hoist静态节点等技术来优化渲染性能。

实际场景题

如何防止用户在未登录的情况下通过直接输入URL地址绕过登录页面

        通过添加前置路由守卫,进行是否进行过登录的判断,如果成功登录过则放行,没有登录过则重定向指定页面。

        在这个判断中并不是所有的页面跳转都需要进行判断(例如:进入登录页面就不需要进行是否已经登录的判断),这种情况下就可以设置一个白名单,白名单中的地址就可以直接放行,无需进行判断。

如何实现大文件的上传

        将文件进行切片,切成若干个小的片段,将小片段一片一片的发送给后端。