CSS: padding 与 margin 的区别? ---pading 向内;作用对象是自己; ---maRgin 向外;作用的对象是其他;
水平垂直居中最快的方式; 父级:display:flex;子级:margin:auto;
vw和百分比的不同 VW 不依赖父级的限制,根据屏幕来; 百分比 依赖父级,根据父级进行百分比缩放;
rem 和 em rem 根据html 的字体大小为基数;em是父级元素的字体大小为基数进行计算的;
position:relative,absolute
盒模型:标准盒模型/IE盒模型
JS: 原型链的最顶层是null; 当我们访问一个对象的属性和方法时,js首先会在对象自身查找,如果找不到会沿着原型链继续向上查找,直到找到对应的属性和方法,或者达到原型链的末尾(null); ---prototype属性:每个函数对象都有一个prototype属性,它指向一个对象,这个对象被认为是该函数的原型, ---原型继承:通过原型链,对象可以基础原型对象的属性和方法
闭包:一个函数内部定义了另一个函数,当内部函数引用了外部函数的变量时,就创建了一个闭包,内部函数可以访问外部函数的变量,即使外部函数已经执行完毕; function outer(){ var outmsg = "here is some message" function inner(){ console.info(outmsg) } return inner } var closure = outer(); closure(); ---封装私有变量:创建私有变量,只能通过暴露的函数进行访问和修改; ---给予或者缓存:可以将计算结果缓存起来,避免重复计算,提供性能; ---模块化开发;创建模块化的代码,避免全局命名冲突;
闭包中的变量无法被垃圾回收,会造成内存泄漏。 如何解决闭包造成的内存泄漏: ----避免循环使用,确保闭包中不引用不需要的外部外部变量,or不需要闭包时手动解除引用; ---显式解除引用,将闭包赋值为null或者将包含闭包的变量赋值为underfined; ---使用事件函数处理时,要注意解除事件监听(removeEventListener); ---避免闭包的滥用,将闭包限制在范围内使用, ---使用模块化开发的方法;使用模块化开发的方法可以帮助限制闭包的作用域,并在模块不需要的时候进行解除引用,如使用ES6的模块化语法(import/export)可以确保模块在不需要时被垃圾回收;
for of 和 for in 的区别; for of 一般循环数组用, for in 一般循环对象用,耗能比较大
深拷贝和浅拷贝 解构赋值: 一维的情况时--可以说是深拷贝,多维的情况--只能是浅拷贝; 浅拷贝:只是复制对象的引用,而不是复制实际的对象,修改原始对象的属性也会影响到浅拷贝的对象。
-
使用 Object.assign() const obj1 = { name: 'John', age: 25 }; const obj2 = Object.assign({}, obj1); obj1.name = 'Jane'; console.log(obj1); // { name: 'Jane', age: 25 } console.log(obj2); // { name: 'John', age: 25 }
-
使用展开运算符(...) const obj1 = { name: 'John', age: 25 }; const obj2 = { ...obj1 }; obj1.name = 'Jane'; console.log(obj1); // { name: 'Jane', age: 25 } console.log(obj2); // { name: 'John', age: 25 }
深拷贝:会递归的复制对象以及嵌套的对象和属性,创建一个完全独立的副本,修改原始对象不会影响拷贝的对象;
- 使用 JSON.parse() 和 JSON.stringify()---(它无法复制函数、正则表达式、循环引用等特殊类型的对象);
const obj1 = { name: 'John', age: 25 };
const obj2 = JSON.parse(JSON.stringify(obj1));
obj1.name = 'Jane';
console.log(obj1); // { name: 'Jane', age: 25 } console.log(obj2); // { name: 'John', age: 25 } 2.可以使用一些第三方库,如 lodash 的 cloneDeep() 方法来实现深拷贝: 3.写一个深拷贝的函数; const deepClone = (source)=>{ const targetObj = source.constructor===Array?[]:{}; for(let keys in source){ if(source.hasOwnProperty('keys')){ if(source[keys] && source[keys].constructor==='object'){ targetObj[keys] = deepClone(source[keys]) }else{ targetObj[keys] = source[keys] } } } return targetObj }
new 一个新对象时发生了什么? ---创建一个空对象; ---将该对象的原型链通过prototype 指向构造函数的原型对象; ---将构造函数的作用域(this)绑定到新的对象上; ---执行构造函数,传递给他指定的参数和必要的参数; ---如果构造函数返回一个对象,则返回该对象,否则返回一个新的对象。
js 判断数据类型的方式: ---typeof 对于基本类型的数据 返回类型字符串;对于引用类型的数据(数组,对象)则返回Object; typeof [] // object; typeof {} // object; typeof ()=>{} // function;
---instanceof 检查一个对象是否为某个构造函数的实例;可以检查对象是否属于特定的引用类型; {} instanceof Object // true; [] instanceof Array // true; ()=>{} instanceof Function // true; [] instanceof Object // true; ()=>{} instanceof Object // true;
---Object.prototype.toString.call() 返回一个对象内部属性[[Class]]的字符串表示对象的类型,区分不同的引用类型非常有用; Object.prototype.toString.call({}) // ['object','Object'] Object.prototype.toString.call([]) // ['object','Array'] Object.prototype.toString.call(()=>{}) // ['object','Function']
Object.entries(obj) 能够将 obj 转化成 每一项都包含key和value的一个数组,然后用map()方法 {Object.entries(item).map(([key, value]) => ( {key}: {value} ))}
react 中的 useState() 和 useCallback(); useState() 用于声明和状态管理; useCallback() 用于缓存函数的引用,以提高性能;
useEffect() 集合了componentDidMount、componentDidUpdate 和 componentWillUnmount 三个生命周期为一个api; 可以获取数据;事件的监听和获取;改变dom;输出日志;
useEffect(()=>{},[]) param1(回调函数)--符合条件时会触发当前的回调函数; param2(数组)--如果为state,则当state改变时会触发回调函数; --如果为[],则只有当初始化阶段会触发回调函数; --如果不传,初始化和更新都会触发回调函数; 回调函数中会返回一个函数:在组件卸载的时候执行清除操作;
useContext() 组件之间需要共享状态; // async/await 的用法案例; async fetchData = ()=>{ try{ const response = await fetch('URL'); const data = await response.json(); }catch(error){ console.info(error) } }
//获取一个多层级对象的 所有的key值;
const getObjKeyList = (params: any)=>{
const objStr = typeof params === 'string'? JSON.parse(params):params;
let keysList: any[] = []
for(let keys in objStr){
if(objStr.hasOwnProperty(keys)){ //如果是对象 就继续循环
if(Object.prototype.toString.call(objStr[keys]) === '[object Object]'){
keysList = keysList.concat(getObjKeyList(objStr[keys]))
}
keysList.push(keys)
}
}
return keysList;
}
//ES6 中简单的数组去重
const list = ["name","age","name","grade","haha"]
const filterList = list.filter((value,index,self)=>{
return self.indexOf(value)===index
})
const filterLists = list.reduce((accumulator: any,currentValue)=>{
if(!accumulator.includes(currentValue)){
accumulator.push(currentValue)
}
return accumulator
},[])
const filtersList = [...new Set(list)]
//对象数组去重 const objList = [ {id:1,name:"aa"}, {id:3,name:"bb"}, {id:2,name:"cc"}, {id:1,name:"aa"}, ]; const filterObjList = objList.filter((obj,index,self)=>{ index === self.findIndex((x)=>x.id===obj.id && x.name===obj.name) }) // 用findIndex 方法在查找当前对象中在数组中第一个索引值,如果当前对象与查找的对象的index 相同则留下,不同则删掉;
const filtersObjList = Object.values(objList.reduce((acc,obj)=>{ const key = obj.id +'|'+ obj.name; if(!acc[key])){ acc[key] = obj; } // acc={1:{...},2:{...}} return acc },{})) // 用reduce来迭代数组,使用对象中的id作为唯一的键值,使用一个空对象作为累加器; 只有当前累加器中没有当前键才加入,用Object.values来 获取acc中的value值的数组。
同步和异步的问题; 同步:代码按照顺序执行, 异步:代码不按照顺序执行,回调函数或者定时器在特定的时间之后执行; 其顺序: 先同步 后异步; Promise 中的 resolve 的执行,不会中断后面底代码的执行,如果没有执行resolve he reject 状态,都是 pending的状态,不会有结果返回; 微任务:优先级较高---Promise,ObjectObserver,MutationObserver,process.nextTick,async/await. 宏任务:优先级较低---setTimeout,setInterval 和XHR