您现在的位置是:亿华云 > 应用开发
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()
对于>>>0有疑问的:解释>>>0的作用
05.Array.prototype.map()
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()
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)
上一篇: 数据架构中的数据问题