一、HTML和CSS
1怎么让一个不定宽高的div垂直水平居中
keyword: flex , transform
<body>
<div class="box"></div>
</body>
* {
padding: 0;
margin: 0
}
html, body {
height: 100%
}
body {
/* display: flex;
justify-content: center;
align-items: center; */
position: relative;
}
.box {
width: 200px;
height: 200px;
background: pink;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50% );
}
2 flex: 1
flex: 1 是flex-grow: 1; flex-shrink: 1; flex-basis: 0%; 的缩写;
(flex: 2 是flex-grow: 2; flex-shrink: 1; flex-basis: 0%; 的缩写;
- flex-grow 定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大
- flex-shrink 定义项目的缩小比例,默认为1,即如果空间不足,该项目将缩小
- flex-basis 给上面两个属性分配多余空间之前, 计算项目是否有多余空间, 默认值为 auto, 即项目本身的大小)
3 localStorage.sessionStorage和cookie的区别
共同点: 都是用来存储数据的;
不同点:
- cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递。而sessionStorage和localStorage不会自动把数据发送给服务器,仅在本地保存。
- 存储大小限制也不同,cookie数据不能超过4k,(因为每次http请求都会携带cookie,所以cookie只适合保存很小的数据,如会话标识)。而sessionStorage和localStorage的存储限制为5M。
- 数据有效期不同,sessionStorage仅在当前浏览器窗口关闭前有效;localStorage始终有效;cookie只在设置的过期时间之前有效,即使窗口或浏览器关闭。
- 作用域不同: sessionStorage不在不同的浏览器窗口共享,即使是同一个页面;localStorage和cookie在所有的同源窗口都是共享的。
二、JS
1 手写函数防抖、节流
// 防抖: 多次操作变为一次
// 节流: 一定时间内只调用一次
function debounce(fn, delay) { // 防抖
let timer = null
return function (...args) {
if (timer) {
clearTimeout(timer)
timer = null
}
timer = setTimeout(() => {
fn.apply(this, args)
clearTimeout(timer)
timer = null
}, delay)
}
}
function throttle(fn, delay) { // 节流
let timer = null
return function (...args) {
if (timer) return false
timer = setTimeout(() => {
fn.apply(this, args)
clearTimeout(timer)
timer = null
}, delay)
}
}
2 手写深拷贝
function deepCopy(source) {
if (!source || typeof source !== 'object') return source
const container = Array.isArray(source) ? [] : {}
for(let key in source) {
if (source.hasOwnProperty(key)) {
const value = source[key]
countainer[key] = value && typeof value === 'object' ? deepCopy(value) : value
}
}
return container
}
3 算法快排
const arr = [5, 8, 9, 12, 2, 4]
function mySort(data) {
if (data.length <= 1) return data
const baseVal = data[0]
const left = []
const right = []
for (let i = 1, len = data.length; i < len; i++) {
const item = data[i]
item < baseVal ? left.push(item) : right.push(item)
}
return [...mySort(left), baseVal, ...mySort(right)]
}
const res = mySort(arr)
console.log(res) // [2,4,5,8,9,12]
console.log(arr.sort()) // [12, 2, 4, 5, 8, 9] 默认排序是将元素转换为字符串,然后按照它们的 UTF-16 码元值升序排序。
console.log(arr.sort((a,b) => b - a)) // [12, 9, 8, 5, 4, 2]
console.log(arr.sort((a,b) => a - b)) // [2,4,5,8,9,12]
console.log(arr) // [2,4,5,8,9,12]
4 去重
const arr = [5, 5,5, 8, 9, 12, 2, 4, 2, 4]
console.log([...new Set(arr)]) // [5, 8, 9, 12, 2, 4]
function unique(data) {
return data.reduce((acc, cur) => acc.includes(cur) ? acc : [...acc, cur], [])
}
console.log(unique(arr)) // [5, 8, 9, 12, 2, 4]
console.log(arr) // [5, 5,5, 8, 9, 12, 2, 4, 2, 4]
5 一维转多维,多维转一维,A数据B数据互转
A 数据
const list = [
{id: 5, name: '独家', pid: 4},
{id: 1, name: '经典奶茶', pid: 0},
{id: 2, name: '原茶', pid: 1},
{id: 3, name: '鲜萃', pid: 2},
{id: 4, name: '奶茶', pid: 3},
]
B 数据
const newList = [
{
id: 1,
name: '经典奶茶',
pid: 0,
children: [
{
id: 2,
name: '原茶',
pid: 1,
children: [
{
id: 3,
name: '鲜萃',
pid: 2,
children: [
{
id: 4,
name: '奶茶',
pid: 3,
children: {
id: 5,
name: '独家',
pid: 4
}
}
]
}
]
}
]
}
]
// A转B :找父级,并把自己放到父级的children中
function toTree(data) {
const container = []
// step2 生成对象
const obj = {}
data.forEach(item => {
obj[item.id] = item
})
data.forEach(item => {
// step1 通过对象的方式找父级
const parent = obj[item.pid]
// step3 pid === 0 是,parent为undefined
if(parent) {
(parent.children || (parent.children = [])).push(item)
} else {
container.push(item)
}
})
return container
}
const newList = toTree(list)
console.log(newList)
// B 转 A
function toFlat(data) {
return data.reduce((acc, cur) => {
acc.push(cur)
if (cur.children) {
acc.push(...toFlat(cur.children))
}
return acc
}, [])
}
console.log(toFlat(newList))
6 数组扁平化
const oldArr = [
1,
1,
[
2, 2, [3],
[4, 5,5, 6],
[7, 8, 9],
10,
11
],
12,
13,
14,
[15, 16, 17],
];
// 方法一:
oldArr.flat(Infinity)
// 方法二:
function myFlat(data) {
return data.reduce((acc, cur) => {
return Array.isArray(cur) ? acc.concat(...myFlat(cur)) : acc.concat(cur)}, [])
}
console.log(myFlat(oldArr))
console.log(oldArr)
7 promise
参考文章 blog.csdn.net/qq_42033567…
const promise = new Promise((resolve, reject) => {
console.log(1);
console.log(2);
});
promise.then(() => {
console.log(3);
});
console.log(4);
// 1 2 4
// promise 内部状态没有发生变化,所以不能输出3
const promise1 = new Promise((resolve, reject) => {
console.log('promise1')
resolve('resolve1')
})
const promise2 = promise1.then(res => {
console.log(res)
})
console.log('1', promise1);
console.log('2', promise2);
// 结果:
// 'promise1'
// '1' Promise{<resolved>: 'resolve1'}
// '2' Promise{<pending>}
// 'resolve1'
const promise = new Promise((resolve, reject) => {
console.log(1);
setTimeout(() => {
console.log("timerStart");
resolve("success");
console.log("timerEnd");
}, 0);
console.log(2);
});
promise.then((res) => {
console.log(res);
});
console.log(4);
// 1 2 4 timerStart timerEnd sucess
Promise.resolve().then(() => {
console.log('promise1');
const timer2 = setTimeout(() => {
console.log('timer2')
}, 0)
});
const timer1 = setTimeout(() => {
console.log('timer1')
Promise.resolve().then(() => {
console.log('promise2')
})
}, 0)
console.log('start');
// start
// promise1
// timer1
// promise2
// timer2
const promise = new Promise((resolve, reject) => {
resolve('success1');
reject('error');
resolve('success2');
});
promise.then((res) => {
console.log('then:', res);
}).catch((err) => {
console.log('catch:', err);
})
// then: success1
8 写出执行顺序(字节面试真题)
async function async1() {
console.log('async1 start'); // 2
await async2();
console.log('async1 end'); //微任务01 6
await async3()
console.log('async3 end') // 微任务03 9
}
async function async2() {
console.log('async2'); // 3
}
async function async3() {
console.log('async3') // 7
}
console.log('script start'); // 1
setTimeout(function () {
console.log('setTimeout'); // 宏任务01 10
}, 0)
async1();
new Promise(function (resolve) {
console.log('promise1'); // 4
resolve();
}).then(function () { // 微任务02
console.log('promise2'); // 8
});
console.log('script end'); // 5
/**
* script start
* async1 start
* async2
* promise1
* script end
* async1 end
* async3
* promise2
* async3 end
* setTimeout
*/
9 执行结果
function test () {
console.log(1);
Promise.resolve().then(test);
}
test();
setTimeout(() => {console.log(2)}, 0)
// 始终输出1 不会执行setTimeout外面的回调函数,浏览器会崩溃
10 排列组合算法
let spec = [
["红", "绿", "蓝"],
["大", "中", "小"],
['酸', '甜', '苦', '辣', '咸']
]
function statistics(data) {
/**
* 思路:
* 先实现[['红'], ['绿'], ['蓝']]
* 再实现[['红', '大'], ['红', '中']]
* 最后实现[['红', '大', '酸']]
*/
return data.reduce((acc, cur) => { // 01 [[]] ["红", "绿", "蓝"] 02 [['红'], ['绿'], ['蓝']] ["大", "中", "小"],
const container = []
acc.forEach(a => { // []
cur.forEach(c => { // '红'
container.push(a.concat(c)) // ['红']
})
});
return container
}, [[]])
}
console.log(statistics(spec))
11 'get-element-by-id' 变成 'getElementById'
const str = 'get-element-by-id'
function change(msg) {
const arr = msg.split('-')
const newArr = arr.map((item, index) => {
if(index === 0) return item
return item.charAt(0).toUpperCase() + item.slice(1)
})
return newArr.join('')
}
console.log(change(str)) // getElementById
const str = 'get-element-by-id'
function change(msg) {
return msg.replace(/\-(\w)/g, (all, letter) => letter.toUpperCase())
}
console.log(change(str)) //getElementById
const str = 'getElementById'
function change(msg) {
return msg.replace(/([A-Z])/g, '-$1').toLowerCase()
}
console.log(change(str)) // get-element-by-id
12判断一个字符串中出现次数最多的字符,统计这个次数
const str = 'fkdjfklajlkfjklsjfklsdjfklsjfiufhfjfghkjfbvmfbvjfjhjf'
function count(msg) {
const obj = {}
for(let i = 0, len = str.length; i < len; i++) {
const letter = str[i]
obj[letter] ? obj[letter]++ : obj[letter] = 1
}
const maxVal = Math.max(...Object.values(obj))
const arr = []
for (let key in obj) {
if (obj[key] === maxVal) {
arr.push(key)
}
}
return `出现次数对多的字符是${
arr.join('&')
},值是${maxVal}`
}
console.log(count(str))
13 力扣算法,合并区间
以数组intervals表示若干区间的集合,其中单个区间为 intervals[i] = [start, end]。 请合并所有重叠的区间,并返回一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间。
let arr = [[1,3],[2,6],[8,10],[15,18]]
function merge(intervals) {
if (!intervals || !intervals.length) return [];
intervals.sort((a, b) => { // 按照区间第一位进行排序
return a[0] - b[0]
});
let result = [intervals[0]] // 排序之后第一个是最小的 [[1,3]]
console.log(result)
for (let i = 1; i < intervals.length; i++) { // 从第二个开始比较
let resultLast = result.length - 1 // 0
console.log(resultLast)
if (result[resultLast][1] > intervals[i][0]) { // 3 > 2 判断结尾是不是大于开始
result[resultLast][1] = Math.max(result[resultLast][1], intervals[i][1]) // 区间重复就进行合并了
} else {
result.push(intervals[i]) // 区间没有重复
}
}
return result
}
console.log(merge(arr)) // [[1,6], [8,10], [15,18]]
三、vue
1 路由守卫
- 全局前置路由守卫:router.beforeEach,切换之前调用(比如,进入新页面前,判断是是否有权限进入),to、from、next
- 全局后置路由守卫:router.afterEach,切换之后调用(比如到新页面后,更换页面title),to、from
- 独享路由守卫:beforeEnter,某一个路由单独享用的
- 组件内路由守卫:在组件内编写,beforeRouteEnter(进入前), beforeRouteLeave(离开前)