Webpack
- 常用的loader和plugin
loader:style-loader,css-loader,less-loader,babel-loader,ts-loader
plugin:html-webpack-plugin,clean-webpack-plugin
- abc.com与abc.com/app两者打包有什么不同
Vue篇
- keep-alive实现原理
- vue的插槽
vue大体分为三种插槽,匿名插槽、具名插槽、作用域插槽
匿名插槽:父组件想要向子组件传入一个模板进行渲染,可以使用slot
具名插槽:当想要传入多个时,就需要设置name
React篇:
- react的effect第一个参数为什么不可以是异步函数
- 受控组件与非受控组件
受控组件:不一定是表单元素,可以是任何组件,展示的value与React的状态绑定,页面数据变化时需要对应的change方法修改React的状态
非受控组件:像原声form表单元素一样,value保存在DOM内部,不与React的状态绑定
- react的性能优化
1.React.Memo缓存组件,当父组件重新render时,无论子组件是否发生变化,都会重新render一次,通过React.Memo缓存子组件,在父组件重新render时,对子组件的prop进行浅比较,如果没有变化,则直接使用缓存
- react和vue的区别
- 浏览器为什么不能解析jsx
- useState为什么返回的是一个数组?可以是对象吗?
为了解构方便,如果是对象的话解构需要写别名
- useEffect对应哪些钩子
- 父组件调用子组件的方法
ES6篇:
- 箭头函数为什么不可以作为构造函数:
new的简单实现:
function myNew(fn, ...args) {
const obj = {};
obj.__proto__ = fn.prototype;
// ❌箭头函数没有prototype属性
const res = fn.apply(obj, args)
// ❌箭头函数没有自己的this,无法使用call、apply等方法改变this指向
return typeof res === 'object' ? res : obj
}
因为箭头函数没有自己的this指向,也没有prototype和arguments属性,所以不能作为构造函数
- 解构函数是深拷贝还是浅拷贝
浅拷贝,const a = {...b}解构出来的如果有引用对象的话还是联动的,复制还是地址
Object.assign函数复制的也一样
- 手动实现深拷贝的递归时需要注意什么
const deepClone = (obj) => {
if (typeof obj !== 'object' || obj === null) {
return { ...obj }
}
const newObj = obj instanceof Array ? [] : {}
for(const i in obj) {
if(typeof obj[i] !== 'object' || obj[i] === null) {
newObj[i] = obj[i]
} else {
newObj[i] = deepClone(obj[i])
}
}
return newObj
}
- class的继承
// 父类
function Person(name){
this.name = name
this.eat=['banana']
this.say = function(word){
console.log(this.name + word)
}
sayHello = function() {
console.log(this.name + ' Hello')
}
}
Person.prototype.getName = function() {
console.log(this.name)
}
// 原形链继承
/* 存在的问题,
* 1、子类的原型是父类的实例,当父类实例中有引用类型的对象时,子类实例会会共享这个引用对象,在其中一个子类中修改该对象,其他子类会被污染
* 2、实例化子类时无法向父类的构造函数传参数
*/
function Son(){}
Son.prototype = new Person();
const s1 = new Son()
const s2 = new Son()
s1.eat.push('apple')
console.log(s1 instanceof Son) // true
console.log(s1 instanceof Person) // true
console.log(s1.eat) // ['banana', 'apple']
console.log(s2.eat) // ['banana', 'apple']
// 构造函数继承
/** 在子类的构造函数中调用父类的构造函数,并通过call或apply指向子类,解决了原型链继承存在的污染问题
* 存在的问题:
* 1、子类无法访问到父类原型上的属性和方法
*/
function Son1() {
Person.call(this)
}
const s11 = new Son1()
const s12 = new Son1()
s11.eat.push('apple')
console.log(s11 instanceof Son1) // true
console.log(s11 instanceof Person) // false
console.log(s11.eat) // ['banana', 'apple']
console.log(s12.eat) // ['banana', ]
s11.getName() // Uncaught TypeError: s11.getName is not a function
// 组合继承
// 把原型链继承和构造函数继承组合起来,两者的缺点都解决了,但是父类会被调用两次,有性能问题,
function Son2(name) {
Person.call(this, name)
this.name = name
} // 构造函数继承
Son2.prototype = new Person() // 原型链继承
const s21 = new Son2('bob')
const s22 = new Son2('pop')
s21.eat.push('apple')
console.log(s21 instanceof Son2) // true
console.log(s21 instanceof Person) // false
console.log(s21.eat) // ['banana', 'apple']
console.log(s22.eat) // ['banana', ]
s21.getName() // bob
s22.getName() // pop
console.dir(s21)
// 寄生组合式继承
// 在组合继承的基础上,子类的prototype不再指向父类的实例,通过Object.create()方法拷贝一个父类prototype
function Son3(name) {
Person.call(this, name)
this.name = name
} // 构造函数继承
const extend = function(Parent, Child) {
Child.prototype = Object.create(Parent.prototype)
// 重写prototype属性会导致constructor丢失,手动加回去
Child.prototype.constructor = Child
}
extend(Person, Son3)
const s31 = new Son3('bob')
const s32 = new Son3('pop')
s31.eat.push('apple')
console.log(s31 instanceof Son3) // true
console.log(s31 instanceof Person) // false
console.log(s31.eat) // ['banana', 'apple']
console.log(s32.eat) // ['banana', ]
s31.getName() // bob
s32.getName() // pop
console.dir(s31)
- JSON.parse(JSON.stringfy())深拷贝的缺陷
/**
使用JSON.parse(JSON.stringfy())实现深拷贝时:
undefined、函数、Symbol类型的值会丢失
Date类型的值会转成字符串
NaN类型会转成null
*/
function Person (name) {
this.name = 20
}
const lili = new Person('lili')
let a = {
data0: '1',
date1: [new Date('2020-03-01'), new Date('2020-03-05')],
data2: new RegExp('\\w+'),
data3: new Error('1'),
data4: undefined,
data5: function () {
console.log(1)
},
data6: NaN,
data7: lili,
data8: Symbol()
}
let b = JSON.parse(JSON.stringify(a))
/**
data0: "1"
data2: {}
data3: {}
data6: null
data7: {name: 20}
date1: (2) ['2020-03-01T00:00:00.000Z', '2020-03-05T00:00:00.000Z']
[[Prototype]]: Object
- for in 和for of的区别(还有Object.keys())
相同点: for in和for of都可以用来遍历数组
不同点: for in遍历获得的是key,for of遍历获得的是value
for in可以遍历对象,for of不行
var myObject={
a:1,
b:2,
c:3
}
for(let i in myObject){ console.log(i) }
// a
// b
// c
for(let i of myObject){ console.log(i) }
// Uncaught TypeError: myObject is not iterable
for in还会遍历数组原型对象上的可枚举属性(Object.keys不会),例如:
Object.prototype.d = 4
for(let i in myObject) {
console.log(i)
}
// a
// b
// c
// d
Object.keys(myObject) // [a,b,c]
除此之外,for in 的遍历顺序不是严格按照声明顺序来的,Object.keys()也有这个问题
CSS篇
- 清除浮动
- 两列布局实现
TypeScript
- 常用的工具函数
typeof:类型捕获
keyof: 键值捕获
const obj = {msg:'123'}
const func = (): typeof obj => {
return obj
}
Partial<T>: 可以只返回T中的某一个属性(场景:传入某一个筛选条件)
Require<T>: 必须返回T中所有的属性
Pick<T, K>: 从T类型中选择K属性
Omit<T, K>: 从类型T中,剔除所有符合K条件的类型
Record<K, T>: 声明一个对象类型,其key类型为K,value类型为T
- 类型保护
- unknown和any的区别