数组原型方法
map
javascript//reduce实现 Array.prototype.myMap = function (fn) { return this.reduce((previousValue, currentValue, idx) => { previousValue.push(fn(currentValue, idx)) return previousValue }, []) }
flat
javascript//代码https://github.com/zzfn/best-practice/blob/main/javascript/other/flat.js //递归 Array.prototype.myFlat = function (level = 1) { const array = this if (level > 0) { let result = []; for (const item of array) { if (Array.isArray(item)) { result = [...result, ...item.myFlat(level - 1)] } else { result.push(item) } } return result; } else { return array; } } //reduce Array.prototype.myFlat = function (level = 1) { return level > 0 ? this.reduce((acc, item) => { if (Array.isArray(item)) { return [...acc, ...item.myFlat(level - 1)] } else { return [...acc, item] } }, []) : this } console.log([1, 2, [3, [4, [5]]]].myFlat(2))
reverse
javascriptconst arr = [1, 2, 3, 4, 5]; Array.prototype.myReverse = function () { const o=[] const arr=this while (arr.length){ o.unshift(arr.shift()) } return o } console.log(arr.myReverse())
reduce
jsArray.prototype.myReduce = function (fn, initialValue) { let acc = initialValue; for (let i = 0; i < this.length; i++) { if (acc === undefined) { acc = this[i]; } else { acc = fn(acc, this[i], i, this); } } return acc; }
javascriptArray.prototype.myReduce = function (callback, initialValue) { // 判断调用该API的元素是否为null if (this == null) { throw new TypeError('this is null or not defined') } // 判断是否为function if (typeof callback !== "function") { throw new TypeError(callback + ' is not a function') } const arr = this const len = arr.length // 第二个参数 let accumulator = initialValue let index = 0 // 如果第二个参数是undefined 则数组的第一个有效值 // 作为累加器的初始值 if (accumulator === undefined) { // 找到数组中的第一个有效值 不一定就是arr[0] while (index < len && !(index in arr)) { index++ } if (index >= len) { throw new TypeError('Reduce of empty array with no initial value') } // 输出第一个有效数组元素,作为累加器的第一个元素 accumulator = arr[index++] } while (index < len) { if (index in arr) { // arr[index] 为 accumulator 的下一个元素 accumulator = callback.call(undefined, accumulator, arr[index], index, arr) } // 持续后移 index++ } // 返回结果 return accumulator }
some
javascriptArray.prototype.myReduce=function(fn,initalValue){ let initialArr = this; let arr = initialArr.concat(); if (initalValue) arr.unshift(initalValue); let index, newValue; while (arr.length > 1) { index = initialArr.length - arr.length + 1; newValue = fn.call(null, arr[0], arr[1], index, initialArr); arr.splice(0, 2, newValue); } return newValue; }
every
filter
foreach
javascriptArray.prototype.myForEach = function (callback, thisArg) { // 判断调用该API的元素是否为null if (this == null) { throw new TypeError('this is null or not defined') } // 判断是否为function if (typeof callback !== "function") { throw new TypeError(callback + ' is not a function') } // 通过this得到调用者arr const arr = this // 确定循环变量 let index = 0 // 循环遍历给每个数组元素调用callback while (index < arr.length) { // 判断是否存在这个项 if (index in arr) { // 通过call将this指向thisArg,并且传入3个参数 callback.call(thisArg, arr[index], index, arr) } index++ } }
对象原型方法
Object.assign
javascriptObject.myAssign = function (target, ...source) { if ([null, undefined].includes(target)) { throw new TypeError('Cannot convert undefined or null to object') } let result = Object(target) source.forEach(function (obj) { if (obj) { for (let key in obj) { if (Object.prototype.hasOwnProperty.call(obj,key)) { result[key] = obj[key] } } } }) return result }
函数原型方法
call
javascriptFunction.prototype.myCall = function (context, ...arg) { const ctx = context || window ctx.fn = this const result = ctx.fn(...arg) delete ctx.fn return result; } //es6 Function.prototype.myCall = function (thisArg, ...argArray) { thisArg.fn=this const result=thisArg.fn(...argArray) Reflect.deleteProperty(thisArg,'fn') return result }
apply
javascriptFunction.prototype.myApply = function (context, arg) { const ctx = context || window ctx.fn = this const result = Array.isArray(arg) ? ctx.fn(...arg) : ctx.fn() delete ctx.fn return result; } // Function.prototype.myApply = function (thisArg, ...argArray) { thisArg.fn=this //判断argArray类数组或者数组 thisArg.fn(argArray) Reflect.deleteProperty(thisArg,'fn') }
bind
javascript//使用apply Function.prototype.myBind = function (ctx) { const fn = this; return function (...arg) { return fn.apply(ctx,...arg); }; }; //构造函数 Function.prototype.myBind = function (context, ...args) { const ctx = context const _this = this const F = function () { } const ret = function (..._args) { if (this instanceof F) { return new _this(...args, ..._args) } return _this.apply(context, args.concat(_args)) } F.prototype = this.prototype ret.prototype = new F() return ret; } //不使用apply Function.prototype.myBind = function (context, ...arg) { const ctx = context || window const fn = Symbol() ctx[fn] = this return function (..._arg) { const result = ctx[fn](...arg, ..._arg) delete ctx[fn] return result } } Function.prototype.myBind = function (context, ...args) { const ctx = context const fn = Symbol() ctx[fn] = this const F = function () {} const ret = function (..._args) { if (this instanceof F) { const result = new ctx[fn](...args, ..._args) delete ctx[fn] return result } const result = ctx[fn](...args, ..._args) delete ctx[fn] return result } F.prototype = this.prototype ret.prototype = new F() return ret; }
trim
javascriptString.prototype.myTrim=function () { return this.replace(/^\s\s*/,'').replace(/\s\s*$/,'') }
其他常见手写题
new
-
创建一个空的简单Javascript对象 (即);
-
继承父类原型上的方法;
-
添加父类的属性到新的对象上并初始化. 保存方法的执行结果;
-
如果执行结果有返回值并且是一个对象, 返回执行的结果, 否则, 返回新创建的对象;
javascriptfunction myNew(fn,...args) { let obj = {} obj.__proto__ = fn.prototype let result = fn.apply(obj,args) return result instanceof Object ? result : obj } function myNew(fn,...args) { let obj = Object.create(fn.prototype) let result = fn.apply(obj,args) return result instanceof Object ? result : obj }
instanceof
javascriptfunction myInstanceof(child, parent) { let proto = Object.getPrototypeOf(child); let prototype = parent.prototype while (proto) { if (proto === prototype) { return true; } proto = Object.getPrototypeOf(proto); } return false; }
柯理化
javascriptconst curry = (fn, ...args) => args.length >= fn.length ? fn(...args) : (..._args) => curry(fn, ...args, ..._args); const curry = (fn, ...args) => args.length < fn.length ? curry.bind(null, fn, ...args) : fn(...args);
反柯理化
javascriptFunction.prototype.uncurrying = function() { var self = this; return function() { return Function.prototype.call.apply(self,arguments) }; }
防抖
javascriptfunction debounce(fn,delay=1000) { let timer=null return function (...arg) {//不能用箭头函数,不然上下文不对 if(timer){ clearTimeout(timer) } timer=setTimeout(()=>{ clearTimeout(timer) fn.apply(this,arg) timer = null },delay) } }
节流
定时器版本
javascriptfunction throttle(fn, delay) { let timer = null; return function(...args) { if (timer) return; timer = setTimeout(() => { clearTimeout(timer); timer = null; fn.apply(this, args); }, delay); }; }
时间戳版本
javascriptconst throttle = (func, delay) => { let startTime = Date.now(); return function(...args) { const currentTime = Date.now(); if (delay <= (currentTime - startTime)) { func.apply(this, args); startTime = Date.now(); } }; };
数组转树
javascriptfunction list2tree(list) { const option = {id: 'id', pid: 'pid', children: 'children'}; const a=list.reduce((prev, curr) => { const obj = list.find((item) => item[option.id] === curr[option.pid]); if (obj) { !Object.prototype.hasOwnProperty.call(obj, option.children) && (obj[option.children] = []); obj[option.children].push(curr); } else { prev.push(curr); } return prev; }, []); console.log(a) }
once
javascriptfunction once(fn) { let ret return function (...args) { if (!fn) return ret ret = fn(...args) fn = undefined return ret } }