总结一下面试的时候遇到的代码题吧,仅供参考,欢迎讨论指正
1、深浅克隆,以及自定义方法实现深克隆
// 浅克隆
Object.assign()
// 深克隆
JSON.parse(JSON.stringify(obj));
// 自定义深克隆
function deepCopy(obj){
// 接受一个参数 obj
// 判断传入的 obj 是否为对象类型
if (typeof obj == 'object') {
// 根据 obj 的类型构造 result 变量,如果是数组则创建空数组,否则创建空对象
var result = obj.constructor == Array ? [] : {};
// 遍历 obj 的属性
for(let i in obj) {
// 如果 obj 属性的值还是一个对象,递归调用函数进行深拷贝;否则直接将简单值赋值给 result 对象的同名属性
result[i] = typeof obj[i] == 'object' ? deepCopy(obj[i]) : obj[i];
}
} else {
// 如果 obj 是简单类型,则将它直接赋值给 result
var result = obj;
}
// 返回赋值后的 result 对象
return result;
}
2、求两个一维数组的交集
function intersection(arr1, arr2) {
// 使用 filter() 方法筛选出在两个数组都存在的元素。
const result = [...arr1].filter(item => arr2.includes(item));
return result;
}
// 示例:
const array1 = [1, 2, 3, 4, 5];
const array2 = [4, 5, 6, 7, 8];
console.log(intersection(array1, array2)); // [4, 5]
// 此方法有缺陷,无法检测重复存在的元素
// 根据百度大佬的提示 重写一个方法
function arrayIntersection(arr1, arr2) {
// 使用 Map 存储 arr1 中出现的元素及其出现次数
const map1 = new Map();
arr1.forEach((item) => {
map1.set(item, (map1.get(item) || 0) + 1);
});
// 遍历 arr2,并与 map1 中的元素进行匹配
const result = [];
arr2.forEach((item) => {
if (map1.get(item)) {
result.push(item);
map1.set(item, map1.get(item) - 1);
}
});
return result;
}
// 示例用法:
const arr1 = ["a", "b", "c", "d", "d", "d"];
const arr2 = ["b","b", "d", "d", "e"];
const intersection = arrayIntersection(arr1, arr2); // ['b', 'd', 'd']
3、数据转换成树状结构
function flattenToTree(data) {
// 遍历数据数组,生成 ID 到元素映射对象
const idMap = data.reduce((acc, el) => {
acc[el.id] = el;
return acc;
}, {});
const roots = [];
data.forEach((item) => {
if (item.parentId === null) {
// 如果没有父级ID,它就是一个顶级节点
roots.push(item);
return;
}
// 其他情况则将该节点挂载到其父亲下面
const parent = idMap[item.parentId];
if (!parent.children) {
// 检查它是否存在子节点,没有则新建一个空白数组
parent.children = [];
}
parent.children.push(item);
});
return roots;
}
4、匹配出 https://www.js.cn/list/show.aspx?version=7&openType=redesign&curid=217541718&nqt=###中的openType
const url = "https://www.js.cn/list/show.aspx?version=7&openType=redesign&curid=217541718&nqt=###";
// 获取问号后面的所有参数
//version=7&openType=redesign&curid=217541718&nqt=###
const searchParamStr = url.slice(url.indexOf('?') + 1);
// 将参数字符串按照 & 分割成数组
// ['version=7', 'openType=redesign', 'curid=217541718', 'nqt=###']
const searchParamsArr = searchParamStr.split('&');
// 遍历数组,将每个参数拆开并存入对象中
const params = {};
for (let i = 0; i < searchParamsArr.length; i++) {
const [key, value] = searchParamsArr[i].split('=');
params[key] = value;
}
console.log(params);
console.log(params.openType);
// 输出 { version: '7', openType: 'redesign', curid: '217541718', nqt: '###' }
5、写一个双色球的算法函数,要求从1~36选出6个不重复的红球,从1~16里选出1个篮球,如返回[[1,3,4,9,21,27],21]
这题当时直接蒙了,啥是双色球,什么红球篮球。。。等我冷静下来有点超时了,硬着头皮写出的第二种方法,总结的时候想出的第一种方法~
// 方法一:
function pickLotteryNumbers() {
const redBallsArray = new Array(36).fill(0).map((_, i) => i + 1); // 构造 1~36 的红球数组
const blueBallsArray = new Array(16).fill(0).map((_, i) => i + 1); // 构造 1~16 的蓝球数组
const lotteryNumbers = []; // 存放彩票号码的数组
for (let i = 0; i < 6; i++) {
const index = Math.floor(Math.random() * redBallsArray.length); // 随机选择一个位置
const ball = redBallsArray.splice(index, 1)[0]; // 取出该位置上的球,并从数组中删除
lotteryNumbers.push(ball); // 将选出的红球存入结果数组
}
const blueIndex = Math.floor(Math.random() * blueBallsArray.length);
const blueBall = blueBallsArray[blueIndex]; // 随机选择一个篮球,并记录下来
lotteryNumbers.sort((a, b) => a - b); // 我不知道双色球是啥,不知道用不用排序
return [lotteryNumbers, blueBall]; // 返回结果数组
}
// 方法二:
function getBall(){
function selectNum(n, min, max){
const num = new Set()
while (num.size < n) {
const number = Math.floor(Math.random()*(max-min+1)+min)
num.add(number)
}
return Array.from(num)
}
const redBall = selectNum(6,1,36)
const blueBall = selectNum(1,1,16)[0]
return [redBall, blueBall]
}
/*
*首先创建了一个空白的 Set,然后进入一个 while 循环。
*循环体会反复执行,直到 Set 的大小达到预设的随机选数目 n。
*每轮循环中我们用 Math.random() 生成介于指定区间 [min, max] 范围内的随机整数
*数字去重使用 Set 来处理,确保了结果中不会有重复的数字。
*/
6、this指向问题
// 面试题 第一题
const a = {
b:()=>{
console.log(this)
}
}
a.b()
const c = a.b
c()
// 第二题
const a2 = {
b:function(){
console.log(this)
},
function(){
console.log(this)
}
}
a2.b()
const c2 = a.b
c2()
7、写一个按钮基于antd,写个通用组件,按一下3秒内disable
const newBtn = ({ children, onClick, ...restProps }) => {
const [disabled, setDisabled] = useState(false);
const handleClick = e => {
if (disabled) return;
setDisabled(true);
onClick(e);
setTimeout(() => {
setDisabled(false);
}, 3000);
};
// 面试官提到了useCallback,优化一下,脑子空白,结束了才反应过来
// onClick 和 disabled 发生变化时, handleClick 函数会重新生成
// 在父级组件更新而导致该组件重新渲染时,可以直接复用之前所生成的同一个事件处理函数
const handleClick = useCallback(e => {
if (disabled) return;
setDisabled(true);
onClick(e);
setTimeout(() => {
setDisabled(false);
}, 3000);
}, [onClick, disabled]);
return (
<Button {...restProps} disabled={disabled} onClick={()=>handleClick(e)}>
{children}
</Button>
);
};
8、用Promise封装一个settimeout
// 实现以下功能
// cosnt obj = delay(2000, 1) 两秒后输出1
// obj.then(console.log)
// obj.cancel() 这一步是终止输出(问终止后promise状态:pending[待定]初始状态)
// 考点:resolve() 后修改promise的状态为fullfiled
function delay(time, data) {
let timeout;
const promise = new Promise((resolve)=>{
timeout = setTimeout(()=>{
resolve(data)
},time)
})
promise.cancel = function () {
clearTimeout(timeout);
};
return promise;
}
9、写个倒计时页面
const App = () => {
const [time, setTime] = useState(60);
useEffect(() => {
const timer = setInterval(() => {
// 检查是否已到 0,若到 0 则立即清除定时器,避免多触发更新
if (time - 1 <= 0) {
clearInterval(timer);
} else {
setTime(time - 1);
}
}, 1000);
// 清理函数:在下一次副作用或组件卸载前,清除定时器
return () => clearInterval(timer);
}, [time]);
return (
<div>
{time}
</div>
);
};
10、多维数组对象,将 "name" 属性更改为 "title"
const data = [
{
name: 'a',
children: [
{
name: 'b',
children: [
{
name: 'a',
children: []
},
{
name: 'a',
children: []
}
]
}
]
},
{
name: 'a',
children: [
{
name: 'b',
children: []
}
]
}
];
// 根据面试官的提示优化了一下方法
function updateList(data) {
return data.map(item => {
const { name, children } = item;
const newItem = { title: name };
if (children && children.length > 0) {
newItem.children = updateList(children);
} else {
newItem.children = [];
}
return newItem;
});
}
11、回文字符串
function isPalindrome(inputString) {
// 提取所有字母并全部转换成小写,转换成数组,过滤出数字字母
const strArray = inputString
.toLowerCase()
.split('')
.filter(char => char >= 'a' && char <= 'z');
// 将字符数组转为字符串以便于比较。
const str = charactersArray.join('');
// 倒序的字符数组
const reversedStrArray = strArray .reverse();
// 将倒序的字符数组转为字符串以便于比较。
const reversedStr = strArray .join('');
// 比较原字符串和倒序字符串是否相等。
return str === reversedStr;
}
console.log(isPalindrome("A man, a plan, a canal: Panama")); // 输出 true
12、原形原型链
Function.prototype.a() = alart(1)
Object.prototype.b() = alart(2)
function a(){}
let a = new a()
a.a()
a.b()