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

news2024/11/17 4:31:17

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.coloradmin.cn/o/1712553.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微调真的能让LLM学到新东西吗:引入新知识可能让模型产生更多的幻觉

大型语言模型(llm)是在巨大的文本语料库上训练的&#xff0c;在那里他们获得了大量的事实知识。这些知识嵌入到它们的参数中&#xff0c;然后可以在需要时使用。这些模型的知识在培训结束时被“具体化”。在预训练结束时&#xff0c;模型实际上停止学习。 对模型进行对齐或进行…

【NumPy】全面解析arange函数:高效创建数值范围数组

&#x1f9d1; 博主简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…

如何高效搜索?99%的人都不知道的搜索进阶小技巧

如何高效搜索任何你想要的信息&#xff1f; 比如怎么找第一手的行业研究报告&#xff1f; 在哪查高清无码的图片素材&#xff1f; 怎么搜最新的AI工具教程&#xff1f; 遇到以上问题你会怎么搜&#xff1f; 可能大部分人都是直接打开百度查关键词&#xff0c;虽然随便一搜…

2024年学浪课程下载工具

学浪下载工具我已经打包好了&#xff0c;有需要的自己下载一下 学浪下载器链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;1234 --来自百度网盘超级会员V10的分享 1.首先解压好我给大家准备好的压缩包 2.打开解压好的文件夹里面的N_m3u8D文件夹&#xff0c;然…

如何理解和使用 this 关键字

this 关键字是许多编程语言中的一个核心概念&#xff0c;在面向对象编程&#xff08;OOP&#xff09;中尤为重要。在JavaScript、Java、C、C#等语言中&#xff0c;this 扮演着至关重要的角色。理解 this 的意义和用法&#xff0c;对于编写清晰、有效的代码至关重要。 什么是th…

字符串操作:写一个方法,实现字符串的反转,如:输入abc,输出cba

import java.util.Scanner; public class Test_A15 {public static void main(String[] args){String strA"";System.out.println("请输入一串字符串:");Scanner scannernew Scanner(System.in);strAscanner.next();Test_A15 T15new Test_A15();String re…

JAVA系列:NIO

NIO学习 一、前言 先来看一下NIO的工作流程图&#xff1a; NIO三大核心组件&#xff0c;channel&#xff08;通道&#xff09;、Buffer&#xff08;缓冲区&#xff09;、selector&#xff08;选择器&#xff09;。NIO利用的是多路复用模型&#xff0c;一个线程处理多个IO的读…

新时代病毒侵染了全世界!自律的自我认知,无聊才是根本——早读(逆天打工人爬取热门微信文章解读)

刷视频的动作是什么&#xff1f; 引言Python 代码第一篇 【夜读】为什么要自律&#xff1f;这是我听过最走心的答案第二篇结尾 引言 文字阅读数量确实在缩减 虽然我觉得未来还是有一席之地 当下的人 普罗大众吧 你让他们看书 看文字 显然是不现实的 他们比起看书看文字 更喜欢…

光缆监测主要设备是什么?

光功率计&#xff08;OPM&#xff09;稳定光源&#xff1a; 当被测光照射到光检测器上即产生相应的光电流&#xff0c;主机部分的作用是把检测到的电信号放大和模/数变换后进入CPU,经CPU处理后的数字信号最后以光功率或相应的功率电平形式显示出来。 光时域反射仪&#xff08;…

GaN功率电子器件中体缺陷相关机制的建模仿真研究

在电力电子器件的外延生长和器件制备过程中&#xff0c;缺陷是不可避免的&#xff0c;大量的缺陷在一定程度上会牺牲器件的击穿电压、导通电阻等性能&#xff0c;同时影响器件的可靠性。近期&#xff0c;河北工业大学和广东工业大学联合开发了缺陷相关的仿真模型&#xff0c;深…

解决Springboot服务启动报错:“Reason: Failed to determine suitable jdbc url”

1、错误详情 *************************** APPLICATION FAILED TO START *************************** Description: Failed to configure a DataSource: url attribute is not specified and no embedded datasource could be configured. Reason: Failed to determine sui…

在全志H616核桃派开发板上配置SSH远程终端方法详解

熟悉指令用户可以对已经联网的核桃派进行局域网SSH远程终端控制&#xff0c;方便使用自己的PC对核桃派远程进行各种指令操作。 普通用户&#xff08;默认&#xff09; 账号&#xff1a;pi ; 密码&#xff1a;pi管理员账户 账号&#xff1a;root ; 密码&#xff1a;root 在这之…

Java基础-注解

注解本质是继承了Annotation接口的一个接口 首先&#xff0c;我们通过键值对的形式可以为注解属性赋值&#xff0c;像这样&#xff1a;Hello&#xff08;value “hello”&#xff09;。 接着&#xff0c;你用注解修饰某个元素&#xff0c;编译器将在编译期扫描每个类或者方…

1794 jsp蛋糕店管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 jsp 蛋糕店管理系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助采用了java设计&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统采用web模式&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&…

swagger-ui页面接口的入参出参与代码实体类不一致有差异、swagger请求实体与预期定义不符、swagger参数与实体中参数不一致原因分析

文章目录 一、问题背景二、问题原因及解决方法 一、问题背景 项目集成swagger之后&#xff0c;发现有个接口的请求跟接口对应不上&#xff0c;把其他接口的请求参数放到当前这个请求上了。 如下图&#xff1a;test1接口的请求参数是其他请求的&#xff0c;并不是test1接口的 …

【Qt】[001]-从入门到成神-前言

一、Qt是什么&#xff1f;[概念] Qt是一个跨平台的应用程序开发框架&#xff0c;简单来说&#xff0c;它是一套工具和库&#xff0c;帮助软件开发者编写可以在多种操作系统上运行的图形用户界面&#xff08;GUI&#xff09;应用程序。比如&#xff0c;你用Qt写了一个软件&#…

ChatGPT:轻松搞定论文润色,让语言更流畅

GPT从3.5一路升级到4.0&#xff0c;不仅在国外火得一塌糊涂&#xff0c;还悄悄地在我们论文润色的世界里掀起了一场革命。 首先&#xff0c;得承认&#xff0c;虽然这玩意儿是“洋货”&#xff0c;用起来可能得费点脑筋——注册个账号啦&#xff0c;买个会员啦之类的。但它对我…

充电宝哪家好用?西圣、倍思、小米充电宝哪个好?热门品牌实测

在如今充电宝市场中&#xff0c;充电宝已经深受大家的喜爱了&#xff0c;但是在市面上众多充电宝中&#xff0c;西圣、倍思、小米充电宝无疑是其中的佼佼者&#xff0c;那么&#xff0c;面对三款热门品牌的充电宝我们该如何选择呢&#xff1f;作为一个有着选购充电宝的老司机来…

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

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

香橙派OrangePi AIpro上手笔记——之USB摄像头目标检测方案测试(三)

整期笔记索引 香橙派OrangePi AIpro上手笔记——之USB摄像头目标检测方案测试&#xff08;一&#xff09; 香橙派OrangePi AIpro上手笔记——之USB摄像头目标检测方案测试&#xff08;二&#xff09; 香橙派OrangePi AIpro上手笔记——之USB摄像头目标检测方案测试&#xff08;…