您现在的位置是:亿华云 > 应用开发

32个手撕JS,彻底摆脱初级前端(面试高频)-上篇

亿华云2025-10-03 18:24:28【应用开发】3人已围观

简介关于源码都紧遵规范,都可跑通MDN示例,其余的大多会涉及一些关于JS的应用题和本人面试过程01.数组扁平化数组扁平化是指将一个多维数组变为一个一维数组constarr=[1,[2,[3,[4,5]]]

 关于源码都紧遵规范,个手都可跑通MDN示例,撕J试高其余的底摆端面大多会涉及一些关于JS的应用题和本人面试过程

01.数组扁平化数组扁平化是指将一个多维数组变为一个一维数组

const arr = [1, [2, [3, [4, 5]]], 6]; // => [1, 2, 3, 4, 5, 6] 复制代码 

方法一:使用flat()

const res1 = arr.flat(Infinity); 复制代码 

方法二:利用正则

const res2 = JSON.stringify(arr).replace(/\[|\]/g, ).split(,); 复制代码 

但数据类型都会变为字符串

方法三:正则改良版本

const res3 = JSON.parse([ + JSON.stringify(arr).replace(/\[|\]/g, ) + ]); 复制代码 

方法四:使用reduce

const flatten = arr => {    return arr.reduce((pre, cur) => {      return pre.concat(Array.isArray(cur) ? flatten(cur) : cur);   }, []) } const res4 = flatten(arr); 复制代码 

方法五:函数递归

const res5 = []; const fn = arr => {    for (let i = 0; i < arr.length; i++) {      if (Array.isArray(arr[i])) {        fn(arr[i]);     } else {        res5.push(arr[i]);     }   } } fn(arr); 复制代码 

02.数组去重

const arr = [1, 1, 1, 17, true, true, false, false, true, a, { }, { }]; // => [1, 1, 17, true, false, true, a, { }, { }] 复制代码 

方法一:利用Set

const res1 = Array.from(new Set(arr)); 复制代码 

方法二:两层for循环+splice

const unique1 = arr => {    let len = arr.length;   for (let i = 0; i < len; i++) {      for (let j = i + 1; j < len; j++) {        if (arr[i] === arr[j]) {          arr.splice(j, 1);         // 每删除一个树,j--保证j的脱初值经过自加后不变。同时,频上篇len--,个手减少循环次数提升性能         len--;         j--;       }     }   }   return arr; } 复制代码 

方法三:利用indexOf

const unique2 = arr => {    const res = [];   for (let i = 0; i < arr.length; i++) {      if (res.indexOf(arr[i]) === -1) res.push(arr[i]);   }   return res; } 复制代码 

当然也可以用include、撕J试高filter,底摆端面思路大同小异。脱初

方法四:利用include

const unique3 = arr => {    const res = [];   for (let i = 0; i < arr.length; i++) {      if (!res.includes(arr[i])) res.push(arr[i]);   }   return res; } 复制代码 

方法五:利用filter

const unique4 = arr => {    return arr.filter((item,频上篇 index) => {      return arr.indexOf(item) === index;   }); } 复制代码 

方法六:利用Map

const unique5 = arr => {    const map = new Map();   const res = [];   for (let i = 0; i < arr.length; i++) {      if (!map.has(arr[i])) {        map.set(arr[i], true)       res.push(arr[i]);     }   }   return res; } 复制代码 

03.类数组转化为数组类数组是具有length属性,但不具有数组原型上的个手方法。常见的撕J试高类数组有arguments、DOM操作方法返回的底摆端面结果。

方法一:Array.from

Array.from(document.querySelectorAll(div)) 复制代码 

方法二:Array.prototype.slice.call()

Array.prototype.slice.call(document.querySelectorAll(div)) 复制代码 

方法三:扩展运算符

[...document.querySelectorAll(div)] 复制代码 

方法四:利用concat

Array.prototype.concat.apply([],脱初 document.querySelectorAll(div)); 复制代码 

04.Array.prototype.filter()

rray.prototype.filter = function(callback, thisArg) {    if (this == undefined) {      throw new TypeError(this is null or not undefined);   }   if (typeof callback !== function) {      throw new TypeError(callback + is not a function);   }   const res = [];   // 让O成为回调函数的对象传递(强制转换对象)   const O = Object(this);   // >>>0 保证len为number,且为正整数   const len = O.length >>> 0;   for (let i = 0; i < len; i++) {      // 检查i是频上篇否在O的属性(会检查原型链)     if (i in O) {        // 回调函数调用传参       if (callback.call(thisArg, O[i], i, O)) {          res.push(O[i]);       }     }   }   return res; } 复制代码 

对于>>>0有疑问的:解释>>>0的作用

05.Array.prototype.map()

Array.prototype.map = function(callback, thisArg) {    if (this == undefined) {      throw new TypeError(this is null or not defined);   }   if (typeof callback !== function) {      throw new TypeError(callback +  is not a function);   }   const res = [];   // 同理   const O = Object(this);   const len = O.length >>> 0;   for (let i = 0; i < len; i++) {      if (i in O) {        // 调用回调函数并传入新数组       res[i] = callback.call(thisArg, O[i], i, this);     }   }   return res; } 复制代码 

06.Array.prototype.forEach()

forEach跟map类似,高防服务器唯一不同的是forEach是没有返回值的。

Array.prototype.forEach = function(callback, thisArg) {    if (this == null) {      throw new TypeError(this is null or not defined);   }   if (typeof callback !== "function") {      throw new TypeError(callback +  is not a function);   }   const O = Object(this);   const len = O.length >>> 0;   let k = 0;   while (k < len) {      if (k in O) {        callback.call(thisArg, O[k], k, O);     }     k++;   } } 复制代码 

07.Array.prototype.reduce()

Array.prototype.reduce = function(callback, initialValue) {    if (this == undefined) {      throw new TypeError(this is null or not defined);   }   if (typeof callback !== function) {      throw new TypeError(callbackfn +  is not a function);   }   const O = Object(this);   const len = this.length >>> 0;   let accumulator = initialValue;   let k = 0;   // 如果第二个参数为undefined的情况下   // 则数组的第一个有效值作为累加器的初始值   if (accumulator === undefined) {      while (k < len && !(k in O)) {        k++;     }     // 如果超出数组界限还没有找到累加器的初始值,则TypeError     if (k >= len) {        throw new TypeError(Reduce of empty array with no initial value);     }     accumulator = O[k++];   }   while (k < len) {      if (k in O) {        accumulator = callback.call(undefined, accumulator, O[k], k, O);     }     k++;   }   return accumulator; } 复制代码 

08.Function.prototype.apply()第一个参数是绑定的this,默认为window,第二个参数是数组或类数组

Function.prototype.apply = function(context = window, args) {    if (typeof this !== function) {      throw new TypeError(Type Error);   }   const fn = Symbol(fn);   context[fn] = this;   const res = context[fn](...args);   delete context[fn];   return res; } 复制代码 

09.Function.prototype.call于call唯一不同的是,call()方法接受的是一个参数列表

Function.prototype.call = function(context = window, ...args) {    if (typeof this !== function) {      throw new TypeError(Type Error);   }   const fn = Symbol(fn);   context[fn] = this;   const res = this[fn](...args);   delete this.fn;   return res; } 复制代码 

10.Function.prototype.bind

Function.prototype.bind = function(context, ...args) {    if (typeof this !== function) {      throw new Error("Type Error");   }   // 保存this的值   var self = this;   return function F() {      // 考虑new的情况     if(this instanceof F) {        return new self(...args, ...arguments)     }     return self.apply(context, [...args, ...arguments])   } } 复制代码 

11.debounce(防抖)触发高频时间后n秒内函数只会执行一次,如果n秒内高频时间再次触发,则重新计算时间。

const debounce = (fn, time) => {    let timeout = null;   return function() {      clearTimeout(timeout)     timeout = setTimeout(() => {        fn.apply(this, arguments);     }, time);   } }; 复制代码 

防抖常应用于用户进行搜索输入节约请求资源,window触发resize事件时进行防抖只触发一次。

12.throttle(节流)高频时间触发,但n秒内只会执行一次,所以节流会稀释函数的执行频率。亿华云

const throttle = (fn, time) => {    let flag = true;   return function() {      if (!flag) return;     flag = false;     setTimeout(() => {        fn.apply(this, arguments);       flag = true;     }, time);   } } 复制代码 

节流常应用于鼠标不断点击触发、监听滚动事件。

13.函数珂里化

指的是将一个接受多个参数的函数 变为 接受一个参数返回一个函数的固定形式,这样便于再次调用,例如f(1)(2) 

经典面试题:实现add(1)(2)(3)(4)=10; 、 add(1)(1,2,3)(2)=9;

function add() {    const _args = [...arguments];   function fn() {      _args.push(...arguments);     return fn;   }   fn.toString = function() {      return _args.reduce((sum, cur) => sum + cur);   }   return fn; } 复制代码 

14.模拟new操作3个步骤:

以ctor.prototype为原型创建一个对象。 执行构造函数并将this绑定到新创建的对象上。 判断构造函数执行返回的结果是否是引用数据类型,若是则返回构造函数执行的结果,否则返回创建的对象。 function newOperator(ctor, ...args) {    if (typeof ctor !== function) {      throw new TypeError(Type Error);   }   const obj = Object.create(ctor.prototype);   const res = ctor.apply(obj, args);   const isObject = typeof res === object && res !== null;   const isFunction = typeof res === function;   return isObject || isFunction ? res : obj; } 复制代码 

15.instanceofinstanceof运算符用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上。

const myInstanceof = (left, right) => {    // 基本数据类型都返回false   if (typeof left !== object || left === null) return false;   let proto = Object.getPrototypeOf(left);   while (true) {      if (proto === null) return false;     if (proto === right.prototype) return true;     proto = Object.getPrototypeOf(proto);   } } 复制代码 

16.原型继承这里只写寄生组合继承了,中间还有几个演变过来的源码下载继承但都有一些缺陷

function Parent() {    this.name = parent; } function Child() {    Parent.call(this);   this.type = children; } Child.prototype = Object.create(Parent.prototype); Child.prototype.constructor = Child; 复制代码 

很赞哦!(728)