手写promise、call、apply、debounce、throttle 等

1、promise

     1.1  实现resolve和reject
class MyPromise {
    // 构造方法
    constructor(executor) {

        // 初始化值
        this.initValue()
        // 初始化this指向
        this.initBind()
              try {
            // 执行传进来的函数
            executor(this.resolve, this.reject)
        } catch (e) {
            // 捕捉到错误直接执行reject
            this.reject(e)
        }
    }

    initBind() {
        // 初始化this
        this.resolve = this.resolve.bind(this)
        this.reject = this.reject.bind(this)
    }

    initValue() {
        // 初始化值
        this.PromiseResult = null // 终值
        this.PromiseState = 'pending' // 状态
    }

    resolve(value) {
        // state是不可变的
              if (this.PromiseState !== 'pending') return
        // 如果执行resolve,状态变为fulfilled
        this.PromiseState = 'fulfilled'
        // 终值为传进来的值
        this.PromiseResult = value
    }

    reject(reason) {
        // state是不可变的
        if (this.PromiseState !== 'pending') return
        // 如果执行reject,状态变为rejected
        this.PromiseState = 'rejected'
        // 终值为传进来的reason
        this.PromiseResult = reason
    }
}

测试代码:

const test3 = new MyPromise((resolve, reject) => {
    throw('fail')
})
console.log(test3) // MyPromise { PromiseState: 'rejected', PromiseResult: 'fail' }

 

  1.2  实现then方法
    then(onFulfilled, onRejected) {
        // 接收两个回调 onFulfilled, onRejected
        
        // 参数校验,确保一定是函数
        onFulfilled = typeof onFulfilled === 'function' ?
                      onFulfilled : val => val
        onRejected = typeof onRejected === 'function' ?
                     onRejected : reason => { throw reason }

        if (this.PromiseState === 'fulfilled') {
            // 如果当前为成功状态,执行第一个回调
            onFulfilled(this.PromiseResult)
        } else if (this.PromiseState === 'rejected') {
            // 如果当前为失败状态,执行第二哥回调
            onRejected(this.PromiseResult)
        }

    }

 测试代码:

// 输出 ”success“
const test = new MyPromise((resolve, reject) => {
    resolve('success')
}).then(res => console.log(res), err => console.log(err))

 

2、call

  2.1  实现思路

call() :在使用一个指定的 this 值和若干个指定的参数值的前提下调用某个函数或方法。

 

let foo = {
    value: 1
};

function bar() {
    console.log(this.value);
}

bar.call(foo); // 1

上述调用注意两点:
1. call 改变了 this 的指向,指向到 foo;
2. bar 函数执行了;


上述方式等同于:
let foo = {
    value: 1,
    bar: function() {
        console.log(this.value)
    }
};

foo.bar(); // 1

这个时候 this 就指向了 foo,但是这样却给 foo 对象本身添加了一个属性,所以们用 delete 再删除它即可。

所以我们模拟的步骤可以分为:

  1. 将函数设为对象的属性;

  2. 执行该函数;

  3. 删除该函数;

// 第一步
// fn 是对象的属性名,反正最后也要删除它,所以起什么都可以。
foo.fn = bar
// 第二步
foo.fn()
// 第三步
delete foo.fn
     2.2  实现

     2.2.1   指定this

     2.2.2   指定参数

     2.2.3   this 参数可以传 null,当为 null 的时候,视为指向 window

// 第三版
Function.prototype.call2 = function (context) {
    var context = context || window;
    context.fn = this;

    let arg = [...arguments].slice(1)
    let result = context.fn(...arg)

    delete context.fn
    return result
}

// 测试一下
var value = 2;

var obj = {
    value: 1
}

function bar(name, age) {
    console.log(this.value);
    return {
        value: this.value,
        name: name,
        age: age
    }
}

bar.call2(null); // 2

console.log(bar.call2(obj, 'kevin', 18));
// 1
// Object {
//    value: 1,
//    name: 'kevin',
//    age: 18
// }

3、apply

      apply 的实现跟 call 类似,只是入参不一样,apply为数组

Function.prototype.apply = function (context, arr) {
    var context = Object(context) || window;
    context.fn = this;

    var result;
    if (!arr) {
        result = context.fn();
    }
    else {
        result = context.fn(...arr)
    }

    delete context.fn
    return result;
}

4、bind

5、debounce > 防抖

防抖: 如果在一定的时间内 (n) 频繁的触发,只会执行最后一次

      5.1  js实现
function debounce(func, ms) {
    let timeout;
    return function () {
        let context = this;
        let args = arguments;

        if (timeout) clearTimeout(timeout);
        
        timeout = setTimeout(() => {
            func.apply(context, args)
        }, ms);
    }
}
     5.1  hooks实现
import { useEffect, useRef } from 'react'

const useDebounce = (fn, ms = 30, deps = []) => {
    let timeout = useRef()
    useEffect(() => {
        if (timeout.current) clearTimeout(timeout.current)
        timeout.current = setTimeout(() => {
            fn()
        }, ms)
    }, deps)

    const cancel = () => {  // 防止内存泄露
        clearTimeout(timeout.current)
        timeout = null
    }
  
    return [cancel]
  }

export default useDebounce

// 实际使用
import { useDebounce } from 'hooks'
const Home = (props) => {
  const [a, setA] = useState(0)
  const [b, setB] = useState(0)
  
  const [cancel] = useDebounce(() => {
    setB(a)
  }, 2000, [a])

  const changeIpt = (e) => {
    setA(e.target.value)
  }
  return <div>
    <input type="text" onChange={changeIpt} />
    { b } { a }
  </div>
}

6、throttle  > 节流

节流:每一次触发的时候,会记录与首次触发的一个时间差,如果时间差大于传入的这个时间,则重新计时

      6.1  js实现
function throttle(func, ms) {
    let previous = 0;
    return function() {
        let now = Date.now();
        let context = this;
        let args = arguments;
        if (now - previous > ms) {
            func.apply(context, args);
            previous = now;
        }
    }
}
      6.2  hooks实现
mport { useEffect, useRef, useState } from 'react'

const useThrottle = (fn, ms = 30, deps = []) => {
    let previous = useRef(0)
    let [time, setTime] = useState(ms)
    useEffect(() => {
        let now = Date.now();
        if (now - previous.current > time) {
            fn();
            previous.current = now;
        }
    }, deps)

    const cancel = () => {
        setTime(0)
    }
  
    return [cancel]
  }

export default useThrottle

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/659166.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Gartner发布评估威胁情报计划有效性指南:评估威胁情报有效性的四个步骤

许多组织都在努力实施 TI 并评估其价值。安全和风险管理领导者必须使用优先情报要求来评估其 TI 计划的有效性&#xff0c;并根据其组织战略完善该计划。 主要发现 尽管许多组织已将威胁情报 (TI) 纳入其安全计划&#xff0c;但他们很难评估其性能、成熟度以及在相关产品和服务…

再次疾呼:一稿多投是作者的合法权利!

近日&#xff0c;有作者反应在收到拒稿邮件之后另投他刊&#xff0c;竟然被判定一稿多投。 出版社解释说现在大多数期刊都是使用投稿系统收稿&#xff0c;如果被退稿后马上又投稿其他期刊&#xff0c;由于时间距离太近&#xff0c;仍然会被系统判定为一稿多投的。核心期刊编辑…

深入探索C++继承机制:从概念到实践的全面指南

目录 继承的概念及定义 继承的概念 继承的定义 定义格式 继承方式和访问限定符 继承基类成员访问方式的变化 默认继承方式 基类和派生类对象赋值转换 继承中的作用域 派生类的默认成员函数 继承与友元 继承与静态成员 继承的方式 菱形虚拟继承 菱形虚拟继承原理 继承…

「盘点」JetBrains IDEs v2024.1新功能一览,更智能的开发体验!

JetBrains IDEs日前正式发布了v2024.1版本&#xff0c;此版本中最大的亮点就是带来了AI赋能的全行代码补全&#xff0c;同时在最新的IDEs中重做了终端、拥有更强大的代码编辑和导航功能、更智能的代码分析和提示、更优化的性能、更丰富的插件和集成等。总的来说&#xff0c;Jet…

淘宝API探秘:一键获取店铺所有商品的魔法之旅

在数字时代的今天&#xff0c;数据已经成为了商业世界中的魔法石。而对于淘宝店主或者那些想要深入探索淘宝数据的人来说&#xff0c;淘宝API就像是打开阿里巴巴宝藏库的钥匙。今天&#xff0c;我们就来一起探索如何使用淘宝API&#xff0c;特别是如何获取店铺所有商品的接口&a…

为WPF的Grid添加网格边框线

在WPF中使用Grid绘制表格的时候&#xff0c;如果元素较多、排列复杂的话&#xff0c;界面会看起来很糟糕&#xff0c;没有层次&#xff0c;这时用网格或边框线分割各元素&#xff08;标签或单元格&#xff09;将会是页面看起来整齐有条理。 默认没有边框线的如下图所示&#xf…

Java 循环嵌套深度揭秘:挑战极限与性能优化

哈喽&#xff0c;大家好&#xff0c;我是木头左&#xff01; 探索Java的调用栈极限 在Java中&#xff0c;方法调用是通过栈&#xff08;Stack&#xff09;这种数据结构来实现的。每当一个方法被调用时&#xff0c;一个新的栈帧&#xff08;Stack Frame&#xff09;会被创建并压…

React 中的 Fiber 架构

React Fiber 介绍 React Fiber 是 React 的一种重写和改进的核心算法&#xff0c;用于实现更细粒度的更新和高效的调度。它是 React 16 版本中的一个重要更新&#xff0c;使得 React 能够更好地处理复杂和高频的用户交互。以下是对 React Fiber 的详细介绍&#xff1a; 为什么…

便民社区信息小程序源码系统 功能强大 带生活电商+求职招聘功能 带完整的安装代码包以及搭建教程

系统概述 便民社区信息小程序源码系统是一款集多种功能于一身的综合性平台。它旨在为用户提供便捷的生活服务&#xff0c;满足社区居民的各种需求。无论是购物、求职还是获取社区信息&#xff0c;都能在这个平台上得到满足。该系统采用先进的技术架构&#xff0c;确保系统的稳…

【python 进阶】 绘图

1. 将多个柱状绘制在一个图中 import seaborn as sns import matplotlib.pyplot as plt import numpy as np import pandas as pd# 创建示例数据 categories [A, B, C, D, E] values1 np.random.randint(1, 10, sizelen(categories)) values2 np.random.randint(1, 10, siz…

揭秘!编写高质量代码的关键:码农必知的黄金法则!

文章目录 一、保持代码的简洁与清晰二、遵循良好的命名规范三、注重代码的可读性四、利用抽象与封装五、遵循SOLID原则六、关注代码性能七、确保代码安全性《码农修行&#xff1a;编写优雅代码的32条法则》编辑推荐内容简介目录前言/序言 在编程的世界里&#xff0c;每一位码农…

VSCode 报错 之 运行 js 文件报错 ReferenceError: document is not defined

1. 背景 持续学习ing 2. 遇到的问题 在VSCode 右键 code runner js 文件报错 ReferenceError: document is not defined eg&#xff1a; // 为每个按钮添加点击事件监听器 document.querySelectorAll(button).forEach(function (button) {button.addEventListener(click, f…

python基础-数据结构-leetcode刷题必看-heapq --- 堆队列算法

文章目录 堆的定义堆的主要操作堆的构建堆排序heapq模块heapq.heappush(heap, item)heapq.heappop(heap)heapq.heappushpop(heap, item)heapq.heapreplace(heap, item)heapq.merge(*iterables, keyNone, reverseFalse)heapq.nlargest(n, iterable, keyNone)heapq.nsmallest(n, …

赛氪网与武汉外语外事职业学院签署校企合作,共创职业教育新篇章

5月23日下午14:00&#xff0c;武汉外语外事职业学院在藏龙岛校区食堂三楼报告厅隆重举行了2024年职业教育活动周优秀校外实习基地表彰仪式。本次活动旨在表彰在职业教育领域作出突出贡献的校外实习基地&#xff0c;同时加强校企合作&#xff0c;共同推动职业教育的发展。作为重…

gitlab之docker-compose汉化离线安装

目录 概述离线资源docker-compose结束 概述 gitlab可以去 hub 上拉取最新版本&#xff0c;在此我选择汉化 gitlab &#xff0c;版本 11.x 离线资源 想自制离线安装镜像&#xff0c;请稳步参考 docker镜像的导入导出 &#xff0c;无兴趣的直接使用在此提供离线资源 百度网盘(链…

经典文献阅读之--RepViT-SAM(利用语义分割提高NDT地图压缩和描述能力的框架)

0. 简介 Segment Anything Model (SAM) 最近在各种计算机视觉任务上展现了令人瞩目的零样本迁移性能 。然而&#xff0c;其高昂的计算成本对于实际应用仍然具有挑战性。MobileSAM 提出通过使用蒸馏替换 SAM 中的重图像编码器&#xff0c;使用 TinyViT&#xff0c;从而显著降低了…

认识K8s集群的声明式资源管理方法

前言 Kubernetes 集群的声明式资源管理方法是当今云原生领域中的核心概念之一&#xff0c;使得容器化应用程序的部署和管理变得更加高效和可靠。本文将认识了解 Kubernetes 中声明式管理的相关理念、实际应用以及优势。 目录 一、管理方法介绍 1. 概述 2. 语法格式 2.1 管…

AI图书推荐:用ChatGPT和Python搭建AI应用来变现

《用ChatGPT和Python搭建AI应用来变现》&#xff08;Building AI Applications with ChatGPT API&#xff09;将ChatGPT API与Python结合使用&#xff0c;可以开启构建非凡AI应用的大门。通过利用这些API&#xff0c;你可以专注于应用逻辑和用户体验&#xff0c;而ChatGPT强大的…

适合学生党的蓝牙耳机有哪些?盘点四大性价比蓝牙耳机品牌

对于追求高品质音乐体验而又预算有限的学生党来说&#xff0c;一款性价比高的蓝牙耳机无疑是最佳选择&#xff0c;在众多品牌和型号中&#xff0c;如何挑选到既适合自己需求又价格亲民的蓝牙耳机&#xff0c;确实是一个值得思考的问题&#xff0c;作为一个蓝牙耳机大户&#xf…

台灯护眼是真的吗?警惕这六大问题!

在当今社会&#xff0c;随着电子设备的普及和长时间的用眼&#xff0c;大多数人面临着严重的视觉疲劳问题。长时间盯着屏幕或学习&#xff0c;眼睛需要不断调节焦距&#xff0c;导致眼睛肌肉疲劳&#xff0c;进而引发视力下降。这种现象在年轻一代甚至青少年中尤为普遍&#xf…