JS中链式调用的实现和应用

你好同学,我是沐爸,欢迎点赞、收藏和关注。个人知乎

不知你是否注意过,链式调用在编程中还是很普遍的,无论是原生JavaScript还是在一些框架和库中,都会看到它们的身影。今天我们一探究竟,看下链式调用是怎么实现的,以及在项目中的应用吧。

在JavaScript中,链式调用(Chaining)是一种非常流行的设计模式,它允许你以流畅的方式连续调用同一个对象的方法。链式调用通常是通过在每个方法的末尾返回对象本身(通常是**this**关键字)来实现的。这样做的好处是代码更加简洁、易读,并且提高了代码的可维护性。

链式调用的实现

构造函数的实现

function Chain(value = 0) {this.value = value// 设置value的值并返回对象本身this.setValue = function (value) {this.value = valuereturn this}// 增加value的值并返回对象本身this.addValue = function (value) {this.value += valuereturn this}// 返回value的值this.getValue = function () {return this.value // 这里不返回this,因为getValue后通常不需要继续链式调用}
}// 使用
const chain = new Chain()
let res = chain.setValue(5).addValue(10).getValue()
console.log(res) // 15

在这个例子中,Chain类的每个方法(除了getValue,因为它不参与链式调用)在执行完自己的任务后,都返回了对象本身(this),这允许你能够连续地调用这些方法。

原型的实现

使用原型prototye改写构造函数示例:

function Chain(value = 0) {this.value = value
}Chain.prototype.setValue = function (value) {this.value = valuereturn this
}Chain.prototype.addValue = function (value) {this.value += valuereturn this
}Chain.prototype.getValue = function () {return this.value
}// 使用
const chain = new Chain()
let res = chain.setValue(5).addValue(10).getValue()
console.log(res) // 15

Chain 函数定义了 value 属性,并使用 Chain.prototype 来定义 setValueaddValuegetValue 方法。这些方法都是实例方法,它们修改或返回 value 属性的值,并返回 this 以支持链式调用。

类的实现

使用类class改写普通函数示例:

class Chain {constructor(value = 0) {this.value = value}setValue(value) {this.value = valuereturn this}addValue(value) {this.value += valuereturn this}getValue() {return this.value}
}// 使用
const chain = new Chain()
let res = chain.setValue(5).addValue(10).getValue()
console.log(res) // 15

Chain 类有一个构造函数,用于初始化 value 属性。setValueaddValuegetValue 方法都是实例方法,它们修改或返回 value 属性的值,并返回 this 以支持链式调用。

使用Proxy实现链式调用

var pipe = function (value) {var funcStack = []var oproxy = new Proxy({},{get: function (pipeObject, fnName) {if (fnName === 'get') {return funcStack.reduce(function (val, fn) {return fn(val)}, value)}funcStack.push(window[fnName])return oproxy}})return oproxy
}var double = (n) => n * 2
var pow = (n) => n * n
var reverseInt = (n) => n.toString().split('').reverse().join('') | 0pipe(3).double.pow.reverseInt.get // 63

上面的示例来自:https://es6.ruanyifeng.com/#docs/proxy

JS原生对象中的链式调用

数组的链式调用

在JavaScript中,数组(Array)原生支持链式调用,这主要得益于数组方法返回数组本身或者新的数组对象。数组的大部分方法都支持链式调用。

const arr = [1, 2, 3, 4, 5].filter((number) => number > 2) // 过滤出大于2的数.map((number) => number * 2) // 将结果翻倍.reduce((acc, number) => acc + number, 0) // 计算总和console.log(arr) // 输出: 24

在这个示例中,我们首先使用.filter()过滤数组,然后使用.map()对结果进行映射,最后使用.reduce()计算所有结果的总和。每个方法都返回一个新的数组或累加值,允许我们继续调用下一个数组方法,实现链式调用。

Promise的链式调用

const p = Promise.resolve(1) // 创建一个已解决的Promisep.then((result) => {console.log(result) // 输出: 1return result + 1 // 返回一个新的Promise
}).then((result) => {console.log(result) // 输出: 2return result * 2 // 返回一个新的Promise}).then((result) => {console.log(result) // 输出: 4,链式调用结束}).catch((error) => {console.error('发生错误:', error) // 错误处理})

在这个示例中,每个.then()方法调用后都返回一个新的Promise,这个Promise将接收上一个Promise的结果作为输入。链中的每个.then()方法都可以根据需要进行异步操作,并且它们的返回值可以被下一个.then()捕获,.catch()方法用来捕获链中任何地方发生的错误。

库和框架中的链式调用

链式调用在某些库和框架的API设计中非常常见。

jQuery

jQuery的DOM操作方法就大量使用了链式调用,使得操作DOM元素变得非常便捷和直观。

$('#myElement').removeClass('old-class').addClass('new-class').hide().fadeIn(1000);

在上面的jQuery示例中,addClasshidefadeIn方法都返回了jQuery对象本身,允许这些方法被连续调用,形成链式调用。
addClass源码示例:

jQuery.fn.extend({addClass: function (value) {var classNames, cur, curValue, className, i, finalValueif (isFunction(value)) {return this.each(function (j) {jQuery(this).addClass(value.call(this, j, getClass(this)))})}classNames = classesToArray(value)if (classNames.length) {return this.each(function () {curValue = getClass(this)cur = this.nodeType === 1 && ' ' + stripAndCollapse(curValue) + ' 'if (cur) {for (i = 0; i < classNames.length; i++) {className = classNames[i]if (cur.indexOf(' ' + className + ' ') < 0) {cur += className + ' '}}finalValue = stripAndCollapse(cur)if (curValue !== finalValue) {this.setAttribute('class', finalValue)}}})}return this // 返回jQuery对象本身}
})

Lodash

Lodash 的很多函数都支持链式调用,这意味着你可以将多个方法连续调用,而不需要创建临时变量。

数组示例:

const result = _([1, 2, 3, 4, 5]).filter((n) => n > 2) // 过滤出大于 2 的数字.map((n) => n * 2) // 将结果中的每个数字乘以 2.value() // 获取最终结果console.log(result) // [6, 8, 10]

对象示例:

const users = [{ name: 'Alice', age: 25 },{ name: 'Bob', age: 30 },{ name: 'Carol', age: 22 }
]const names = _(users).filter({ age: 30 }) // 过滤出年龄为 30 的用户.map('name') // 取出这些用户的名字.value() // 获取最终结果console.log(names) // ['Bob']

字符串示例:

const namesString = _(['Alice', 'Bob', 'Carol']).join(' & ') // 将名字数组连接成一个字符串,元素之间用 " & " 分隔.chain() // 开启链式调用.trim() // 去除字符串两端的空白字符.toUpperCase() // 将字符串转换为大写.value() // 获取最终结果console.log(namesString) // 输出: "ALICE & BOB & CAROL"

Axios

Axios 是一个基于 Promise 的 HTTP 客户端,用于浏览器和 Node.js 环境。Axios 提供了链式调用的能力,使得你可以连续地使用多个实例方法来处理 HTTP 请求。

axios.get('https://api.example.com/data').then((response) => {console.log(response.data) // 处理响应数据}).catch((error) => {console.error('请求失败:', error) // 处理请求错误})

Node.js

在Node.js中,链式调用通常与流、事件和异步操作相关。

Node.js的流API允许你以链式的方式连接数据读取和写入操作:

const fs = require('fs')
const zlib = require('zlib')// 创建一个可读流
const rs = fs.createReadStream('input.txt')// 使用 gzip 压缩数据
const gzip = zlib.createGzip()// 创建一个写入流并压缩数据
const ws = fs.createWriteStream('input.txt.gz')rs.pipe(gzip) // 将读取的数据传递给 gzip 流.pipe(ws) // 将 gzip 压缩后的数据写入文件rs.on('error', (err) => {console.error('读取错误:', err)
})ws.on('error', (err) => {console.error('写入错误:', err)
})

Node.js的EventEmitter类允许你以链式的方式注册多个事件监听器:

const emitter = new EventEmitter()emitter.on('event1', () => {console.log('事件1发生')}).on('event2', () => {console.log('事件2发生')}).emit('event1') // 触发事件1

是不是像我说的?链式调用在前端编程中大量存在。希望对你有所帮助,下期再见!

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

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

相关文章

Chat App 项目之解析(二)

Chat App 项目介绍与解析&#xff08;一&#xff09;-CSDN博客文章浏览阅读76次。Chat App 是一个实时聊天应用程序&#xff0c;旨在为用户提供一个简单、直观的聊天平台。该应用程序不仅支持普通用户的注册和登录&#xff0c;还提供了管理员登录功能&#xff0c;以便管理员可以…

MongoDB数据类型介绍

MongoDB作为一种高性能、开源、无模式的文档型数据库&#xff0c;支持丰富的数据类型&#xff0c;以满足各种复杂的数据存储需求。本文将详细介绍MongoDB支持的主要数据类型&#xff0c;包括数值类型、字符串类型、日期和时间类型、布尔类型、二进制类型、数组、对象以及其他扩…

SpringBoot项目部署时application.yml文件的加载优先级和启动脚本

文章目录 application.yml文件的加载优先级(由高到低)第一级命令行参数第二级Jar包同级目录 /config第三级Jar包同级目录第四级classpath 下的/config第五级classpath 根路径/总结&#xff1a; logback.xml 文件加载顺序当application.yml 和 bootstrap.yml 同时存在时java jar…

【iOS】Block底层分析

目录 前言Block底层结构Block捕获变量原理捕获局部变量&#xff08;auto、static&#xff09;全局变量捕获实例self Block类型Block的copyBlock作为返回值将Block赋值给__strong指针Block作为Cocoa API中方法名含有usingBlock的方法参数Block作为GCD API的方法参数Block属性的写…

使用QGraphicsView思想做一个简单图片查看器

使用QGraphicsView思想做一个简单图片查看器 如果要做一个图片查看器&#xff0c;支持放大、滚动操作&#xff0c;比较直接的方法是&#xff0c;使用QWidget来显示完整图片&#xff0c;将QWidget放入QScrollArea。缩放时调整QWidget的尺寸&#xff0c;QScrollArea会自动调整滚…

MBR20200FCT-ASEMI智能AI专用MBR20200FCT

编辑&#xff1a;ll MBR20200FCT-ASEMI智能AI专用MBR20200FCT 型号&#xff1a;MBR20200FCT 品牌&#xff1a;ASEMI 封装&#xff1a;TO-220F 批号&#xff1a;最新 最大平均正向电流&#xff08;IF&#xff09;&#xff1a;20A 最大循环峰值反向电压&#xff08;VRRM&a…

别再问了!微信小程序的那些事儿,一文搞定

微信小程序是一种无需下载安装即可使用的应用&#xff0c;它嵌入在微信生态中&#xff0c;用户通过微信扫一扫或搜索即可快速访问。 无论是购物、订餐、预约服务&#xff0c;还是玩个小游戏、看篇文章&#xff0c;都不需要下载额外的APP&#xff0c;直接就能在微信里搞定。不会…

联想电脑如何查看ip地址?详细介绍几种方法

随着互联网的普及和技术的飞速发展&#xff0c;IP地址已成为我们日常网络活动中不可或缺的一部分。无论是访问网站、远程办公还是进行网络游戏&#xff0c;IP地址都扮演着重要的角色。对于联想电脑用户来说&#xff0c;了解如何查看自己的IP地址是一项基本技能。虎观代理小二将…

跟国外客户的谈判总是难以掌控?那是因为你还不具备这7种特质

更多外贸干货及开发客户的方法&#xff0c;尽在微信【千千外贸干货】 谈判&#xff0c; 既可以是权力的游戏&#xff0c;也可以是想象的游戏。 有些人熟练地玩游戏而有些人只是模糊地参与着。成功的销售谈判者通常会很巧妙地运用自己的知识&#xff0c;经验和技能来让客户说“Y…

笑出腹肌!Ubuntu:如果连猫都会用,那你呢?‍

目录 &#x1f50d; 初见Ubuntu&#xff1a;喵星人的眼神也亮了 &#x1f50d; &#x1f4bb; Ubuntu&#xff1a;喵星人也能成为技术宅&#xff1f; &#x1f4bb; &#x1f431;‍&#x1f4bb; 喵星人的Ubuntu日常&#xff1a;从追剧到编程&#xff08;误&#xff09; &a…

微信小程序电话号码授权

前端&#xff1a; 文档&#xff1a;https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/getPhoneNumber.html uniapp调用的时候&#xff0c;要将bind用替换 <button open-type"getPhoneNumber" getphonenumber"getPhoneNumber"…

JSON Web Token (JWT): 理解与应用

JWT&#xff08;JSON Web Token&#xff09;是一种开放标准&#xff08;RFC 7519&#xff09;&#xff0c;它定义了一种紧凑且自包含的方式&#xff0c;用于在各方之间以JSON对象的形式安全地传输信息。JWT通常用于身份验证和授权目的&#xff0c;因为它可以使用JSON对象在各方…

【向量数据库】Ubuntu编译安装FAISS

参考官方的安装指导&#xff1a;https://github.com/facebookresearch/faiss/blob/main/INSTALL.md&#xff0c;不需要安装的可以跳过 ~$ wget https://github.com/facebookresearch/faiss/archive/refs/tags/v1.8.0.tar.gz ~$ tar -zxvf v1.8.0.tar.gz ~$ cd faiss-1.8.0 ~$ …

易基因:RNA修饰N4-乙酰胞苷(ac4C)的调控机制、检测方法及其在癌症中的作用最新研究进展|新方向

大家好&#xff0c;这里是专注表观组学十余年&#xff0c;领跑多组学科研服务的易基因。 N4-乙酰胞苷&#xff08;ac4C&#xff09;是一种高度保守的化学修饰&#xff0c;广泛存在于真核和原核生物RNA中&#xff0c;如tRNA、rRNA和mRNA。这种修饰与多种人类疾病显著相关&#…

vuex的原理和使用方法

简介 Vuex 是 Vue.js 应用的状态管理模式&#xff0c;它为应用内的所有组件提供集中式的状态&#xff08;数据&#xff09;管理。可以帮我们管理 Vue 通用的数据 (多组件共享的数据)。 Vuex的构成 state&#xff1a;state 是 Vuex 的数据中心&#xff0c;也就是说state是用来…

关于开启SQL Server服务及其防火墙的方法步骤

一、检查SQL Server服务状态 1、打开服务管理器 可以通过“控制面板” -> “管理工具” -> “服务”来打开服务窗口。或者使用快捷键Win R&#xff0c;输入services.msc后回车&#xff0c;直接打开服务窗口。 2、查找SQL Server服务 在服务列表中&#xff0c;找到与…

职业院校云计算实训室建设方案全景剖析

在信息化社会的今天&#xff0c;云计算作为一项关键技术&#xff0c;正在迅速改变着教育和培训的方式。本文旨在探讨如何通过"职业院校云计算实训室建设方案"&#xff0c;为学生提供一个现代化、高效的学习和研究环境&#xff0c;以适应云计算技术的发展和市场需求。…

软件测试---接口测试

一、接口及接口测试概念 &#xff08;1&#xff09;接口的类型 &#xff08;2&#xff09;接口测试的概念 &#xff08;3&#xff09;接口测试的原理 &#xff08;4&#xff09;接口测试的特点 &#xff08;5&#xff09;接口测试的实现方式 二、HTTP协议 &#xff08;1&#…

Qt 实现抽屉效果

1、实现效果和UI设计界面 2、工程目录 3、mainwindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow> #include <QToolButton> #include <QPushButton> #include <vector> using namespace std;QT_BEGIN_NAMESPACE namespace…

生成式:PolyGen: An Autoregressive Generative Model of 3D Meshes【附件】

论文:PolyGen: An Autoregressive Generative Model of 3D Meshes OBJ坐标变换: # Transpose so that z-axis is vertical.vertices = vertices[:, [2, 0, 1]]变换前: 对应数据: