CSS
垂直居中
flex、grid以及绝对定位三种方法
<!-- flexbox -->
<div class="father flexbox">
<div class="son"></div>
</div>
<!-- grid -->
<div class="father gridbox">
<div class="son"></div>
</div>
<!-- 子绝父相 -->
<div class="father relative">
<div class="son absolute" ></div>
</div>
// css
.father {
width: 200px;
height: 200px;
background-color: pink;
}
.son {
width: 50px;
height: 50px;
background-color: red;
}
.flexbox{
display: flex;
justify-content: center;
align-items: center;
}
.gridbox {
display: grid;
place-items: center;
}
.relative{
position: relative;
}
.absolute{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
}
实现一个三角形
将一个div宽度和高度都为0,通过设置 border 属性,实现一个任意朝向的等边三角形
<div class="triangle"></div>
.triangle{
width: 0;
height: 0;
border-left: 50px solid transparent;
border-right: 50px solid transparent;
border-bottom: 100px solid red;
}
JS手撕题
防抖
触发事件后延时执行,延时期间重复触发,则重新计时
function debounce(fn, delay = 500){
let timer = null
return function(...args){
if(timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.call(this, ...args)
},delay)
}
}
const debouncedfunc = debounce(func, 500)
debouncedfunc(...args)
适用于输入框输入、搜索联想等场景,只有在连续触发事件停止一段时间后才会执行,避免频繁触发请求。
节流
设定时间内重复触发事件,只执行一次
function thettle(fn, delay=500){
let timer = null
return function(...args){
if(timer) return
timer = setTimeout(() => {
timer = null
fn.call(this, ...args)
}, delay)
}
}
const thettledfunc = thettle(func, 500)
thettledfunc(...args)
适用于滚动事件、窗口大小调整等场景,在固定的时间间隔内,只会执行一次操作,限制操作的执行频率。
深拷贝
1.循环引用检查: 使用 WeakMap 缓存已经拷贝过的对象,通过检查缓存来避免循环引用导致的无限递归。
2.特殊值和非对象类型处理: 如果传入的对象是 null 或者不是对象类型,直接返回原始值,不进行递归拷贝。
3.日期对象和正则表达式对象处理: 对于日期对象和正则表达式对象,分别创建新的对象,避免引用相同的对象。
4.数组处理: 对于数组,创建一个新的数组 arrCopy,并缓存当前数组的引用,然后递归拷贝数组的每个元素,将拷贝后的元素放入新的数组中。
5.普通对象处理: 对于普通对象,创建一个新的对象 objCopy,并缓存当前对象的引用,然后递归拷贝对象的每个属性,将拷贝后的属性放入新的对象中。
function deepClone(obj, cache = new WeakMap()){
// 循环引用检查
if(cache.has(obj)){
return cache.get(obj)
}
// 特殊值和非对象类型处理
if(obj === null || typeof obj !== 'object'){
return obj
}
// 日期对象和正则表达式对象处理
if(obj instanceof Date){
return new Date(obj)
}
if(obj instanceof RegExp){
return new RegExp(obj)
}
// 数组处理
if(Array.isArray(obj)){
const newArr = []
cache.set(obj, newArr) // 缓存数组引用,避免循环引用
obj.forEach((item, index) => {
newArr[index] = deepClone(item, cache)
})
return newArr
}
// 普通对象
const newObj = {}
cache.set(obj, newObj) // 缓存对象引用,避免循环引用
Object.keys(obj).forEach(key => {
if(obj.hasOwnProperty(key)){
newObj[key] = deepClone(obj[key], cache)
}
})
return newObj
}
Promise.all
Promise.all 的特点是当传入的所有 Promise 都成功完成时,返回的 Promise 才会被resolve,值是一个包含所有传入 Promise resolve 值的数组。如果其中任何一个 Promise 被reject,返回的 Promise 就会被reject,并传递第一个被reject的 Promise 的原因。
function myPromiseAll(promises){
return new Promise((resolve, reject) => {
if(!Array.isArray(promises)){
return reject(new TypeError('promises must be an array'))
}
const results = []
if(promises.length === 0){
return resolve(results)
}
let donePromise = 0
for(let i = 0; i < promises.length; i++){
promises[i].then(result => {
results[i] = result
donePromise++
if(donePromise === promises.length){
return resolve(results)
}
}).catch(error => {
return rejcet(error)
})
}
})
}
Promise.race
在传入的多个 Promise 中有一个率先改变状态(resolve或reject)时就改变状态
function myPromiseRace(promises){
return new Promise((resolve, reject) => {
if(!Array.isArray(promises)){
return reject(new TypeError('promises muse be an array!'))
}
for(let i = 0; i < promises.length; i++){
Promise.resolve(promises[i])
.then(resolve)
.catch(reject)
}
})
}
instanceof 实现
实现:A instanceof B,结果返回一个布尔值
原理:通过判断 A 对象的原型链中能不能找到 B 对象的 prototype
function myInstanceof(A, B) {
A = A.__proto__;
B = B.prototype;
while (true) {
if (A === B) return true;
else if (A === null) return false;
A = A.__proto__;
}
}
console.log(myInstanceof([], Array)); // true
console.log(myInstanceof([], Function)); // false
注:
- 基本数据类型不能通过
instanceof来判断 - 所有引用类型数据用
instanceof检测Object都会返回true
retry函数
题目: 实现一个retry函数,失败了重试,直至最大失败次数或者执行成功
思路: 通过递归实现
1.利用Promise实现一个暂停函数
2.catch方法捕获错误
3.延时后递归调用retry或者返回Promise.reject
const pause = (delay) => new Promise((resolve) => setTimeout(resolve,delay))
const retry = function(fn, retries,delay = 500){
fn.catch((err) => retries > 0
? pause(delay).then(() => retry(fn,--retries,delay)
: Promise.reject(err)
)
}
数组扁平化
数组扁平化是将多层嵌套的数组转换为一个层级的数组的过程
function myFlat(flat){
return flat.reduce((pre, cur) => {
return pre.concat(Array.isArray(cur) ? myFlat(cur) : cur)
}, [])
}
const nestedArray = [1, [2, [3, 4], 5], 6];
const myFlatResult = myFlat(nestedArray);
console.log(myFlatResult); // [ 1, 2, 3, 4, 5, 6 ]
实现reduce
Array.prototype.selfReduce = function (callback, initValue) {
const originArray = this;
if(!originArray.length) {
throw new Error('selfReduce of empty array with no initial value');
}
// 累计器
let accumulator = initValue === undefined ? originArray[0] : initValue
// 循环执行 callback
for (let i = 0; i < originArray.length; i++) {
// 如果没有初始值且是最后一次循环,不再执行callback
if (initValue === undefined && (i + 1) === originArray.length) break;
accumulator = callback(
accumulator,
initValue === undefined ? originArray[i + 1] : originArray[i],
i,
originArray
);
}
return accumulator
}
const res = [1, 2, 3, 4, 5].selfReduce((pre, cur) => pre + cur)
console.log(res) // 15