手撕js中常见方法

这篇具有很好参考价值的文章主要介绍了手撕js中常见方法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

array.fill

Array.prototype.fill2 = function (value, start, end) {
  const length = this.length; // 获取数组的长度

  start = start >> 0; // 将start转换为整数
  // 如果end参数未填写,则默认为数组的长度,否则将end转换为整数
  end = typeof end === 'undefined' ? length : end >> 0;
  // 将start限制在合法范围内,最小值为0,最大值为数组的长度
  start = start >= 0 ? Math.min(start, length) : Math.max(start + length, 0);
  // 将end限制在合法范围内,最小值为0,最大值为数组的长度
  end = end >= 0 ? Math.min(end, length) : Math.max(end + length, 0);
  // 使用指定的value填充从start到end范围内的数组索引
  while (start < end) {
    this[start] = value;
    start++;
  }
  // 返回被修改后的数组
  return this;
}

这段代码实现了一个自定义的fill2方法,用于在数组中指定的范围内填充指定的值。它接受三个参数:value表示要填充的值,start表示填充的起始索引,end表示填充的结束索引(不包含在内)。

在代码中,首先获取了数组的长度。然后对start和end参数进行处理,将它们转换为整数,并进行范围限制,确保它们在合法的范围内。接下来,使用一个循环从start索引开始,逐个将数组的元素设置为指定的value值,直到达到end索引为止。最后,返回被修改后的数组。

通过使用这个自定义的fill2方法,我们可以在数组中指定的范围内快速填充指定的值。 

array.map

Array.prototype.myMap = function (callbackFn, thisArg) {
  if (this == "undefined" || this == "null") {
    throw new TypeError("can not read property 'map' of undefined or null");
  }
  if (typeof callbackFn !== "function") {
    throw `${callbackFn} is not a function`;
  }
  let O = Object(this); // 将当前数组对象转换为对象类型
  let T = thisArg; // 设置回调函数的this值
  let len = O.length >>> 0; // 获取数组的长度
  let A = new Array(len); // 创建一个新的数组,用于存储映射后的值
  for (let k = 0; k < len; k++) {
    for (k in O) {
      let KValue = O[k]; // 获取当前索引的值
      let mapValue = callbackFn.call(T, KValue, k, O); // 调用回调函数进行映射操作
      A[k] = mapValue; // 将映射后的值存储到新数组中
    }
  }
  return A; // 返回映射后的新数组
}

let arr = [1, 2, 3, 4];
let arr2 = arr.myMap(function (currentValue, index, Array) {
  console.log(currentValue, index, Array);
  return currentValue + 1;
});
console.log(arr2);
    Array.prototype.myMap = function (callbackFn, thisArg) {
        if (this == "undefined" || this == "null") {
            throw new TypeError("can not read property 'map' of undefined or null")
        }
        if (typeof callbackFn !== "function") {
            throw `${callbackFn} is not a function`
        }
        let length = Object(this).length >>> 0
        let newArrray = []
        let i = 0
        while (i < length) {
            if (i in this) {
                //2. call修改了函数callbackFn的this指向,指向thisArg,后面的this还是指向的 arr,作为参数传给函数
                newArrray.push(callbackFn.call(thisArg, this[i],i,this))
            }
            i++
        }
        return newArrray
    }

    let arr = [1,2,3,4]
    // 1.绑定实例:用类实例对象去调用成员方法,此时this的指向为调用的实例对象  arr
    let arr2 = arr.myMap(function(currentValue,index,Array){
        // 3.此时的参数 currentValue,index,Array 对应2.传入的参数:this[i],i,this
        // 此时this为callbackFn的指向  this.Args  也就是 {message:"🐟"}
        console.log(currentValue,index,Array,this);
        return ++currentValue
    },{message:"🐟"})
    console.log(arr2);

节流函数

    function myThrottle(myFn,myDelay){
        let initState = true
        return function(...args){
            if(!initState) return
            initState = false
            setTimeout(() => {
                myFn.apply(this,args)
                initState = true
            }, myDelay);
        }
    }

    function mytest(arguments){
        console.log('test'+ arguments);  //testppp
    }
    const oneTest = myThrottle(mytest,500)
    oneTest('ppp')

防抖函数

    function debounce(fn,delay){
        var initWaitTime = null
        return function(...args){
            clearTimeout(initWaitTime)
            initWaitTime = setTimeout(() => {
                fn.apply(this,args)
            },delay)
        }
    }

    function testDebounce(){
        console.log('防抖');
    }
    const test4 = debounce(testDebounce,1000)
    console.log(test4);
    test4()
    test4()
    test4()

异步并发调度器Scheduler

    class Scheduler {
        constructor(max) {
            this.max = max
            this.count = 0
            this.queue = []
        }
        add(p) {
            this.queue.push(p)
            this.start()
        }
        start() {
            if (this.count >= this.max || !this.queue.length) return
            this.count++
            this.queue.shift()().finally(() => {
                this.count--
                this.start()
            })
        }
    }

    // 延迟函数
    const sleep = time => new Promise(resolve => setTimeout(resolve, time));

    // 同时进行的任务最多2个
    const scheduler = new Scheduler(2);

    // 添加异步任务
    // time: 任务执行的时间
    // val: 参数
    const addTask = (time, val) => {
        scheduler.add(() => {
            return sleep(time).then(() => console.log(val));
        });
    };

    addTask(1000, '1');
    addTask(500, '2');
    addTask(300, '3');
    addTask(400, '4');
// 2
// 3
// 1
// 4
class Scheduler {
  constructor(maxNum) {
    this.maxNum = maxNum; // 最大同时执行任务的数量
    this.count = 0; // 当前正在执行的任务数量
    this.taskList = []; // 任务列表,用于存储待执行的任务
  }

  addTask(time, val) {
    this.taskList.push([time, val]); // 将任务添加到任务列表中
  }

  start() {
    if (!this.taskList.length) return; // 如果任务列表为空,则直接返回
    if (this.count < this.maxNum) { // 如果当前正在执行的任务数量小于最大值
      const [time, val] = this.taskList.shift(); // 从任务列表中取出一个任务
      this.count++; // 增加正在执行的任务数量
      setTimeout(() => { // 使用setTimeout延迟执行任务
        console.log(val); // 打印任务的值
        this.count--; // 减少正在执行的任务数量
        this.start(); // 继续执行下一个任务
      }, time * 1000); // 将时间转换为毫秒,并设置延迟执行的时间
      this.start(); // 继续执行下一个任务
    }
  }
}

深拷贝函数:文章来源地址https://www.toymoban.com/news/detail-709056.html

    function deepClone(target, hashMap = new WeakMap()) {


        // 基本数据类型,直接返回
        if (typeof target !== "object" || target == null) {
            /* 
            函数,则调用函数并返回结果(虽然这里是同一个存储空间
            但是如果修改函数时,相当于重写函数,会自动分配堆内存存放新函数,也就是不会改变原函数)
            */
            if (target instanceof Function) return target.call(this, ...arguments);
            return target;
        }

        // 日期对象,则创建一个新的日期对象并返回
        if (target instanceof Date) return new Date(target);

        // 正则表达式对象,则创建一个新的正则表达式对象并返回
        if (target instanceof RegExp) return new RegExp(target);

        // 创建一个与目标对象构造函数相同的新对象
        let res = new target.constructor();

        // 如果哈希表中已经存在目标对象,则直接返回对应的新对象
        if (hashMap.get(target)) return hashMap.get(target);

        // 将新对象和目标对象存入哈希表中
        hashMap.set(res, target);

        // 遍历目标对象的属性
        for (let key in target) {
            // 递归调用深拷贝函数,复制目标对象的属性值,并赋值给新对象的对应属性
            res[key] = deepClone(deepClone(target[key], hashMap));
        }

        // 返回新对象
        return res;
    }

到了这里,关于手撕js中常见方法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包