JavaScript 手写代码 第三期

news2025/1/16 3:34:32

文章目录

  • 1. 为什么要手写代码?
  • 2. 手写代码
    • 2.1 函数柯里化
      • 2.1.1 基本使用
      • 2.1.2 手写实现
    • 2.2 sleep函数
      • 2.2.1 简单使用
      • 2.2.2 手写实现
    • 2.3 Object.assign() 方法
      • 2.3.1 基本使用
      • 2.3.2 具体示例
      • 2.3.3 具体思路
      • 2.3.4 具体实现

1. 为什么要手写代码?

我们在日常开发过程中,往往都是取出来直接用,从来不思考代码的底层实现逻辑,但当我开始研究一些底层的东西的时候,才开始理解了JavaScript每个方法和函数的底层实现思路,我认为这可以很好的提高我们的代码水平和逻辑思维。

2. 手写代码

2.1 函数柯里化

2.1.1 基本使用

函数柯里化指的是一种将多个参数的一个函数转换成一系列使用一个参数的函数的技术

            // 正常使用
            function sum(a, b, c) {
                return a + b + c;
            }
            console.log(sum(1, 2, 3));
            
            // 函数柯里化实现上面的操作
            function sum1(a) {
                return function (b) {
                    return function (c) {
                        return a + b + c;
                    };
                };
            }
            console.log(sum1(1)(2)(3));

函数柯里化其实就是利用了闭包,大家想了解闭包可以转到我的博文 闭包

2.1.2 手写实现

            function curry(fn, ...args) {
                let length = fn.length;
                args = args || [];
                return function () {
                    let subArgs = args.slice(0);
                    // 合并所有的参数
                    subArgs = [...subArgs, ...arguments];
                    // 判断参数的长度是否已经满足函数所需要的长度
                    if (subArgs.length >= length) {
                        return fn.apply(this, subArgs);
                    } else {
                        // 返回柯里化化函数,等待继续传递参数
                        return curry.call(this, fn, ...subArgs);
                    }
                };
            }

可以进行测试
传入方法sum

          function sum(a, b, c) {
                return a + b + c;
          }

发现可以正常打印出结果,成功实现 函数柯里化

            let add = curry(sum);
            console.log(add(1)(1, 2, 3)); // 6
            console.log(add(1)(2)(3)); // 6
            console.log(add(1, 2, 3));
            console.log(add()(1, 2, 3));

函数柯里化的简单实现方法
一行代码搞定

function curry1(fn, ...args) {
	return fn.length <= args.length ? fn(...args) : curry1.bind(null, fn, ...args);
}

主要利用了bind在改变this指向的同时,也可以传递参数
案例如下就可以理解了

            function fn(a, b, c) {
                console.log(a, b, c);
            }
            let fn1 = fn.bind(null, 1, 2);
            fn1(3); // 1,2,3

正常打印出了 1,2,3

2.2 sleep函数

2.2.1 简单使用

sleep是一种函数,作用是延时,程序暂停若干时间,在执行时要抛出一个中断异常,必须对其进行捕获并处理才可以使用这个函数。
js 中是没有这个函数的,需要我们手写实现使用

2.2.2 手写实现

方法一 利用了promise异步处理和定时器

            function sleep(delay) {
                return new Promise((resolve) => {
                    setTimeout(resolve, delay);
                });
            }
            sleep(1000).then(() => {
                console.log('111');
            });

一秒后打印出111
方法二 利用了定时器setTimeout和回调函数写法

            function sleep(delay, callback) {
                setTimeout(callback, delay);
            }
            sleep(1000, () => {
                console.log(1000);
            });

方法三 利用了Date函数时间戳写法。精确计算。

            function sleep(delay) {
                let startTime = new Date().getTime();
                while (new Date().getTime() - startTime < delay) {
                    // 只要还没有到特定事件,就一直在循环内,
                    // 到了规定延迟后,跳出循环,指向下面的方法
                    continue;
                }
            }
            console.log('1111');
            sleep(5000);
            console.log('2222');

2.3 Object.assign() 方法

2.3.1 基本使用

Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。

Object.assign(target, …sources) 

第一个参数target: 即目标对象,目标对象的值会发生改变。
第二个参数souce:源对象(可多个)源对象不会发生改变

2.3.2 具体示例

            let obj = { name: 'zs' };
            let obj1 = { name: 'lisi' };
            let obj2 = { age: 20 };
            let newObj = Object.assign(obj, obj1, obj2);
            console.log(newObj); // {name: 'lisi', age: 20}
            console.log(obj);  // {name: 'lisi', age: 20}
            console.log(obj1); // {name: 'lisi'}
            console.log(obj2); // {age: 20}

细心的大家可以发现,目标对象里面的值被源对象里面的值覆盖了。

注意:如果目标对象中的属性具有相同的键,则属性将被源对象中的属性覆盖。后面的源对象的属性将类似地覆盖前面的源对象的属性

2.3.3 具体思路

大家通过上面的示例不能发现 Objec.assign() 到底干了什么,通过 遍历 sources 里面的对象属性,依次添加到 目标对象上,遇到相同的属性,目标对象的属性值直接被覆盖,最后返回目标对象合并后的值,并且 目标对象的值 也会被改变。

2.3.4 具体实现

小知识: Object.assign()方法在Object 对象上,并不是在它的原型对象上,myAssign()加粗,表示是我们新增的方法,而 assign 是自带的方法
在这里插入图片描述

            Object.myAssign = function (target, ...sources) {
                if (target == null) {
                    throw new TypeError('Cannot convert undefind or null to object');
                }
                sources.forEach((source) => {
                    if (source != null) {
                        // 遍历每一个对象里面的属性,会遍历到原型上面的属性
                        for (let key in source) {
                            // 判断该属性是不是对象自身的属性
                            if (source.hasOwnProperty(key)) {
                                target[key] = source[key];
                            }
                        }
                    }
                });
                // 将合并后的对象返回即可
                return target;
            };

测试上面实现的代码

            let newObj = Object.myAssign(obj, obj1, obj2);
            console.log(newObj); // {name: 'lisi', age: 20}
            console.log(obj); // {name: 'lisi', age: 20}
            console.log(obj1); // {name: 'lisi'}
            console.log(obj2); // {age: 20}

打印输出结果完成,成功实现。

欢迎大家在讨论学习,感谢大家支持

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

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

相关文章

ChatGPT底层架构Transformer技术及源码实现(三)

ChatGPT底层架构Transformer技术及源码实现(三) 贝叶斯Bayesian Transformer数学推导论证过程全生命周期详解及底层神经网络物理机制剖析 Gavin大咖微信:NLP_Matrix_Space 从数学的角度来讲,线性转换 其中函数g联合了所有头的操作结果,每个头的产生是采用一个f_att的…

RedHat红帽认证---RHCE

&#x1f497;wei_shuo的个人主页 &#x1f4ab;wei_shuo的学习社区 &#x1f310;Hello World &#xff01; RHCE 1.安装和配置 Ansible 安装和配置 Ansible按照下方所述&#xff0c;在控制节点 control 上安装和配置 Ansible&#xff1a;安装所需的软件包创建名为 /home/gre…

认识区块链

文章目录 前言从交易说起线下交易&线上交易存在的隐患线上交易隐患引发的思考 货币发展史解决线上交易存在的隐患比特币的诞生比特币价值的产生 比特币&区块链 前言 我想大多数的 IT 人&#xff0c;即便不是 IT 人&#xff0c;或多说少都听说过“比特币”“区块链”这…

InceptionNext:当Inception遇到ConvNeXt

摘要 https://arxiv.org/pdf/2303.16900.pdf 受 Vision Transformer 长距离依赖关系建模能力的启发&#xff0c;大核卷积最近被广泛研究和采用&#xff0c;以扩大感受野和提高模型性能&#xff0c;如采用77深度卷积的杰出工作connext。虽然这种深度算子只消耗少量的flop&…

初识mysql数据库之数据库介绍

目录 一、什么是数据库 1. 数据库的概念 2. 为什么要有数据库 3. 数据库样例 二、 主流数据库 三、服务器、数据库和表之间的关系 四、mysql存储架构 五、sql语句分类 一、什么是数据库 1. 数据库的概念 如果大家现在已经安装好了mysql&#xff0c;想必大家应该也都知…

数字逻辑与模拟电子技术-部分知识点(1)——模电部分-半导体二极管,半导体的基础知识、本征半导体、杂质半导体、PN结的形成、PN结的特性、二极管的伏安特性

目录 半导体二极管 半导体的基础知识 本征半导体(经过加工处理) 杂质半导体 PN结的形成 PN结的特性 二极管的伏安特性 半导体二极管 半导体的基础知识 半导体器件的材料主要是硅&#xff08;Si&#xff09;、锗&#xff08;Ge&#xff09;和砷化镓&#xff08;GaAs&…

Airtest框架和Poco框架常见问题

Airtest 报告可以导出发给别人看吗 Airtest的报告是可以打包发给别人看的。 ① 想要导出报告发给别人观看&#xff0c;我们需要生成报告的命令中传入 --export 参数&#xff0c;这样就可以将 包含静态资源文件和图片文件的报告 导出到一个指定的文件夹内&#xff0c;之后直接…

Qt绘图(线条、椭圆、矩形、图片滚动)

widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent nullptr);~Widget();//绘图事件void paintEvent(QPaintE…

XML系列篇之dtd约束

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于xml的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一.XML 是什么 &#x1f4a1;辉辉小贴士&a…

STM32时钟系统

时钟 时钟是具有周期性的脉冲信号&#xff0c;最常用的是占空比50%的方波。 时钟是单片机的脉搏。 时钟树 HSE&#xff1a;高速外部振荡器&#xff0c;4~16MHz&#xff0c;&#xff08;晶体&#xff0c;陶瓷&#xff09;LSE&#xff1a;低速外部振荡器&#xff0c;32.768KHz…

ADC0808/ADC0809引脚图及功能和工作原理介绍

ADC0808芯片有28条引脚&#xff0c;采用双列直插式封装。如图所示&#xff1a; . . . 各引脚功能如下&#xff1a; 1-5和26-28&#xff08;IN0-IN7&#xff09;&#xff1a;8路模拟量输入端。 8、14、15和17-21&#xff1a;8位数字量输出端。 22&#xff08;ALE&#xff09…

深度学习代码环境配置(编译器, git, anaconda)

内容 编译器 gcc&#xff1a;GNU编译器套装C builderMicrosoft Visual C&#xff08;MSVC&#xff09;&#xff1a;微软的VC编译器MinGW&#xff08;Minimalist GNU on Windows&#xff09;&#xff1a;可自由使用和自由发布的Windows特定头文件和使用GNU工具集导入库的集合&…

【设计模式】面向对象的设计原则

(一) UML 和面向对象设计原则 1. 一种某唱片播放器不仅可以播放唱片&#xff0c;而且可以连接计算机并把计算机中的歌曲刻录到 唱片上&#xff08;同步歌曲&#xff09;。连接计算机的过程中还可自动完成充电。 关于唱片&#xff0c;还有如下描述信息&#xff1a; &#xf…

ChatGPT底层架构Transformer技术及源码实现(一)

ChatGPT底层架构Transformer技术及源码实现 Language Model底层的数学原理之最大似然估计MLE及最大后验概率MAP内部机制详解 Gavin大咖微信:NLP_Matrix_Space 传统人工智能算法的真相(The Truth Under Traditional AI Algorithms),传统人工智能算法是相对于贝叶斯(Bayesia…

【软件设计师暴击考点】程序设计语言-高频考点暴击系列

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;软件…

碳中和城市建筑能源系统(4):储能篇(龙惟定)2022

碳中和城市建筑能源系统(4):储能篇 摘要 本文是碳中和城市建筑能源系统系列文章的第四篇。在碳中和语境下&#xff0c;无论是增加可再生能源应用的渗透率&#xff0c;还是平抑负荷、提高电网的灵活性&#xff0c;都离不开储能。本文介绍了当今储能技术的主要类型&#xff0c;…

【新星计划·2023】Centos 7安装教程(一步一图)

作者&#xff1a;Insist-- 个人主页&#xff1a;insist--个人主页 作者会持续更新网络知识和python基础知识&#xff0c;期待你的关注 目录 一、下载VMware 二、下载镜像的方式 三、安装Linux ’前言 本文将讲解下载VMware和下载镜像的方式&#xff0c;以及安装centos 7的教…

webpack编译打包从入门到放弃

写在前面的话&#xff1a;推荐学习vite。当然&#xff0c;我更推荐你直接上手体验webpack_demo与vite_demo 看看他们的编译、打包、热更新速度等差距。你也可以直接通过vite开发lib库&#xff0c;一句话就是比webpack快&#xff0c;它有的vite都有&#xff0c;并且更好&#x…

NCI-NFCEE

10.5 NFCEE 状态 NFCC 使用此控制消息向 DH 通知启用的 NFCEE 状态的变化。 NFCC 发送 NFCEE_STATUS_NTF 来报告启用的 NFCEE 状态的变化。 对于任何禁用或无响应的 NFCEE&#xff0c;NFCC 不应发送 NFCEE_STATUS_NTF。 当启用 NFCEE 并且 NFCC 检测到与该 NFCEE 通信时存在不…

C++布隆过滤器

目录 布隆过滤器介绍实现哈希函数布隆过滤器删除 小结使用——题目 布隆过滤器 介绍 在许多场景下&#xff0c;如设置昵称时&#xff0c;往往要求唯一性。这时就需要高效判断该昵称是否被使用过。 使用红黑树的kv模型或者哈希表来组织昵称集合&#xff0c;可以&#xff0c;但缺…