前端2024年3月面试题个人总结

684 阅读21分钟

CSS基础

JavaSrcipt基础

1,[]==[] 对比为true还是false
[]==[] // false
[]===[] // false

两边的数据类型都是对象,所以比较的是引用地址,地址不同所以都是false
2,检测数组的方法有哪些 || 区分数组和对象的方法?
  • toString 方式

Object.prototype.toString.call(val) === '[object Array]' // true 代表为数组

  • Array.isArray 方法

ES5中提供了 isArray 方法用来判断值是否为数组

Array.isArray(val) // true 代表为数组

  • instanceof 方式

val instanceof Array // true 代表为数组

为什么 instanceof 可以用来判断数组而不可以判断对象呢?因为数组本身就是一个类似于列表的高阶对象。

  • constructor 方式

val?.constructor === Array // true 代表为数组

  • Object.getPrototypeOf 方式

Object.getPrototypeOf(val) === Array.prototype // true 代表为数组

  • isPrototypeOf 方式

isPrototypeOf() 方法用于测试一个对象是否存在于另一个对象的原型链上。

Array.prototype.isPrototypeOf(val) // true 代表为数组

3,讲讲你对堆和栈的理解

栈: 栈会自动分配内存空间,会自动释放,存放基本类型,简单的数据段,占据固定大小的空间;

堆: 动态分配的内存,大小不定也不会自动释放,存放引用类型,指那些可能由多个值构成的对象,保存在堆内存中,包含引用类型的变量,实际上保存的不是变量本身,而是指向该对象的指针。

4,讲一下微任务和宏任务
  • 微任务:Promise.then Process.nextTick
  • 宏任务:Ajax请求,setTimeout,setInterval,setImmediate, script
  • 执行顺序:在异步队列中先查找是否有微任务,执行完所有微任务后,执行下一个宏任务,执行完每一个宏任务后,都会检查是否还存在待执行的微任务,如果有,就执行完微任务,再继续执行下一个宏任务。
5,继承有哪些
  1. 原型链继承:利用原型让一个引用类型继承另一个引用类型的属性和方法,这种方式有一个缺点,即所有的实例共享原型对象,如果一个实例修改了原型对象,其他实例的属性和方法也会受到影响。
  2. 构造函数继承:在子类构造函数内部调用父类构造函数,从而实现对父类实例属性的继承
  3. 组合继承:将原型链继承和构造函数继承结合起来的一种继承方式。
  4. 寄生继承:通过创建一个实现继承的函数,然后在函数内部以某种方式增强对象,最后返回这个对象。
6,原型链继承和构造函数继承有什么区别
  • 构造函数继承无法继承父类原型对象上的属性和方法。
  • 构造函数需要改变this指向继承。
  • 求大佬补充。。
7,map对象和普通对象的区别
  • Map可以是任意类型的数据,而普通对象的键只能是字符串类型。
  • Map对象会保持插入顺序,而普通对象不保证键值对的顺序。
  • Map对象有一些特定的方法来操作和访问键值对,而普通对象使用点语法或方括号语法来操作和访问键值对。
  • Map对象的键值对数量可以通过size属性获取,而普通对象需要手动计算键值对的数量。
8,for...in和for...of的区别
  • for…of 遍历获取的是对象的键值,for…in 获取的是对象的键名;
  • for… in 会遍历对象的整个原型链,性能非常差不推荐使用,而 for … of 只遍历当前对象不会遍历原型链;
  • 对于数组的遍历,for…in 会返回数组中所有可枚举的属性(包括原型链上可枚举的属性),for…of 只返回数组的下标对应的属性值
9,typeOf和instanceof的区别
  • typeOf:typeof用于基本数据类型的类型判断,返回值都为小写的字符串
  • instanceof: instanceof 利用原型链继承关系做判断,主要的是用来检测引用类型,返回值是truefalse
// 模仿indtsnceof实现的代码
function myInstanceof(leftA ,style){
    left = left.__proto__;
    if(left === nill ll !style) return false;
    else if(style.name ===left) return true;
    return myInstanceof(leftA,style);
  }
10,讲讲你对Promise的理解?Promise的属性?为什么Promise 可以一直 .then?
  • Promise 是异步编程的一种解决方案,其实是一个构造函数,自己身上有all、reject、resolve这几个方法,实例对象上有then、catch等方法;Promis执行后的内部都会返回一个新的Promise对象,且默认状态都是resolved,所以才能一直then下去
11, 深拷贝和浅拷贝的区别
  • 浅拷贝(shallow copy):只复制指向某个对象的指针,而不复制对象本身,新旧对象共享一块内存。
  • 深拷贝(deep copy):复制并创建一个一模一样的对象,不共享内存,修改新对象,旧对象保持不变。
12, map, filter, reduce,find,forEach
  • forEach 只是简单的遍历数组。
[1,2,3].forEach(num => numconsole.log(num))
  • map 遍历原数组,生成新的数组,将数组的每一个元素拿出来处理完成之后在放回去
[1,2,3] .map(num => num > 10 ? num : '0' + num)
  • filter 遍历数组,生成新的数组,判断每一个值得返回结果是否为true,是true的放进去
[1,2,3].filter( num => num > 1 ) // [2 ,3]
  • reduce主要是为了对所有数组进行累加,最后返回一个值,不改变原数组
[1,2,3] .reduce((add ,val ,index ,arr) => add +val ,0)
  • find 遍历数组找到第一个与之匹配的值
[1,2,3].find(num => num >1)

EcmaScript6.0

13, 调用new干了什么?
  • 创建一个新的对象
  • 将对象里面的this指向这个新的对象
  • 将新对象连接到构造函数的原型
  • 返回这个对象
14, instanceof 的原理
  • instanceof主要的作用是判断对象的正确类型。
  • 他的内部原理是通过判断原型链中能不能找到类型的原型Object,Array
// 模仿indtsnceof实现的代码
function myInstanceof(leftA ,style){
  left = left.__proto__;
  if(left === nill ll !style) return false;
  else if(style.name ===left) return true;
  return myInstanceof(leftA,style);
}
15, 箭头函数与普通函数的区别
  • 箭头函数比普通函数更加简洁
  • 箭头函数没有自己的this
  • 箭头函数继承来的this指向永远不会改变
  • call()、apply()、bind()等方法不能改变箭头函数中this的指向
  • 箭头函数不能作为构造函数使用
  • 箭头函数没有自己的arguments
  • 箭头函数没有prototype
  • 箭头函数不能用作Generator函数,不能使用yeild关键字
16, var let const 的区别
  • var 会变量提升let和const不会
  • var 在全局命名的变量会挂载到window上,let const不会
  • let 和cosnt 有块级作用(暂时性死区),var没有
  • let const 不允许重复命名
17, Proxy
  • Proxy用于修改某些操作的默认行为
  • Proxy可以理解为对在目标对象上面设置一层拦截
var obj = new Proxy({},{
    get: function (target,key, receiver) {
        console.log(`getting ${key}!`);
        return Reflect.get(target,key, receiver);
    },
    set: function (target,key, value, receiver)
        console.log(`setting ${key}!`);
        return Reflect.set(target,key,value, receiver);
    }
});
obj.count =1
// setting count!
++0bj.count
// getting count!
// setting count!
// 2
18,Promise

Promise表示一个异步操作的最终结果,以之交互的方式主要有then方法,该方法主要注册 了二个回调函数,用于接收Promise的最终结果和不能执行的原因。

  1. Promise的状态主要有三种等待,执行,拒绝
  • 等待Pending 等待进入执行或拒绝状态;
  • 执行resolve不能进入其他状态,有一个不可变的最终结果
  • 拒绝Rejected 不能进入其他状态,有一个不可变得拒绝原因
  1. Promise.then(onResolve, onRejected) then接收二个参数
  • 如果onResolve不是函数,其必须被忽略
  • 如果onRejected不是函数,其必须被忽略
  1. onResolve 特性
  • promise执行结束后其必须被调用,第一个值就是promise的结果。
  • promise结束前不可以被调用。
  • onResolve调用次数不可以大于一次。
  1. onRejected特性
  • promise被拒绝执行后其必须被调用,其第一个参数为promise的拒绝原因
  • promise结束前不可以被调用。
  • onRejected调用次数不可以大于一次。
  • onResolve 和 onRejected必须被作为函数调用(即没有this值)
  1. 多次调用
  • then 方法可以被同一个promise调用多次
  • 当promise成功执行时,所有onResolve需按照其注册顺序依次回调
  • 当 promise 被拒绝执行时,所有的onRejected需按照其注册顺序依次回调
  1. 返回
  • then方法必须返回一个promise对象(这也是上文说的为什么可以一直 .then的原因)
19, const对象的属性可以修改吗
  • const保证的并不是变量的值不能改动,而是变量指向的那个内存地址不能改动。对于基本类型的数据(数值、字符串、布尔值),其值就保存在变量指向的那个内存地址,因此等同于常量。

  • 但对于引用类型的数据(主要是对象和数组)来说,变量指向数据的内存地址,保存的只是一个指针,const只能保证这个指针是固定不变的,至于它指向的数据结构是不是可变的,就完全不能控制了。

20, Object.is()

ES5 比较两个值是否相等 相等运算符() 和严格相等运算符(=)。它们都有缺点,前者会自动转换数据类型,后者 的NaN不等于自身,以及+0等于-0。JavaScript缺乏一种运算,在所有环境中,只要两个值 是一样的,它们就应该相等。

+0 === -0 //true
NaN === NaN // false

0bject.is(+0,-0) // false
0bject.is(NaNNaN) //true
21, Object.assign

Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对 象(target)。

const target= {a:1};
const source1 = { b:2};
const source2 = { c: 3 };
0bject.assign(target,source1,source2);
target // {a:1,b:2,c:3}

Vue

1, Vue里面computed是什么东西怎么用?
  • 在vue模板里面使用表达式是非常便利的,但是设计它们的初衷是用来简单运算的。在实际开发过程中在模板里面放入过多的表达式会让项目可维护性大大降低。
<div>
{{ data.split('') ? data.split('').reverse().join('') : data.split('')}}
</div>
  • 对于这种复杂计算的数据,我们应该使用计算属性来解决;
  • 计算属性中的方法是依赖于其中的值得,当计算属性中的值发生变化的时候,计算属性会更新
var vm = new Vue({
el:'#example'
data: {
data:'Hello'
},
computed: {
//计算属性的 getter
reversedMessage:function (){
// `this` 指向 vm 实例
   return this.data.split('').reverse().join('')
})

  • 当this.data的值发生变化的时候,他所依赖的计算属性reversedMessage会重新计算并且调用
2, Vue里面的watch是什么东西怎么使用
  • 虽然计算属性在大部分情况下都适用,但是在实际开发过程中需要一些自定义的监听器,当需要在执行异步或者一些开销比较大的操作中,监听器会比计算属相更加有效。
    watch:{
    // 需要监听的值
    question(){
     }
    }
计算属性和监听器看上去是差不多的,但是还是有区别。
3, watch和computed的区别
  1. 对于Computed:
  • 它支持缓存,只有依赖的数据发生了变化,才会重新计算
  • 不支持异步,当Computed中有异步操作时,无法监听数据的变化
  • computed的值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data声明过,或者父组件传递过来的props中的数据进行计算的。
  • 如果一个属性是由其他属性计算而来的,这个属性依赖其他的属性,一般会使用computed
  • 如果computed属性的属性值是函数,那么默认使用get方法,函数的返回值就是属性的属性值;在computed中,有一个get方法和一个set方法,当数据发生变化时,会调用set方法。
  1. 对于Watch:
  • 它不支持缓存,数据变化时,它就会触发相应的操作
  • 支持异步监听
  • 监听的函数接收两个参数,第一个参数是最新的值,第二个是变化之前的值
  • 当一个属性发生变化时,就需要执行相应的操作
  • 监听数据必须是data中声明的或者父组件传递过来的props中的数据,当发生变化时,会触发其 他操作,函数有两个的参数:
<template>
	<div></div>
</template>
<script>
	export default {
		data(){
			variable:null,
		},
		watch:{
			variable:{
				// 此处监听variable变量,当期有变化时执行
				handler(newV,oldV){
					// newV为新值,oldV为旧值
				},
                                immediate: true,
                                deep:true
			}
		}
	}
      immediate:组件加载立即触发回调函数
      deep:深度监听,发现数据内部的变化,在复杂数据类型中使用,例如数组中的对象发生变化。需要注意的是,deep无法监听到数组和对象内部的变化。当想要执行异步或者昂贵的操作以响应不断的变化时,就需要使用watch。
</script>
4,vue-router有哪几种导航钩子

vue一共有3种导航钩子

  1. 全局钩子
  • 其中全局导航钩子有三种,前置守卫,后置钩子和全局解析守卫
  • 前置守卫router.beforeEach
  • 后置守卫router.afterEach
  • 解析守卫router.beforeResolve
  • 其中解析守卫是在2.5版本中新增加的。解析和router.beforeEach类似,区别是:在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用
  1. 路由独享钩子
  • 即单个路由独享的导航钩子,他是在路由配置上直接定义的。
cont router = new VueRouter({
    routes: [
    path: '/file',
    component: File,
    beforeEnter:(to,from,next)
    // do someting
}
]
});
  1. 组件内导航钩子
  • 组件内的导航钩子主要有这三种:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave。他们是直接在路由组件内部直接进行定义的
const File = {
    template:`<div>This is file</div>
    beforeRouteEnter(to,from,next)
        // do someting
        // 在渲染该组件的对应路由被confirm 前调用
    },
    beforeRouteUpdate(to,from,next){
        // do someting
        //在当前路由改变,但是依然渲染该组件是调用
    beforeRouteLeave(to,from ,next){
        // do someting
       // 导航离开该组件的对应路由时被调用
   }
}
5, 导航解析流程说一下
  1. 导航被触发
  2. 在失活的组件里调用离开守卫
  3. 调用全局的beforeEach 守卫
  4. 在重用的组件里调用beforeRouteUpdate守卫
  5. 在路由配置里调用beforEnter
  6. 解析异步路由组件
  7. 在被激活的组件里调用beforeRouteEnter
  8. 调用全局的beforeResolve 守卫
  9. 导航被确认
  10. 调用全局的afterEach 钩子
  11. 触发 DOM 更新
  12. 在创建好的实例调用beforeRouteEnter守卫中传给next的回调函数
6,vuex是什么?怎么使用?哪种功能场景使用它?
  1. Vuex 是一个专为Vue.js应用程序开发的状态管理器,采用集中式存储管理应用的所有组件的状态。
  • state Vuex store实例的根状态对象,用于定义共享的状态变量.
  • Action -动作,向store发出调用通知,执行本地或者远端的某一个操作(可以理解为store的methods)
  • Mutations -修改器,它只用于修改state中定义的状态变量。
  • getter -读取器,外部程序通过它获取变量的具体值,或者在取值前做一些计算(可以认为是store的计算属性)
  1. vuex 的使用场景:
  • 数据需要在多个组件里面来回调用的
  • 全局都要使用的方法,并且方法是需要保存不被浏览器清理掉的。
  • 组件需要保存的数据
7, vue-loader是什么
  • 解析和转换.vue 文件,提取出其中的逻辑代码script、样式代码 style、以及 HTML 模版
  • template,再分别把它们交给对应的Loader去处理。
  • css-loade: 加载由vue-loader提取出的CSS代码。
  • vue-template-compiler:把vue-loader提取出的 HTML 模版编译成对应的可执行的
  • JavaScript代码,这和React中的JSX语法被编译成JavaScript代码类似。预先编译好HTML 模版相对于在浏览器中再去编译HTML 模版的好处在于性能更好。

总结:ue-loader的作用就是提取。

8,$nextTick是什么?

因为vue是异步更新的,$nextTick是用来知道什么时候DOM更新完成的

  • vue在观察到数据发生变化的时候不会直接更新DOM的,而是开启一个队列,并缓冲在同一 个事件循环中发生的所以数据改变,在缓冲时会去除所有的重复数据。从而避免不必要的 DOM操作和计算。在下一个事件循环Vue刷新队列并执行实际(已去重的)工作 Vue会根据当前浏览器环境优先使用原生的Promise.then和MutationObserver,如果都不支 持,就会采用setTimeout代替。
  • 理论上,我们应该不用去主动操作DOM,因为Vue的核心思想就是数据驱动DOM,但在很多 业务里,我们避免不了会使用一些第三方库,比如popper.js、swiper等,这些基于原生 javascript的库都有创建和更新及销毁的完整生命周期,与Vue配合使用时,就要利用好 $nextTick。
9,说一下Vue的生命周期

Vue实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模版、挂载Dom ->渲染、 更新-> 渲染、卸载等一系列过程,称这是Vue的生命周期。

  1. beforeCreate(创建前)
  2. created(创建后)
  3. beforeMount(挂载前)
  4. mounted(挂载后)
  5. beforeUpdate(更新前)
  6. updated (更新后)
  7. beforeDestroy(销毁前)
  8. destroyed(销毁后) 另外还有keep-alive独有的生命周期,分别为activated和 deactivated .用 keep-alive包裹的组件在切换时不会进行销毁,而是缓存到内存中并执行deactivated 钩子函数,命中缓存渲染后会执行activated 钩子函数。
10,Vue 子组件和父组件执行顺序

加载渲染过程:

  1. 父组件beforeCreate
  2. 父组件 created
  3. 父组件beforeMount
  4. 子组件beforeCreate
  5. 子组件 created
  6. 子组件beforeMount
  7. 子组件mounted
  8. 父组件 mounted

更新过程:

  1. 父组件beforeUpdate
  2. 子组件beforeUpdate
  3. 子组件updated
  4. 父组件 updated

销毁过程:

  1. 父组件beforeDestroy
  2. 子组件beforeDestroy
  3. 子组件destroyed
  4. 父组件 destoryed
11,keep-alive 中的生命周期哪些

keep-alive是Vue提供的一个内置组件,用来对组件进行缓存--在组件切换过程中将状态保留在 内存中,防止重复渲染DOM。 如果为一个组件包裹了keep-alive,那么它会多出两个生命周期:deactivated、activated。同 时,beforeDestroy 和 destroyed 就不会再被触发了,因为组件不会被真正销毁。 当组件被换掉时,会被缓存到内存中、触发deactivated 生命周期;当组件被切回来时,再去缓存

12,vue中keep-alive组件的作用

keep-alive:主要用于保留组件状态或避免重新渲染。 当二个组件被很频繁的调用的时候可以使用keep-alive标签进行缓存,这样页面就会从缓存 中快速渲染,而不是重新渲染。

<!-- 逗号分隔字符串-->
</keep-alive include="a,b>
   <Component :is="view"></Component>
</keep-alive>
<!-- 正则表达式(使用`v-bind`) -->
    <keep-alive :include="/alb/">
    <component :is="view"></component
 </keep-alive>
  <!--数组(使用“v-bind`) -->
 <keep-alive :include="['a''b']">
    <component :is="view"></component>
</keep-alive>
  • include 和 exclude属性允许组件有条件地缓存。二者都可以用逗号分隔字符串、正则表达式或一个数组来表示
  • include 字符串或正则表达式。只有名称匹配的组件会被缓存。
  • exclude 字符串或正则表达式。任何名称匹配的组件都不会被缓存。
  • max 数字,最多可以缓存多少组件实例。《*2.5.0 新增》 里找这个组件、触发activated钩子函数。
13,vue组件的scoped属性的作用

当 style 标签有scoped属性时,它的CSS只作用于当前组件中的元素 你可以在一个组件中同时使用有scoped和非scoped 样式

<style>
/*全局样式 */
</style>
<style scoped>
/* 本地样式 */
</style>

但有时在vue-cli 中引入UI库后,修改UI库一些样式,可能不生效。

14,v-if和v-show的区别
  • v-if是动态的向DOM树内添加或者删除DOM元素;v-show是通过设置DOM元素的display样式属性控制显隐;
  • v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听
  • v-show只是简单的基于css切换;
  • v-if是惰性的,如果初始条件为假,则什么也不做;只有在条件第一次变为真时才开
  • v-show是在任何条件下,无论首次条件是否为真,都被编译,然后被缓存,而且DOM元素保留;
  • v-if有更高的切换消耗;v-show有更高的初始渲染消耗;
  • v-if适合运营条件不大可能改变;v-show适合频繁切换。
15,什么是 mixin ?
  • Mixin 使我们能够为Vue组件编写可插拔和可重用的功能。
  • 如果希望在多个组件之间重用一组组件选项,例如生命周期hook、方法等,则可以将其编写为mixin,并在组件中简单的引用它。
  • 然后将 mixin的内容合并到组件中。如果你要在mixin中定义生命周期hook,那么它在执行 时将优化于组件自已的hook。
16,Vue组件通信
  1. 父子组件通信:
  • props / $emit(父组件通过props向子组件传递数据,子组件通过$emit和父组件通信)
  • ref / $refs(这种方式也是实现父子组件之间的通信。)
  • $parent / $children
  1. eventBus: $emit / $on (eventBus事件总线适用于父子组件、非父子组件等之间的通信)
  2. 跨组件通信:
  • provide / inject(父子组件之间的通信,也可以是祖孙组件,在层数很深的情况下)
  • $attrs / $listeners :
  • $attrs:继承所有的父组件属性(除了prop传递的属性、class 和style),一般用在子组件的子元素上
  • $listeners:该属性是一个对象,里面包含了作用在这个组件上的所有监听器,可以配合on="$listeners"将所有的事件监听器指向这个组件的某个特定的子元素。(相当于子组件继承父组件的事件)
  • vuex: 专为Vue.js应用程序开发的状态管理器,是一个全局通用,缺点:页面刷新数据会丢失。
17,解决vuex页面刷新数据丢失问题
  1. 将vuex中的数据直接保存到浏览器缓存中(sessionStorage、localStorage、cookie)
  2. 在页面刷新的时候再次请求远程数据,使之动态更新vuex数据
  3. 在父页面向后台请求远程数据,并且在页面刷新前将vuex的数据先保存至sessionStorage(以防请求数据量过大页面加载时拿不到返回的数据)
18, Vue3中 reactive 和ref 区别
  • reactive参数一般接受对象或数组,是深层次的响应式。ref参数一般接收简单数据类型,若ref接收对象 为参数,本质上会转变为reactive方法
  • 在JS中访问ref的值需要手动添加.value,访问reactive不需要
  • 响应式的底层原理都是Proxy
19,vue如何优化首屏加载速度?

将引用的外部js、css文件剥离开来,不编译到vendor.js中,而是用资源的形式引用,这样浏 览器可以使用多个线程异步将vendor.js、外部的js等加载下来,达到加速首开的目的。外部 的库文件,可以使用CDN资源,或者别的服务器资源等。

  1. 大文件定位:我们可以使用webpack可视化插件Webpack Bundle Analyzer查看工程js 文件大小,然后有目的的解决过大的js文件。
  2. 路由的按需加载
  3. 将JS文件引入方式放在body 的最后
  4. 用文档的cdn文件代替npm安装包
用文档的cdn文件代替,而不用打包到vender里面去
<script src="https://cdn.bootcss.com/vue/2.3.3/vue.min.js"></script>
<script src="https://cdn.bootcss.com/axios/0.16.2/axios.min.js"></script>
  1. UI库的按需加载:一般UI库都提供按需加载的方法,按照文档即可配置.
  2. 开启 Gzip 压缩 在config/index.js 设置productionGzip为true,开启 Gzip 压缩
20,说一说相比 vue3.x 对比 vue2.x变化
  1. 源码组织方式变化:使用TS 重写
  2. 支持 Composition API: 基于函数的API,更加灵活组织组件逻辑(vue2用的是optionsapi)
  3. 响应式系统提升:Vue3中响应式数据原理改成proxy,可监听动态新增删除属性,以及数组变化
  4. 编译优化:vue2通过标记静态根节点优化diff,Vue3 标记和提升所有静态根节点,diff的时候只需要对比动态节点内容
  5. 打包体积优化:移除了一些不常用的api (inline-template、filter)
  6. 生命周期的变化:使用setup代替了之前的beforeCreate和created
  7. Vue3 的 template 模板支持多个根标签
  8. Vuex状态管理:创建实例的方式改变,Vue2为new Store,Vue3为createStore
  9. Route 获取页面实例与路由信息:vue2通过this获取router实例,vue3通过使用getCurrentInstance/ userRoute和userRouter方法获取当前组件实例
  10. Props 的使用变化:vue2 通过 this 获取 props 里面的内容,vue3直接通过 props
  11. 子组件传值:vue3 在向父组件传回数据时,如使用的自定义名称,如backData,则需要在 emits 中定义一下

React

1,Hooks

Hook是 React 16.8 的新增特性。它可以让你在不编写class 的情况下使用 state 以及其他的 React 特性。通过自定义hook,可以复用代码逻辑。

 // 自定义一个获职订阅数据的hook
 function useSubscription(){
    const data = Datasource.getComments();
    return [data];
}
function Commentlist(props){
    const {data} = props;
    const [subData] = useSubscription();
...
}
 // 使用
 <Commentlist data='hello' />

hook的优点如下:

  • 使用直观;
  • 解决hoc的prop 重名问题;
  • 解决render props 因共享数据而出现嵌套地狱的问题;
  • 能在return之外使用数据的问题。 需要注意的是:hook只能在组件顶层使用,不可在分支语句中使用。

总结:Hoc、render props和hook都是为了解决代码复用的问题,但是hoc和render props都有特 定的使用场景和明显的缺点。hook是react16.8更新的新的API,让组件逻辑复用更简洁明了,同时 也解决了hoc和render props的一些缺点。

2,高阶组件

高阶组件(High-Order Component)接受React组件作为输入,输出一个新的React组件。

  • 高阶组件不是组件,是增强函数,可以输入一个元组件,输出一个新的增强组件
  • 高阶组件的主要作用是代码复用,操作状态和参数 实现高阶组件的方法:
  • 属性代理(props proxy)。高阶组件通过被包裹的React组件来操作props .
  • 反向继承(inheritance inversion)。高阶组件继承于被包裹的React组件。

网络篇

什么是同源策略和跨域问题?

同源策略和跨域问题

浏览器因为安全的原因,有一套策略,叫做同源策略。这套策略只在浏览器端才会有. 当你的请求协议、域名或者端口有一个不同就会跨域。 跨域时,浏览器实际上是拿到数据的,但是浏览器不会将数据给你,所以你也就没有办法获取到数据。 跨域主要的作用是防止CSRF攻击,简单点说,CSRF攻击是利用用户的登录态发起恶意请求。 解决跨域的方案:

  • JSONP 使用script标签向后台请求数据,但是只适用于get请求。
  • CORS是让服务端设置Access-Control-Allow-Origin,这样浏览器就不会包跨域错误。
  • 反向代理 是搭建一个自己的服务器,让我的服务器请求数据,拿到数据之后在放回给我自己。
http和https的区别
  1. https协议需要到ca申请证书,般免费证书较少,因而需要一定费用。
  2. http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
  3. http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
  4. http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、 身份认证的网络协议,比http协议安全。
https的工作原理
  1. 客户使用https的URL访问Web服务器,要求与Web服务器建立SSL连接。
  2. Web服务器收到客户端请求后,会将网站的证书信息(证书中包含公钥)传送一份给客户端。
  3. 客户端的浏览器与Web服务器开始协商SSL连接的安全等级,也就是信息加密的等级。
  4. 客户端的浏览器根据双方同意的安全等级,建立会话密钥,然后利用网站的公钥将会话密钥加密,并传送给网站。
  5. Web服务器利用自己的私钥解密出会话密钥。
  6. Web服务器利用会话密钥加密与客户端之间的通信。

PS: 以上面试题纯属个人面试所遇问题总结,如有雷同,纯属巧合,持续更新中...