前端面试必备 || javascript手写题

以下内容是我归列的前端面试经常会遇到的手写题,主要是考察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

联系我们
联系我们
分享本页
返回顶部