以下内容是我归列的前端面试经常会遇到的手写题,主要是考察js的熟练程度,其中好多我们都知道概念,但是动手去写,还是有点难度的。
我大概罗列了一些,比如: 数组去重,浅拷贝,深拷贝,节流,防抖,对象扁平化等等。
1.数组去重
对于数组去重,我们其实并不陌生,最传统的办法还是我们将数组每一项挨个比较,但是在es6中也提出了一个Set对象,该方法可以储存唯一的元素,更加减少了我们的代码量。
我们先来传统写法写一下
这里面使用了一个Map对象中的has方法,该方法是用于查询键是否存在,存在则返回true,我们利用该方法的机制,可以快速写出数组去重。

// 1.传统方法数组去重
// 接受一个数组作为参数
function deduplicationArray(arr) {
// 创建一个数组,最后去重完return出去
let red = [];
// 创建一个Map对象
let map = new Map();
// 遍历该数组
arr.forEach(ele => {
// 使用Map的has方法检测值是否存在
// 存在返回true
if(!map.has(ele)) {
// 没有的话将数字push到red中
// 将该值储存到map中
red.push(ele);
map.set(ele,1)
}
})
// 最终return 出去
return red;
}
console.log(deduplicationArray([1,1,2,5,9]));
// 输出 [1,2,5,9]
紧接着,我们使用Set方法来实现数组去重,该方法有一个特点,就是只储存唯一的元素,我们也可以使用该方法,将其唯一的值储存下,最终使用扩展运算符转为数组。

// 2.es6提出了一个Set对象,该对象只储存唯一的元素
function deduplicationArray1(arr) {
console.log(new Set(arr));
// 输入{2,5,9}
// 我们使用扩展运算符来实现数组输出
return [...new Set(arr)];
}
console.log(deduplicationArray1([2,2,5,9]));
//输出[2,5,9]
2.浅拷贝
在写浅拷贝前,我们不妨先了解一下浅拷贝的特点,拷贝其实就是我们的复制粘贴,可以理解为我们只模仿了外在样子,并没有模仿其内部精华一样。
浅拷贝主要有以下几个特点
1.浅拷贝只会拷贝引用类型的值,并不会拷贝引用类型原始数据类型的值,如果说引用类型时,如果是基本类型,那就是拷贝它的值,如果是引用类型的话,那就是拷贝的内存地址。
2.修改了浅拷贝拷贝的值之后,也会影响原来的数据,因为浅拷贝拷贝的是引用类型的内存地址,也就是说新旧对象共享一块内存
了解完,我们的浅拷贝特点,再去尝试手写,就非常轻松了
我们来尝试写一下

let obj = {
a: '1111',
b: '2222'
}
// let b = obj
// 采用Object的assign方法即可实现浅拷贝
let b = Object.assign({},obj);
setTimeout(() => {
obj.a = 'aaa';
console.log(obj, b);
}, 2000);
我们可以发现改变了以前的值,浅拷贝的值也会发生变化,在开发中,尽量减少浅拷贝的使用,接下来我们讲到的深拷贝,还是经常会用到的。
3.深拷贝
上面说的的浅拷贝,在深拷贝这里都可以将不行改为行即可,也就是我们深拷贝一个引用类型,其实就是重新开辟一个对象空间,不但可以克隆内容,他们也都指向不同的空间,所以一个值得变化,不会影响到其他的变化,深拷贝相比于浅拷贝来说,速度会很慢,并且花销也会很大。
我们来手写一个深拷贝。
我们使用序列化和反序列化对象的方法进行深拷贝

但是使用序列化和反序列化对象方法,容易存在弊端,比如我们obj中存在时间对象,等我们深拷贝完之后,时间对象就变成了字符串等等…
接下来我们写一个深拷贝方法,对数据进行深拷贝。

我们使用该方法,就可以对引用类型,进行深拷贝了因为我们知道之后Object数据类型时,浅拷贝才会拷贝引用地址,所以我优先判断一下是否是Object,再在Object中进行细分,可能这个值是一维,二维,三维,我们也不确定,所以这里用递归进行判断。
let obj = {
name: "小吕",
age: 18,
arr: [[1, 2], [3, 4], [5, 6]],
}
let obj1 = {}
copyFn(obj1, obj)
function copyFn(o, obj) {
for (let key in obj) {
// 先判断是否是数组,因为数组也是Object类型
// 采用递归的方式,获取到最后一层
if (obj[key] instanceof Array) {
o[key] = [];
copyFn(o[key], obj[key])
} else if (obj[key] instanceof Object) {
o[key] = {}
copyFn(o[key], obj[key])
} else {
o[key] = obj[key]
}
}
}
setTimeout(() => {
obj.name = "小苏"
}, 2000)
console.log(obj,obj1)
4.节流
我们先来了解一下节流的概念,其实防抖和节流都是一种优化的术语,节流主要是在一段时间内,防止高频的事件触发,也就是说,在一段时间内,只执行一次。
我们知道了概念,我们来手写一下,也就是让其一段时间只执行一次函数
比如:我们点击提交的时候,如果还没提交上的话,对于急性子人,还需要多点几下,这时候,就需要做节流阀了
我们模拟一下点击

function throttle(fn, delay = 100) {
// 设置一个节流阀
let flag = true;
return function (...args) {
// 如果是false,就不再执行
if (!flag) return;
// 否则的话,变为false
flag = false;
// 2秒后,再将其结果返回,点击再执行
setTimeout(() => {
fn.call(this, ...args);
flag = true;
}, delay);
}
}
let div = document.querySelector('.div');
div.addEventListener('click', throttle(function (e) {
console.log('点击了');
}, 2000));
5.防抖
对于防抖,其实就是当我们触发了一个时间,在一定时间内,没有再触发,我们才会执行这个方法,事件点击之后,并不会立即触发,而是会延迟触发
例如: 我们经常会遇到的输入框,如果不做防抖,那么我们没输入一个字就会触发一次请求,对于服务器来说,无疑是一个巨大的挑战,也会导致页面非常的卡顿,对于下拉框数据非常多的话,选择element ui的远程搜索也是很不错的选择。
后台 | 赶紧把下拉框换成输入搜索吧
了解完功能之后,我们来写一个防抖吧。

function debounce(fn, delay = 100) {
let timer = null;
return function (...args) {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
fn.call(this, ...args);
timer = null;
}, delay)
}
}
let inp = document.querySelector('.inp');
// 使用
inp.addEventListener('keyup', debounce(function () {
console.log(inp.value);
}, 500));
今日暂时就先写这点,希望可以帮到大家早日拿到满意的offer,如果以上内容,对大家有帮助,不要忘记点个关注,并设为星标!!!
声明:文中观点不代表本站立场。本文传送门:https://eyangzhen.com/311414.html