手写方法
原生
数组
1.flat
function _flatten(arr){
let result=[]
for (let i = 0; i < arr.length; i++) {
if(arr[i] instanceof Array){
result=result.concat(_flatten(arr[i]))
}else{
result.push(arr[i])
}
}
return result
}
Array.prototype.myFlat=function(){
return _flatten(this)
}
var arr1 = [1, 2, 3, [1, 2, 3, 4, [2, 3, 4]]];
console.log( arr1.flat(Infinity));
console.log( arr1.myFlat());
2.map
Array.prototype.myMap=function(fn){
this.forEach((element,index) => {
result.push(fn(element,index))
});
return result
}
let arr=[1,2,3]
let r= arr.myMap((item,index)=>{
return item+1
})
console.log(r);
3.reduce
Array.prototype.myReduce=function(cb,initValue){
let result=initValue===undefined?this[0]:initValue
for(let i=0;i<this.length;i++){
result=cb(result,this[i],i)
}
return result
}
function fn(result, currentValue, index){
return result + currentValue
}
var arr = [2,3,4,5]
let a= arr.myReduce(fn,10)
console.log(a);
4.filter
Array.prototype.myFilter = function (callback) {
const res = []
for (let i = 0; i < this.length; i++) {
callback(this[i], i, this) && res.push(this[i])
}
return res
}
5.forEach
Array.prototype.myForEach = function (callback) {
for (let i = 0; i < this.length; i++) {
callback(this[i], i, this)
}
}
6.every
Array.prototype.myEvery = function (callback) {
let flag = true
for (let i = 0; i < this.length; i++) {
flag = callback(this[i], i, this)
if (!flag) break
}
return flag
}
7.some
Array.prototype.mySome = function (callback) {
let flag = false
for (let i = 0; i < this.length; i++) {
flag = callback(this[i], i, this)
if (flag) break
}
return flag
}
8.findIndex
Array.prototype.myFindIndex = function (callback) {
for (let i = 0; i < this.length; i++) {
if (callback(this[i], i, this)) {
return i
}
}
return -1
}
9. find
Array.prototype.myFind = function (callback) {
for (let i = 0; i < this.length; i++) {
if (callback(this[i], i, this)) {
return this[i]
}
}
return undefined
}
10.fill
Array.prototype.myFill = function (value, start = 0, end) {
end = end || this.length
for (let i = start; i < end; i++) {
this[i] = value
}
return this
}
11.includes
Array.prototype.myIncludes = function (value, start = 0) {
if (start < 0) start = this.length + start
const isNaN = Number.isNaN(value)
for (let i = start; i < this.length; i++) {
if (this[i] === value || Number.isNaN(this[i]) === isNaN) {
return true
}
}
return false
}
12.join
Array.prototype.myJoin = function (s = ',') {
let str = ''
for(let i = 0; i < this.length; i++) {
str = i === 0 ? `${str}${this[i]}` : `${str}${s}${this[i]}`
}
return str
}
13.splice
Array.prototype.mySplice = function (start, length, ...values) {
if (length === 0) return []
length = start + length > this.length - 1 ? this.length - start : length
console.log(length)
const res = [], tempArr = [...this]
for (let i = start; i < start + values.length; i++) {
this[i] = values[i - start]
}
this.length = start + values.length
if (values.length < length) {
const cha = length - values.length
console.log(cha)
for (let i = start + values.length; i < tempArr.length; i++) {
this[i] = tempArr[i + cha]
}
this.length = this.length - cha
}
if (values.length > length) {
for (let i = start + length; i < tempArr.length; i++) {
this.push(tempArr[i])
}
}
for (let i = start; i < start + length; i++) {
res.push(tempArr[i])
}
return res
}
对象
1.instanceof
function myInstanceof(target,origin){
while(target){
if(target.__proto__===origin.prototype){
return true
}else{
target=target.__proto__
}
}
return false
}
let arrt=[1,2,9]
console.log(myInstanceof(arrt,Array));
console.log(myInstanceof(arrt,Boolean));
5.call
Function.prototype.myCall = function(thisArg, ...args) {
thisArg.fn = this
return thisArg.fn(...args)
}
Function.prototype.myCall = function(thisArg, ...args) {
const fn = Symbol('fn')
thisArg = thisArg || window
thisArg[fn] = this
const result = thisArg[fn](...args)
delete thisArg[fn]
return result
}
6.apply
Function.prototype.myApply = function(thisArg, args) {
const fn = Symbol('fn')
thisArg = thisArg || window
thisArg[fn] = this
const result = thisArg[fn](...args)
delete thisArg[fn]
return result
}
7.bind
Function.prototype.myBind = function(thisArg, ...args) {
return () => {
this.apply(thisArg, args)
}
}
Function.prototype.myBind = function (thisArg, ...args) {
var self = this
var fbound = function () {
self.apply(this instanceof self ? this : thisArg, args.concat(Array.prototype.slice.call(arguments)))
}
fbound.prototype = Object.create(self.prototype);
return fbound;
}
10.Promise(简化版)
function Promise(fn) {
this.cbs = [];
const resolve = (value) => {
setTimeout(() => {
this.data = value;
this.cbs.forEach((cb) => cb(value));
});
}
fn(resolve);
}
Promise.prototype.then = function (onResolved) {
return new Promise((resolve) => {
this.cbs.push(() => {
const res = onResolved(this.data);
if (res instanceof Promise) {
res.then(resolve);
} else {
resolve(res);
}
});
});
};
11.new
function myNew(foo, ...args) {
let obj={}
obj.__proto__=foo.prototype
let result = foo.apply(obj, args)
return Object.prototype.toString.call(result) === '[object Object]' ? result : obj
}
12.ajax
function ajax(url) {
return new Promise((resolve,reject)=>{
const xhr =new XMLHttpRequest()
xhr.onreadystatechange(()=>{
if(xhr.readyState===4){
if(xhr.status==200){
resolve(JSON.parse(xhr.responseText))
}else{
reject('error')
}
}
})
xhr.send()
})
}
13.JSON.parse
function parse (json) {
return eval("(" + json + ")");
}
经典排序
1.bubbleSort
function bubbleSort(arr){
for (let i = 0; i < arr.length; i++) {
let flag = true
for (let j = 0; j < arr.length-i-1; j++) {
if(arr[j]>arr[j+1]){
flag = false
let temp =arr[j+1]
arr[j+1]=arr[j]
arr[j]=temp
}
}
if(flag)break;
}
return arr
}
2.selectionSort
function selectionSort(arr){
let min_index
for (let i = 0; i < arr.length-1; i++) {
min_index=i
for (let j = i+1; j < arr.length; j++) {
if(arr[min_index]>arr[j]){
min_index=j
}
}
let temp=arr[min_index]
arr[min_index]=arr[i]
arr[i]=temp
}
return arr
}
3.quickSort
function quickSort(arr) {
if(arr.length <= 1) return arr
const pivot = arr.length / 2 | 0
const pivotValue = arr.splice(pivot, 1)[0]
const leftArr = []
const rightArr = []
arr.forEach(val => {
val > pivotValue ? rightArr.push(val) : leftArr.push(val)
})
return [ ...quickSort(leftArr), pivotValue, ...quickSort(rightArr)]
}
function quickSort2(arr, left, right) {
if(right>left){
let pos=left-1
let p=arr[right]
for (let i = left; i <= right; i++) {
if(p>=arr[i]){
pos++
let temp = arr[pos]
arr[pos] = arr[i]
arr[i] = temp
}
}
quickSort2(arr,left,pos-1)
quickSort2(arr,pos+1,right)
}
return arr
}
4.mergeSort
function mergeSort(arr) {
if(arr.length <= 1) return arr
const midIndex = arr.length/2 | 0
const leftArr = arr.slice(0, midIndex)
const rightArr = arr.slice(midIndex, arr.length)
return merge(mergeSort(leftArr), mergeSort(rightArr))
}
function merge(leftArr, rightArr) {
const result = []
while(leftArr.length && rightArr.length) {
leftArr[0] <= rightArr[0] ? result.push(leftArr.shift()) : result.push(rightArr.shift())
}
while(leftArr.length) result.push(leftArr.shift())
while(rightArr.length) result.push(rightArr.shift())
return result
}
实用经典
1.debounce(防抖)
function debounce(func, wait) {
let timeout = null
return function() {
let context = this
let args = arguments
if (timeout) clearTimeout(timeout)
timeout = setTimeout(() => {
func.apply(context, args)
}, wait)
}
}
2.throttle(节流)
function throttle(func, wait) {
let timeout = null
return function() {
let context = this
let args = arguments
if (!timeout) {
timeout = setTimeout(() => {
timeout = null
func.apply(context, args)
}, wait)
}
}
}
3.curry(柯里化)
function curry(fn,len=fn.length){
return _curry.call(this,fn,len)
}
function _curry(fn,len,...args){
return function(...params){
let _args=[...args,...params]
if(_args.length>=len){
return fn.call(this,..._args)
}else{
return _curry.call(this,fn,len,..._args)
}
}
}
4.deepClone(深克隆)
function deepClone(target){
if(!['object','function'].includes(typeof target))return target
let result=Array.isArray(target)?[]:{}
for(let key in target){
if(target.hasOwnProperty(key)){
result[key]=typeof target[key]==='object'?deepClone(target[key]) :target[key]
}
}
return result
}
5.unique(去重)
function quchong1(arr) {
const newArr = []
arr.reduce((pre, next) => {
if (!pre[next]) {
pre[next] = 1
newArr.push(next)
}
return pre
}, {})
return newArr
}
function quchong2(arr) {
return [...new Set(arr)]
}
6.compose(组合)
function compose(...fn) {
if (fn.length === 0) return (num) => num
if (fn.length === 1) return fn[0]
return fn.reduce((pre, next) => {
return (num) => {
return next(pre(num))
}
})
}
function fn1(x) {
return x + 1;
}
function fn2(x) {
return x + 2;
}
function fn3(x) {
return x + 3;
}
function fn4(x) {
return x + 4;
}
const a = compose(fn1, fn2, fn3, fn4);
console.log(a)
console.log(a(1));
7.LRU(LRU缓存策略)
class LRUCache {
constructor(size) {
this.size = size
this.cache = new Map()
}
get(key) {
const hasKey = this.cache.has(key)
if (hasKey) {
const val = this.cache.get(key)
this.cache.delete(key)
this.cache.set(key, val)
return val
} else {
return -1
}
}
put(key, val) {
const hasKey = this.cache.has(key)
if (hasKey) {
this.cache.delete(key)
}
this.cache.set(key, val)
if (this.cache.size > this.size) {
this.cache.delete(this.cache.keys().next().value)
}
}
}
8.EventEmitter (发布订阅)
class EventEmitter {
constructor() {
this.cache = {}
}
on(name, fn) {
const tasks = this.cache[name]
if (tasks) {
this.cache[name].push(fn)
} else {
this.cache[name] = [fn]
}
}
off(name, fn) {
const tasks = this.cache[name]
if (task) {
const index = tasks.findIndex(item => item === fn)
if (index >= 0) {
this.cache[name].splice(index, 1)
}
}
}
emit(name, once = false, ...args) {
const tasks = this.cache[name].slice()
if (tasks) {
for (let fn of tasks) {
fn(...args)
}
}
if (once) {
delete this.cache[name]
}
}
once(name, ...args) {
this.emit(name, true, ...args)
}
}
9.dom2tree(抽象dom)
<div>
<span></span>
<ul>
<li></li>
<li></li>
</ul>
</div>
{
tag: 'DIV',
children: [
{ tag: 'SPAN', children: [] },
{
tag: 'UL',
children: [
{ tag: 'LI', children: [] },
{ tag: 'LI', children: [] }
]
}
]
}
function dom2tree(dom) {
const obj = {}
obj.tag = dom.tagName
obj.children = []
dom.childNodes.forEach(child => obj.children.push(dom2tree(child)))
return obj
}
10.render(渲染)
function render(vnode) {
if (typeof vnode === "number") {
vnode = String(vnode);
}
if (typeof vnode === "string") {
return document.createTextNode(vnode);
}
const dom = document.createElement(vnode.tag);
if (vnode.attrs) {
Object.keys(vnode.attrs).forEach((key) => {
const value = vnode.attrs[key];
dom.setAttribute(key, value);
});
}
vnode.children.forEach((child) => dom.appendChild(render(child)));
return dom;
}
11.cycleDetector(环引用检测)
function cycleDetector(obj) {
const arr = [obj]
let flag = false
function cycle(o) {
const keys = Object.keys(o)
for (const key of keys) {
const temp = o[key]
if (typeof temp === 'object' && temp !== null) {
if (arr.indexOf(temp) >= 0) {
flag = true
return
}
arr.push(temp)
cycle(temp)
}
}
}
cycle(obj)
return flag
}
var obj = {
a: {
c: [
1, 2
]
},
b: 1
}
console.log(cycleDetector(obj))
12.loopGetLevel(检测对象层数)
function loopGetLevel(obj) {
var res = 1;
function computedLevel(obj, level) {
var level = level ? level : 0;
if (typeof obj === 'object') {
for (var key in obj) {
if (typeof obj[key] === 'object') {
computedLevel(obj[key], level + 1);
} else {
res = level + 1 > res ? level + 1 : res;
}
}
} else {
res = level > res ? level : res;
}
}
computedLevel(obj)
return res
}
const obj = {
a: { b: [1] },
c: { d: { e: { f: 1 } } }
}
console.log(loopGetLevel(obj))
13.flatten(对象扁平化)
const isObject = (val) => typeof val === "object" && val !== null
function flatten(obj) {
if (!isObject(obj)) return
const res = {}
const dfs = (cur, prefix) => {
if (isObject(cur)) {
if (Array.isArray(cur)) {
cur.forEach((item, index) => {
dfs(item, `${prefix}[${index}]`)
})
} else {
for(let key in cur) {
dfs(cur[key], `${prefix}${prefix ? '.' : ''}${key}`)
}
}
} else {
res[prefix] = cur
}
}
dfs(obj, '')
return res
}
const obj = {
a: {
b: 1,
c: 2,
d: {e: 5}
},
b: [1, 3, {a: 2, b: 3}],
c: 3
}
console.log(flatten(obj))
14.(a == 1 && a == 2 && a == 3)为true
var a = {
i: 1,
toString: function () {
return a.i++;
}
}
console.log(a == 1 && a == 2 && a == 3)
var a = [1, 2, 3];
a.join = a.shift;
console.log(a == 1 && a == 2 && a == 3);
var val = 0;
Object.defineProperty(window, 'a', {
get: function () {
return ++val;
}
});
console.log(a == 1 && a == 2 && a == 3)
15.Scheduler(Promise并发调度)
class Scheduler {
constructor(limit) {
this.queue = []
this.limit = limit
this.count = 0
}
add(time, order) {
const promiseCreator = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(order)
resolve()
}, time)
})
}
this.queue.push(promiseCreator)
}
taskStart() {
for(let i = 0; i < this.limit; i++) {
this.request()
}
}
request() {
if (!this.queue.length || this.count >= this.limit) return
this.count++
this.queue.shift()().then(() => {
this.count--
this.request()
})
}
}
const scheduler = new Scheduler(2);
const addTask = (time, order) => {
scheduler.add(time, order);
};
addTask(1000, "1");
addTask(500, "2");
addTask(300, "3");
addTask(400, "4");
scheduler.taskStart();
16.lazyMan
class _LazyMan {
constructor(name) {
this.tasks = []
const task = () => {
console.log(`Hi! This is ${name}`)
this.next()
}
this.tasks.push(task)
setTimeout(() => {
this.next()
}, 0)
}
next() {
const task = this.tasks.shift()
task && task()
}
sleep(time) {
this.sleepWrapper(time, false)
return this
}
sleepFirst(time) {
this.sleepWrapper(time, true)
return this
}
sleepWrapper(time, first) {
const task = () => {
setTimeout(() => {
console.log(`Wake up after ${time}`)
this.next()
}, time * 1000)
}
if (first) {
this.tasks.unshift(task)
} else {
this.tasks.push(task)
}
}
eat(food) {
const task = () => {
console.log(`Eat ${food}`);
this.next();
};
this.tasks.push(task);
return this;
}
}
const lazyMan = (name) => new _LazyMan(name)
lazyMan('Hank').sleep(1).eat('dinner')
lazyMan('Hank').eat('dinner').eat('supper')
lazyMan('Hank').eat('supper').sleepFirst(5)
17.Add(链式加法)
function add(...args1) {
let allArgs = [...args1]
function fn(...args2) {
if (!args2.length) return fn.toString()
allArgs = [...allArgs, ...args2]
return fn
}
fn.toString = function () {
return allArgs.reduce((pre, next) => pre + next)
}
return fn
}
console.log(add(1)(2)(3)())
console.log(add(1, 2)(3)())
Promise
1.all
function all(promises) {
const result = []
let count = 0
return new MyPromise((resolve, reject) => {
const addData = (index, value) => {
result[index] = value
count++
if (count === promises.length) resolve(result)
}
promises.forEach((promise, index) => {
if (promise instanceof MyPromise) {
promise.then(res => {
addData(index, res)
}, err => reject(err))
} else {
addData(index, promise)
}
})
})
}
2.race
function race(promises) {
return new MyPromise((resolve, reject) => {
promises.forEach(promise => {
if (promise instanceof MyPromise) {
promise.then(res => {
resolve(res)
}, err => {
reject(err)
})
} else {
resolve(promise)
}
})
})
}
3.allSettled
function allSettled(promises) {
return new Promise((resolve, reject) => {
const res = []
let count = 0
const addData = (status, value, i) => {
res[i] = {
status,
value
}
count++
if (count === promises.length) {
resolve(res)
}
}
promises.forEach((promise, i) => {
if (promise instanceof MyPromise) {
promise.then(res => {
addData('fulfilled', res, i)
}, err => {
addData('rejected', err, i)
})
} else {
addData('fulfilled', promise, i)
}
})
})
}
4.any
function any(promises) {
return new Promise((resolve, reject) => {
let count = 0
promises.forEach((promise) => {
promise.then(val => {
resolve(val)
}, err => {
count++
if (count === promises.length) {
reject(new AggregateError('All promises were rejected'))
}
})
})
})
}
}
5.finally
Promise.prototype.finally = function(callback) {
return this.then(res => {
callback()
return res
}, err => {
callback()
throw err
})
}