手写JS方法
Promise
Promise.all
function MyPromiseAll(arr){
return new Promise((resolve,reject)=>{
let res=[]
for(let i=0;i<arr.length;i++){
Promise.resolve(arr[i])
.then((data)=>{
res[i]=data
if(!res.includes(undefined)&&res.length===arr.length){
resolve(res)
}
})
.catch(err=>{
reject(err)
})
}
})
}
Promise.race
function MyPromiseRace(arr){
return new Promise((resolve,reject)=>{
for(let i=0;i<arr.length;i++){
Promise.resolve(arr[i])
.then(data=>{
resolve(data)
})
.catch(err=>{
resolve(err)
})
}
})
}
深拷贝
const setTag='[object Set]'
const mapTag='[object Map]'
const funTag='[object Function]'
const dateTag='[object Date]'
const regxTag='[object RegExp]'
const symbolTag='[object Symbol]'
const isObject = (target) => {
const type = typeof target
return target !== null && (type === 'object' || type === 'function')
}
const getType=(obj)=>{
return Object.prototype.toString.call(obj)
}
const getInit=(obj)=>{
const con=obj.constructor
return new con()
}
function deepClone(target, map = new Map()) {
//原始类型直接返回
if (!isObject(target)) return target
// let clone = target instanceof Array ? [] : {}
//获取克隆模板
let clone = getInit(target)
//防止循环引用
if (map.get(target)) {
return map.get(target)
}
map.set(target, clone)
const type=getType(target)
//克隆set
if(type === setTag){
target.forEach((item)=>{
clone.add(deepClone(item,map))
})
return clone
}
//克隆map
if(type === mapTag){
target.forEach((value,key)=>{
clone.set(key,deepClone(value,map))
})
return clone
}
//克隆函数
if(type === funTag ){
return target
}
//克隆date
if(type===dateTag){
return new target.constructor(target)
}
//克隆regex
if(type === regxTag){
return new target.constructor(target.source,/\w*$/.exec(target))
}
//克隆symbol---bug!作为基本类型返回,导致克隆对象和源对象Symbol相等
if(type === symbolTag){
//有待商榷
}
//对象和数组
for (const key in target) {
clone[key] = deepClone(target[key], map)
}
return clone
}
AJAX
bind
Function.prototype.myBind=(obj,...args)=>{
let that=this
return (...newArgs)=>{
that.apply(obj,[...args,...newArgs])
}
}
Function.prototype.myBind= (obj,...args)=>{
obj.fn=this
return (...newArgs)=>{
obj.fn(...newArgs,...args)
delete obj.fn
}
}
apply
Function.prototype.myApply=(obj,args)=>{
obj.fn=this
let rs=obj.fn(...args)
delete obj.fn
return rs
}
call
Function.prototype.myCall=(obj,...args)=>{
obj.fn=this
let rs=obj.fn(...args)
delete obj.fn
return rs
}
reduce
Array.prototype.myReduce = function (cb, initVal) {
let pre = initVal ? initVal : this.splice(0, 1)[0]
for (let i = 0; i < this.length; i++) {
pre = cb(pre, this[i], i, this)
}
return pre
}
instanceof
const myInstanceof=(left,right)=>{
let proto=right.prototype
let _left=left.__proto__
while(_left){
if(_left===proto) return true
_left=_left.__proto__
}
return false
}
console.log(myInstanceof([],Object))
防抖节流
// 防抖:连续触发多次,最后一次执行
function debounce(fn, delay) {
let timer
return () => {
if (timer) {
clearTimeout(timer)
}
timer=setTimeout(() => {
fn()
}, delay)
}
}
const fn = () => {
console.log('hello')
}
window.addEventListener('click', debounce(fn, 1000))//测试
//节流:一段之间内连续触发,只执行一次
function throttle(fn,time){
let oldTime=Date.now()
return ()=>{
let newTime=Date.now()
if(newTime-oldTime>=time){
fn()
oldTime=newTime
}
}
}
const fn=()=>{
console.log('hello')
}
window.addEventListener('click',throttle(fn,1000))//测试
柯里化
//定长参数
function curry(fn,...args){
if(args.length>=fn.length){
return fn(...args)
}else {
return (..._args)=> curry(fn,...args,..._args)
}
}
function add(a,b,c){
return a+b+c
}
const curryAdd=curry(add)
console.log(curryAdd(1,2,3))//6
console.log(curryAdd(1)(2)(3))//6
//不定长参数
function curry(fn,...args){
function _curry(..._args){
return curry(fn,...args,..._args)
}
_curry.toString=function(){
return fn(...args)
}
return _curry
}
function dynamicAdd() {
return [...arguments].reduce((prev, curr) => prev + curr)
}
let add = curry(dynamicAdd);
alert(add(1)(2)(3)(4))//console.log输出函数体,需要alert
发布订阅
class EventEmitter{
constructor() {
this.events={}
}
on(eventName,fn){
if(!this.events[eventName]){
this.events[eventName]=[fn]
}else{
this.events[eventName].push(fn)
}
}
emit(eventName,...args){
this.events[eventName].forEach(fn=>fn.apply(this,args))
}
off(eventName,fn){
this.events[eventName]=this.events[eventName].filter(item=>item!==fn)
}
once(eventName,fn){
let that=this
function func(){
fn()
that.off(eventName,func)
}
this.on(eventName,func)
}
}
setTimeout实现setInterval
function myInterval(fn,wait){
setTimeout(()=>{
fn()
myInterval(fn,wait)
},wait)
}
力扣高频题
- 11 盛水最多容器(42)
- 15 三数之和为0
- 20 判断括号有效
- 21 合并两个有序链表
- 25 K个一组反转链表
- 42 接雨水
- 46 全排列(77)
- 50 快速幂
- 53 最大子数组和
- 66 加一
- 77 组合
- 98 验证二叉搜索数
- 110 平衡二叉树
- 134 加油站
- 136 只出现一次的数字
- 137 只出现一次的数字2
- 146 LRU缓存
- 206 反转链表
- 215 数组中的第K个最大元素
- 232 用栈实现队列
- 300 最长递增序列、最长公共子串
- 动态规划、二分查找
- 328 奇偶链表
- 343 整数拆分
- 382 链表随机结点(水塘抽样)
- 415 大数加法
- 470 用Rand7实现Rand10 1.27
- 496 下一个更大元素 1.27
- 704 二分查找
- 860 柠檬水找零
简单算法题
斐波那契
function fib(n) {
if(n<=2) return 1
return fib(n-1)+fib(n-2)+fib(n-3)
}
// 拓展---三数之和---尾递归优化
//1 1 1 3 5 9 17
function fib(n,a=1,b=1,sum=1){
if (n===3) return sum
return fib(n-1,b,sum,a+b+sum)
}
数组拍平
function flatten(arr){
let res=[]
for(let i=0;i<arr.length;i++){
if(Array.isArray(arr[i])){
res=res.concat(flatten(arr[i]))
}else{
res.push(arr[i])
}
}
return res
}
数组去重
function fn(arr){
return Array(...new Set(arr))
}
function fn2(arr){
return arr.filter((value,index)=> arr.indexOf(value)===index)
}
function fn3(arr){
return arr.reduce((acc,cur)=>{
return acc.includes(cur)?acc:acc.concat(cur)
},[])
}
function fn4(arr){
for(let i=0;i<arr.length;i++){
for(let j=i+1;j<arr.length;j++){
if(arr[i]===arr[j]){
arr.splice(j,1)
j--
}
}
}
return arr
}
let arr=[2,3,4,5,6,3,3,3,3,4,5,6,4]
console.log(fn(arr))
console.log(fn2(arr))
console.log(fn3(arr))
console.log(fn4(arr))
找出数组中重复元素
两个无序数组合并为有序数组
环形链表找入口节点
质数(素数)
//返回一个数的所有质因数
function primeNumber(n){
let k=2
let rs=[]
while(k<=n){
if(k===n){
rs.push(n)
break;
}else{
if(n%k===0){
rs.push(k)
n=n/k
}else{
k++
}
}
}
return rs
}
//判断一个数为质数
function isPrime(n){
if(n<2) return false
if(n%2===0) return false
for(let k=3;k<=Math.sqrt(n);k+=2){
if(n%k===0) return false
}
return true
}
排序
快排
//借助额外空间
function quickSort(arr) {
if (arr.length <= 1) return arr
let left = [], right = []
let pivot = arr.splice(arr.length >> 1, 1)[0]
for (let i = 0; i < arr.length; i++) {
if (arr[i] <= pivot) left.push(arr[i])
else right.push(arr[i])
}
return quickSort(left).concat(pivot, quickSort(right))
}
//原地转换,不使用额外空间
function quickSort(arr, left, right) {
if(left>=right) return
let i = left, j = right;
let pivot = arr[i]
while(i<j){
while(i<j && arr[j]>=pivot) j--
if(i<j){
arr[i]=arr[j]
i++
}
while (i < j && arr[i] < pivot) i++
if(i<j){
arr[j]=arr[i]
j--
}
}
arr[i]=pivot
quickSort(arr,left,i-1)
quickSort(arr,i+1,right)
}
冒泡排序
function bubbleSort(arr){
for(let i=0;i<arr.length-1;i++){
for(let j=0;j<arr.length-1-i;j++){
if(arr[j]>arr[j+1]){
let tmp=arr[j+1]
arr[j+1]=arr[j]
arr[j]=tmp
}
}
}
}
插入排序
function insertSort(arr) {
for (let i = 1; i < arr.length; i++) {
let j = i - 1
const tmp = arr[i]
while (j >= 0 && arr[j] > tmp) {
arr[j + 1] = arr[j]// 移动
j--
}
// 放入合适位置
arr[j + 1] = tmp
}
return arr
}
function insertSort(arr){
for(let i=0;i<arr.length-1;i++){
for(let j=i+1;j>0;j--){
if(arr[j]<arr[j-1]){
let tmp=arr[j-1]
arr[j-1]=arr[j]
arr[j]=tmp
}else{
break
}
}
}
}
选择排序
function selectSort(arr) {
for(let i=0;i<arr.length;i++){
let minIndex=i;
for(let j=i+1;j<arr.length;j++){
if(arr[j]<arr[minIndex]) minIndex=j
}
let tmp=arr[i]
arr[i]=arr[minIndex]
arr[minIndex]=tmp
}
}
希尔排序
堆排序
其他
返回两数的最大公约数
const gcd = (a, b) => {
if (b === 0) {
return a;
}
return gcd(b, a % b);
}
查找缺失的数📎missingNumber.js
计算圆周率📎pi.js
下划线驼峰互转📎camel.js
数组转对象📎array2Object.js