不知你是否注意過,鏈?zhǔn)秸{(diào)用在編程中還是很普遍的,無論是原生JavaScript還是在一些框架和庫中,都會(huì)看到它們的身影。今天我們一探究竟,看下鏈?zhǔn)秸{(diào)用是怎么實(shí)現(xiàn)的,以及在項(xiàng)目中的應(yīng)用吧。 在JavaScript中,鏈?zhǔn)秸{(diào)用(Chaining)是一種非常流行的設(shè)計(jì)模式,它允許你以流暢的方式連續(xù)調(diào)用同一個(gè)對(duì)象的方法。鏈?zhǔn)秸{(diào)用通常是通過在每個(gè)方法的末尾返回對(duì)象本身(通常是**this**關(guān)鍵字)來實(shí)現(xiàn)的。這樣做的好處是代碼更加簡(jiǎn)潔、易讀,并且提高了代碼的可維護(hù)性。 鏈?zhǔn)秸{(diào)用的實(shí)現(xiàn) 構(gòu)造函數(shù)的實(shí)現(xiàn) function Chain(value = 0) { this.value = value // 設(shè)置value的值并返回對(duì)象本身 this.setValue = function (value) { this.value = value return this } // 增加value的值并返回對(duì)象本身 this.addValue = function (value) { this.value += value return this } // 返回value的值 this.getValue = function () { return this.value // 這里不返回this,因?yàn)間etValue后通常不需要繼續(xù)鏈?zhǔn)秸{(diào)用 } } // 使用 const chain = new Chain() let res = chain.setValue(5).addValue(10).getValue() console.log(res) // 15 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 ' 運(yùn)行運(yùn)行 在這個(gè)例子中,Chain類的每個(gè)方法(除了getValue,因?yàn)樗粎⑴c鏈?zhǔn)秸{(diào)用)在執(zhí)行完自己的任務(wù)后,都返回了對(duì)象本身(this),這允許你能夠連續(xù)地調(diào)用這些方法。 原型的實(shí)現(xiàn) 使用原型prototye改寫構(gòu)造函數(shù)示例: function Chain(value = 0) { this.value = value } Chain.prototype.setValue = function (value) { this.value = value return this } Chain.prototype.addValue = function (value) { this.value += value return this } Chain.prototype.getValue = function () { return this.value } // 使用 const chain = new Chain() let res = chain.setValue(5).addValue(10).getValue() console.log(res) // 15 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ' 運(yùn)行運(yùn)行 Chain 函數(shù)定義了 value 屬性,并使用 Chain.prototype 來定義 setValue、addValue 和 getValue 方法。這些方法都是實(shí)例方法,它們修改或返回 value 屬性的值,并返回 this 以支持鏈?zhǔn)秸{(diào)用。 類的實(shí)現(xiàn) 使用類class改寫普通函數(shù)示例: class Chain { constructor(value = 0) { this.value = value } setValue(value) { this.value = value return this } addValue(value) { this.value += value return this } getValue() { return this.value } } // 使用 const chain = new Chain() let res = chain.setValue(5).addValue(10).getValue() console.log(res) // 15 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 ' 運(yùn)行運(yùn)行 Chain 類有一個(gè)構(gòu)造函數(shù),用于初始化 value 屬性。setValue、addValue 和 getValue 方法都是實(shí)例方法,它們修改或返回 value 屬性的值,并返回 this 以支持鏈?zhǔn)秸{(diào)用。 使用Proxy實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用 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('') | 0 pipe(3).double.pow.reverseInt.get // 63 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 上面的示例來自:https://es6./#docs/proxy JS原生對(duì)象中的鏈?zhǔn)秸{(diào)用 數(shù)組的鏈?zhǔn)秸{(diào)用 在JavaScript中,數(shù)組(Array)原生支持鏈?zhǔn)秸{(diào)用,這主要得益于數(shù)組方法返回?cái)?shù)組本身或者新的數(shù)組對(duì)象。數(shù)組的大部分方法都支持鏈?zhǔn)秸{(diào)用。 const arr = [1, 2, 3, 4, 5] .filter((number) => number > 2) // 過濾出大于2的數(shù) .map((number) => number * 2) // 將結(jié)果翻倍 .reduce((acc, number) => acc + number, 0) // 計(jì)算總和 console.log(arr) // 輸出: 24 1 2 3 4 5 6 ' 運(yùn)行運(yùn)行 在這個(gè)示例中,我們首先使用.filter()過濾數(shù)組,然后使用.map()對(duì)結(jié)果進(jìn)行映射,最后使用.reduce()計(jì)算所有結(jié)果的總和。每個(gè)方法都返回一個(gè)新的數(shù)組或累加值,允許我們繼續(xù)調(diào)用下一個(gè)數(shù)組方法,實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用。 Promise的鏈?zhǔn)秸{(diào)用 const p = Promise.resolve(1) // 創(chuàng)建一個(gè)已解決的Promise p.then((result) => { console.log(result) // 輸出: 1 return result + 1 // 返回一個(gè)新的Promise }) .then((result) => { console.log(result) // 輸出: 2 return result * 2 // 返回一個(gè)新的Promise }) .then((result) => { console.log(result) // 輸出: 4,鏈?zhǔn)秸{(diào)用結(jié)束 }) .catch((error) => { console.error('發(fā)生錯(cuò)誤:', error) // 錯(cuò)誤處理 }) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ' 運(yùn)行運(yùn)行 在這個(gè)示例中,每個(gè).then()方法調(diào)用后都返回一個(gè)新的Promise,這個(gè)Promise將接收上一個(gè)Promise的結(jié)果作為輸入。鏈中的每個(gè).then()方法都可以根據(jù)需要進(jìn)行異步操作,并且它們的返回值可以被下一個(gè).then()捕獲,.catch()方法用來捕獲鏈中任何地方發(fā)生的錯(cuò)誤。 庫和框架中的鏈?zhǔn)秸{(diào)用 鏈?zhǔn)秸{(diào)用在某些庫和框架的API設(shè)計(jì)中非常常見。 jQuery jQuery的DOM操作方法就大量使用了鏈?zhǔn)秸{(diào)用,使得操作DOM元素變得非常便捷和直觀。 $('#myElement') .removeClass('old-class') .addClass('new-class') .hide() .fadeIn(1000); 1 2 3 4 5 在上面的jQuery示例中,addClass、hide和fadeIn方法都返回了jQuery對(duì)象本身,允許這些方法被連續(xù)調(diào)用,形成鏈?zhǔn)秸{(diào)用。 addClass源碼示例: jQuery.fn.extend({ addClass: function (value) { var classNames, cur, curValue, className, i, finalValue if (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對(duì)象本身 } }) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 Lodash Lodash 的很多函數(shù)都支持鏈?zhǔn)秸{(diào)用,這意味著你可以將多個(gè)方法連續(xù)調(diào)用,而不需要?jiǎng)?chuàng)建臨時(shí)變量。 數(shù)組示例: const result = _([1, 2, 3, 4, 5]) .filter((n) => n > 2) // 過濾出大于 2 的數(shù)字 .map((n) => n * 2) // 將結(jié)果中的每個(gè)數(shù)字乘以 2 .value() // 獲取最終結(jié)果 console.log(result) // [6, 8, 10] 1 2 3 4 5 6 對(duì)象示例: const users = [ { name: 'Alice', age: 25 }, { name: 'Bob', age: 30 }, { name: 'Carol', age: 22 } ] const names = _(users) .filter({ age: 30 }) // 過濾出年齡為 30 的用戶 .map('name') // 取出這些用戶的名字 .value() // 獲取最終結(jié)果 console.log(names) // ['Bob'] 1 2 3 4 5 6 7 8 9 10 11 12 字符串示例: const namesString = _(['Alice', 'Bob', 'Carol']) .join(' & ') // 將名字?jǐn)?shù)組連接成一個(gè)字符串,元素之間用 " & " 分隔 .chain() // 開啟鏈?zhǔn)秸{(diào)用 .trim() // 去除字符串兩端的空白字符 .toUpperCase() // 將字符串轉(zhuǎn)換為大寫 .value() // 獲取最終結(jié)果 console.log(namesString) // 輸出: "ALICE & BOB & CAROL" 1 2 3 4 5 6 7 8 Axios Axios 是一個(gè)基于 Promise 的 HTTP 客戶端,用于瀏覽器和 Node.js 環(huán)境。Axios 提供了鏈?zhǔn)秸{(diào)用的能力,使得你可以連續(xù)地使用多個(gè)實(shí)例方法來處理 HTTP 請(qǐng)求。 axios .get('https://api./data') .then((response) => { console.log(response.data) // 處理響應(yīng)數(shù)據(jù) }) .catch((error) => { console.error('請(qǐng)求失敗:', error) // 處理請(qǐng)求錯(cuò)誤 }) 1 2 3 4 5 6 7 8 Node.js 在Node.js中,鏈?zhǔn)秸{(diào)用通常與流、事件和異步操作相關(guān)。 Node.js的流API允許你以鏈?zhǔn)降姆绞竭B接數(shù)據(jù)讀取和寫入操作: const fs = require('fs') const zlib = require('zlib') // 創(chuàng)建一個(gè)可讀流 const rs = fs.createReadStream('input.txt') // 使用 gzip 壓縮數(shù)據(jù) const gzip = zlib.createGzip() // 創(chuàng)建一個(gè)寫入流并壓縮數(shù)據(jù) const ws = fs.createWriteStream('input.txt.gz') rs .pipe(gzip) // 將讀取的數(shù)據(jù)傳遞給 gzip 流 .pipe(ws) // 將 gzip 壓縮后的數(shù)據(jù)寫入文件 rs.on('error', (err) => { console.error('讀取錯(cuò)誤:', err) }) ws.on('error', (err) => { console.error('寫入錯(cuò)誤:', err) }) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 ' 運(yùn)行運(yùn)行 Node.js的EventEmitter類允許你以鏈?zhǔn)降姆绞阶?cè)多個(gè)事件監(jiān)聽器: const emitter = new EventEmitter() emitter .on('event1', () => { console.log('事件1發(fā)生') }) .on('event2', () => { console.log('事件2發(fā)生') }) .emit('event1') // 觸發(fā)事件1 1 2 3 4 5 6 7 8 9 10 是不是像我說的?鏈?zhǔn)秸{(diào)用在前端編程中大量存在。 ———————————————— 版權(quán)聲明:本文為博主原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文出處鏈接和本聲明。 原文鏈接:https://blog.csdn.net/m0_37943716/article/details/141300423 |
|