JavaScript 手写代码 第三期

简介: JavaScript 手写代码 第三期

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}

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

目录
相关文章
|
5天前
|
资源调度 前端开发 JavaScript
Babel:JavaScript代码的编译利器
Babel:JavaScript代码的编译利器
|
5天前
|
JavaScript 前端开发 安全
抽象语法树(AST):理解JavaScript代码的抽象语法树
抽象语法树(AST):理解JavaScript代码的抽象语法树
|
6天前
|
JSON JavaScript 前端开发
JavaScript原生代码处理JSON的一些高频次方法合集
JavaScript原生代码处理JSON的一些高频次方法合集
|
6天前
|
存储 JavaScript 前端开发
非常实用的JavaScript一行代码(整理总结)
非常实用的JavaScript一行代码(整理总结)
34 0
|
6天前
|
JavaScript 前端开发 测试技术
如何编写JavaScript模块化代码
如何编写JavaScript模块化代码
14 0
|
5天前
|
存储 JavaScript 前端开发
掌握值类型和引用类型,让你的JavaScript代码更上一层楼!
掌握值类型和引用类型,让你的JavaScript代码更上一层楼!
|
6天前
|
JavaScript 前端开发 测试技术
编写JavaScript模块化代码主要涉及将代码分割成不同的文件或模块,每个模块负责处理特定的功能或任务
【5月更文挑战第10天】编写JavaScript模块化代码最佳实践:使用ES6模块或CommonJS(Node.js),组织逻辑相关模块,避免全局变量,封装细节。利用命名空间和目录结构,借助Webpack处理浏览器环境的模块。编写文档和注释,编写单元测试以确保代码质量。通过这些方法提升代码的可读性和可维护性。
13 3
|
6天前
|
JavaScript 前端开发 开发工具
【JavaScript 与 TypeScript 技术专栏】TypeScript 如何提升 JavaScript 代码的可读性与可维护性
【4月更文挑战第30天】TypeScript 提升 JavaScript 代码的可读性和可维护性,主要通过静态类型系统、增强代码组织、智能提示与错误检测、文档化和在大型项目中的优势。静态类型减少误解,类和接口提供结构,智能提示提高编码效率,类型注解充当内置文档。在大型项目中,TypeScript 降低理解差异,平滑迁移现有 JavaScript 项目,助力提高开发效率和项目质量。
|
6天前
|
JavaScript 前端开发 算法
< JavaScript小技巧:如何优雅的用【一行代码 】实现Js中的常用功能 >
在开发中,采用简洁的语法和结构,遵循一致的命名规范,具有良好的代码组织和注释,能很好的提高代码的质量。可读性:易于阅读和理解。清晰的命名、简洁的语法和良好的代码结构可以使代码的意图更加明确,降低理解代码的难度,提高代码的可读性。可维护性:易于维护。当代码逻辑清晰、结构简洁时,开发者可以更快速地定位和修复bug,进行功能扩展或修改。同时,可读性高的代码也有助于后续的代码重构和优化。可扩展性:更具有扩展性和灵活性。清晰的代码结构和简洁的代码风格使得添加新功能、修改现有功能或扩展代码更加容易。
< JavaScript小技巧:如何优雅的用【一行代码 】实现Js中的常用功能 >
|
6天前
|
前端开发 JavaScript 容器
JavaScript、CSS像素动画特效代码
此示例创建一个带有像素粒子的容器,每隔300毫秒就会动态添加一个新的像素粒子,然后通过CSS的关键帧动画(`@keyframes`)使它们产生上升和逐渐消失的动画效果。你可以根据需要修改像素粒子的颜色、大小、动画效果和创建速度。
14 0