1.React如何进行组件通信?
父传子:父组件中定义一个自定义属性,自定义属性的值就是要传递的数据
子传父:在父组件中定义一个回调函数,通过父传子的方式将这个函数传递给子组件,子组件进行调用,函数的参数就是要传递的数据
兄弟组件之间的通信包括状态提升和发布订阅模式
状态提升就是子传父然后父传子
发布订阅模式就是订阅者提供一个回调函数,保存在数组中,发布者去调用这个回调函数
Context跨组件通信,创建一个contenxt对象,从中导出provider和consumer组件,provider组件包裹跟组件,value就是要传递的数据,子组件如果是类组件那么就创建一个静态方法contextType,然后通过this.Context获取到要传递的数据,如果是函数组件,那么就需要用consumer包裹组件,返回一个jsx,函数的第一个参数就是要传递的数据
还有状态管理工具redux,react-redux,@reduxjs/toolkit
2.闭包的理解以及应用场景
闭包通俗来讲就是一个函数嵌套一个函数,内部函数可以访问外部函数的变量,形成一个封闭的作用域。
闭包的优点:
1.数据封装:闭包可以将变量封装在函数内部,避免全局变量的污染,提高代码的可维护性和可复用性。
2.保持状态:闭包可以保持函数的状态,及时函数已经执行完毕,闭包中的变量仍然可以被访问和使用。
3.实现私有变量和方法:通过闭包,可以创建私有变量和方法,只能在函数内部访问,外部无法直接访问和修改。
闭包的缺点:
1.内存消耗:闭包会引用外部函数的变量,导致这些变量无法被垃圾回收,可能会占用更多的内存。
2.性能问题:由于闭包会涉及作用域链的查找,会增加函数的执行时间和内存消耗。
3.潜在的内存泄漏,如果闭包中引用了外部函数的变量,导致这些变量不再使用,但是闭包仍然存在,可能会导致内存泄漏。
应用场景:
1.封装私有变量和方法
2.延长变量的生命周期
3.原生js实现防抖节流
3.JS数组之间进行合并,写出三种合并方式
1.使用数组的concat方法
let arr1=[1,2,3]
let arr2=[4,5,6]
let merge=arr1.concat(arr2)
console.log(merge)
2.使用扩展运算符…
let arr1=[1,2,3]
let arr2=[4,5,6]
// let merge=arr1.concat(arr2)
let merge=[...arr1,...arr2]
console.log(merge)
3.使用第三方库lodash的 concat() 合并
4.使用for循环
let arr1=[1,2,3]
let arr2=[4,5,6]
// let merge=arr1.concat(arr2)
// let merge=[...arr1,...arr2]
for (let i in arr2){
arr1.push(arr2[i])
}
console.log(arr1)
4.TypeScript支持的访问修饰符有哪些?
1.public:所有定义成public的属性和方法都可以在任何地方进行访问。public是默认的修饰符
2.static:静态方法,只能在类内部访问
3.private:所有定义成private的属性和方法都只能在类定义内部进行访问。
4.protected:受保护的修饰符,只能在类内部以及继承的子类中访问,不能再实例化对象中访问
5.readonly关键字将属性设置为只读的,不能修改。
5.如何将 unknown 类型指定为一个更具体的类型?
进行类型断言,类型断言就是说告诉编译器,他就是这个类型,你不用去检查了。
类型断言的方法有两种
1.值 as 类型
2.<类型>值
1 const value: unknown = "Hello World";
2 const foo: string = value; // Error
3 const bar: string = value as string; // OK
只有对已经类型断言的数据才能实现给别的变量赋值。
6.解释一下TypeScript中的枚举?
枚举( mei ju ) : 枚举的意思就是一一列举, 把所有情况都列举出来, 那么取值的时候, 只有这几个可以使用, 其他的都不行。
TypeScript枚举使用关键字“enum”来定义一个新的枚举类型。例如:
enum Direction {
Up,
Down,
Left,
Right
}
自定义枚举值
您可以通过自定义枚举值来覆盖默认的自动递增行为。例如:
enum Direction {
Up = 1,
Down,
Left,
Right
}
要访问枚举值,只需使用点表示法即可。例如:
console.log(Direction.Up); // 输出1
console.log(Direction.Down); // 输出2
7.TypeScript中的方法重写是什么?
为了提高效率效率,我们通常会用到重载和重写两种那个方式。
一、重载
重载:方法名称相同,参数的类型或者个数不同。
重载是面向对象编程的一种特有的方法,它允许一个函数在实现的过程中有多个入口,而且只需要实现一次
二、重写
重写:方法名称,参数名称,返回值类型全部相同
特点:当父类和其派生类拥有同一个方法时,这种情况就是方法的重写
8.Js中深拷贝和浅拷贝的定义以及具体实现都有哪些方法?
理解概念
如何区分深拷贝与浅拷贝,简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,拿人手短,如果B没变,那就是深拷贝,自食其力。
1.如果是基本数据类型,名字和值都会储存在栈内存中。
当然,这也算不上深拷贝,因为深拷贝本身只针对较为复杂的object类型数据
2.如果是引用数据类型,名字存在栈内存中,值存在堆内存中,但是栈内存会提供一个引用的地址指向堆内存中的值。
实现的方法
(1)采用递归去拷贝所有层级属性
function deepClone(obj){
let objClone = Array.isArray(obj)?[]:{};
if(obj && typeof obj==="object"){
for(key in obj){
if(obj.hasOwnProperty(key)){
//判断ojb子元素是否为对象,如果是,递归复制
if(obj[key]&&typeof obj[key] ==="object"){
objClone[key] = deepClone(obj[key]);
}else{
//如果不是,简单复制
objClone[key] = obj[key];
}
}
}
}
return objClone;
}
let a=[1,2,3,4],
b=deepClone(a);
a[0]=2;
console.log(a,b);
(2) 通过JSON对象来实现深拷贝
缺点: 无法实现对对象中方法的深拷贝,会显示为undefined
function deepClone2(obj) {
var _obj = JSON.stringify(obj),
objClone = JSON.parse(_obj);
return objClone;
}
(3)lodash函数库实现深拷贝
let result = _.cloneDeep(test)
9.Umi中如何实现路由权限,实现按钮权限?
export default {
routes: [
{ path: '/user', component: 'user',
wrappers: [
'@/wrappers/auth',
],
},
{ path: '/login', component: 'login' },
]
}
import { Redirect } from 'umi'
export default (props) => {
const { isLogin } = useAuth();
if (isLogin) {
return <div>{ props.children }</div>;
} else {
return <Redirect to="/login" />;
}
}
10.Umi路由跳转传参方式都有哪些?
import { history } from 'umi';
// 跳转到指定路由
history.push('/list');
// 带参数跳转到指定路由
history.push('/list?a=b');
history.push({
pathname: '/list',
query: {
a: 'b',
},
});
// 跳转到上一个路由
history.goBack();