手写js函数集合(一)

最近整理学习了一些js的手写实现,本着分享和复习的心态,给大家分析并分享以下,然后代码也都上传GitHub了 地址:github.com/dizao006/--... 话不多说,先来第一部分

一、原型链

要想手画出来原型,首先的画出来一个小原型

根据这张图科研看出来,每一个函数都可以通过new方法创建出一个实例。函数本身则有一个显示原型,实例本身又会指向函数的显示原型,也就是说,函数new出来的实例的隐式原型指向与函数本身的显示原型指向是一直的 而函数的原型身上有一个方法constructor方法,它指向函数本身,于是一个基础班的原型图就出现了,后续所有的原型图都以此为基础
那么函数原型怎么来的呢?在js中,函数是对象,对象也是函数,所以存在一个Object创建的实例,于是在第一个的基础上第二个原型图就出现了

刚刚也提到,函数是对象,对象也是函数,那么object是否也是某个函数的实例呢?函数又是怎么来的呢,那么就引出了最终的原型链

我们知道,函数又可以携程new Function的形式,所以所有的函数都可以使用这样的方式来写,所以的函数都是Function的实例,而在js中Fcuntion的显示原型和隐士原型都是特定的指向function原型而new出来的函数也有一个隐士原型,指向function原型,此时下方的三角形成闭环而object他的隐式原型也指向function原型,因为对象也是函数,最后function隐士原型又指向object原型。而object原型指向为空 最后完整的原型图

二、手写数组扁平化

js 复制代码
针对数组扁平化我相信大家一定不陌生,就是把多维数组展开形成一维数组,下面介绍两种方式
**1 flat方法**
在es6以后出现了Array.prototype.flat()方法,用来处理数组扁平化的,可以传入一个参数表示展开几层,不传只会默认展开1层
let arr = [1, 2, [2, 3, 4, [2, 1], 2, [2, 3]]]

 //flat 方法
 let a=arr.flat()
 //[ 1, 2, 2, 3, 4, [ 2, 1 ], 2, [ 2, 3 ] ]
 let s = arr.flat(2)
 console.log(s)
 //[
  1, 2, 2, 3, 4,
  2, 1, 2, 2, 3
]

//reduce实现flat函数
//reduce就是一个累加器函数,会返回新的数组,在这里可以通过这样的方式进行扁平化
function Myflat(arr) {
    return arr.reduce((pre, cur) => {
        if (Array.isArray(cur)) {
                //如果第二个数还是数组的话,那么使用apply进行递归将递归后的数加入到pre中
            pre.push.apply(pre, Myflat(cur))
        } else {
        //如果不是数组则直接加入到pre中
            pre.push(cur)
        }
        return pre
    }, [])
}
console.log(Myflat(arr));
//[
  1, 2, 2, 3, 4,
  2, 1, 2, 2, 3
]

三、手写group by方法

兼容问题

js 复制代码
Object.groupby()方法,可以根据某一对象的属性进行分类处理
groupby方法传入两个参数,一个是数组对象,一个是函数返回的要根据谁进行分类
const inventory = [{
    name: "芦笋",
    type: "蔬菜",
    quantity: 5,
    pice: 200
  },
  {
    name: "香蕉",
    type: "水果",
    quantity: 0,
    pice: 100
  },
  {
    name: "山羊",
    type: "肉",
    quantity: 23,
    pice: 200
  },
  {
    name: "樱桃",
    type: "水果",
    quantity: 5,
    pice: 300
  },
  {
    name: "鱼",
    type: "肉",
    quantity: 22,
    pice: 500
  },
];

let result = Object.groupBy(inventory, (e) => e.type)
console.log(result);
js 复制代码
接下来是手写该方法
还是通过reduce方法,reduce会返回一个新的数组,groupby传入的第二个参数是一个函数,拿到函数的返回值就是要根据谁进行分组
function groupBy(array, keyFn) {
  return array.reduce((acc, item) => {
    const key = keyFn(item);//分组的key
    if (!acc[key]) {
    //如果对象里不存在这个类别则创建一个并赋值为空数组
      acc[key] = [];
    }
    //将对应类别的数据加入到里面
    acc[key].push(item);
    return acc;
  }, {});//效果是一样的
}

下面还有一个简化版的对象分类方法
function gb(obj, gbroup) {
//传入数据和分组的类别
// let result = {}
// for (let i = 0; i < obj.length; i++) {
//   let s = obj[i]
//   let fen = s[gbroup] //拿到对应分类的数据作为分类的key
//   if (result[fen]) {
      //如果存在对应的key值,则push
//        result[fen].push(obj[i])
//   } else {
//如果不存在则把值放入数组添加到对象里
//        result[fen] = [obj[i]]
//   }
// }
// return result
// }
{
  '100': [ { name: '香蕉', type: '水果', quantity: 0, pice: 100 } ],
  '200': [
    { name: '芦笋', type: '蔬菜', quantity: 5, pice: 200 },
    { name: '山羊', type: '肉', quantity: 23, pice: 200 }
  ],
  '300': [ { name: '樱桃', type: '水果', quantity: 5, pice: 300 } ],
  '500': [ { name: '鱼', type: '肉', quantity: 22, pice: 500 } ]
}

四、函数防抖

js 复制代码
大家更不陌生了,防抖函数,该函数会返回一个函数,返回的函数就是经过防抖处理的,同时使用了apply,防止传入的参数丢失
function devounce2(fn, time = 1000) {
  let timer
  return function (...arges) {
    clearInterval(timer)
    timer = setTimeout(() => {
      fn.apply(this, arges)
    }, time)
  }
}

五、函数节流

js 复制代码
传统的函数节流存在两种方式
最常见的,但是无法立即执行一次
function throttle(callback, time = 100) {
    let timer //不会立即执行
    return function () {
        if (timer) {
            return //这里是与防抖的区别,如果已经存在了就不再执行了,而是相隔固定的秒数固定执行
        }
        let arg = arguments
        timer = setTimeout(() => {
            callback.apply(this, arg)
            timer = null
        }, time);
    } 
}
第二种 时间戳的方式,该方法会立即执行一次。原因在于首次t为空,所以会立即执行一次回调函数,通过判断当前时间与指定的间隔时间的差值来判断
function throttle2(callback, time = 100) {
    let t //会立即执行一次
    return function () {
        if (!t || Date.now() - t >= time) {
            callback.apply(null, arguments)
            t = Date.now()
        }
    }
}
第三种,二者的结合允许自定义是否首次执行
function throttle3(callback, time = 100, immediate) {
    //整合版,允许自定义控制是否立即执行
    if (immediate === undefined) {
    //默认首次要执行
        immediate = true
    }
    if (immediate) {
        let t;
        return function () {
            if (!t || Date.now() - t >= time) {
                callback.apply(null, arguments)
                t = Date.now()
            }
        }
    } else {
        let timer;
        return function () {
            if (timer) {
                return
            }
            let arg = arguments
            timer = setTimeout(() => {
                callback.apply(this, arg)
                timer = null
            }, time);
        }
    }

}

六、手写arr[-1]

js 复制代码
大家都知道,arr[-1]会默认取数组的最后一项,那么来看看他是如何实现的吧
Proxy代理大家肯定不陌生,实现这个的原理就是使用代理,通过代理来实现再读取的时候会触发代理,逻辑在这里处理
let arr = [1, 2, 3, 4, 5]
const proxyAry = (arr) => {
    const len = arr.length
    return new Proxy(arr, {
        get(target, key) {
            key = +key
            if (key < 0) {
                key += len
            }
            return target[key]
        }
    })
}
let s = proxyAry(arr)
console.log(s[-2]);

本次分析就到这里啦,感兴趣的可以取我的GitHub取源码:

地址:github.com/dizao006/--...

相关推荐
tt55555555555521 分钟前
每日一题——小根堆实现堆排序算法
c语言·数据结构·算法·面试·排序算法·八股文
解道Jdon1 小时前
杨立昆退休?中国Deepseek超Llama 4触发Meta
javascript·reactjs
村口老王4 小时前
鸿蒙开发——应用程序包及模块化设计
android·前端·harmonyos
不做超级小白4 小时前
JavaScript反爬技术解析与应对
开发语言·javascript·ecmascript
engchina5 小时前
使用Express.js和SQLite3构建简单TODO应用的后端API
javascript·sqlite·express
fly spider6 小时前
每日 Java 面试题分享【第 20 天】
java·开发语言·面试·io
轻口味6 小时前
Vue.js `v-memo` 性能优化技巧
前端·vue.js·性能优化
prince_zxill6 小时前
Array.prototype 方法在复杂数据处理中的应用
前端·javascript·原型模式
GISer_Jing6 小时前
React基础知识回顾详解
前端·react.js·前端框架
键.6 小时前
react-bn-面试
javascript·react.js·ecmascript