概念
鏈式調用(Method Chaining)是 JavaScript 中一種常見的編程模式,允許通過連續調用對象的方法來簡化代碼。這種模式的核心在于每個方法返回調用對象本身(通常是 this
),從而可以繼續調用其他方法。
鏈式調用的關鍵在于每個方法返回當前對象(this
)。這樣,每次方法調用后,可以立即調用下一個方法。例如:
const obj = {method1() {// 執行邏輯return this;},method2() {// 執行邏輯return this;}
};obj.method1().method2();
優點
- 代碼簡潔:減少重復代碼,避免多次引用同一對象。
- 可讀性高:鏈式調用的代碼通常更接近自然語言,易于理解。
- 流暢接口:適合構建流暢的 API 或 DSL(領域特定語言)。
常見應用場景
-
jQuery:jQuery 是鏈式調用的經典例子,例如:
$('div').addClass('active').css('color', 'red').fadeOut();
-
數組操作:部分數組方法(如
map
、filter
)可以鏈式調用:const result = [1, 2, 3].map(x => x * 2).filter(x => x > 3);
-
構建器模式:用于構造復雜對象,例如:
const query = new QueryBuilder().select('name').from('users').where('age > 18').limit(10);
實現自定義鏈式調用
下面是一個簡單的自定義鏈式調用的例子:
class Calculator {constructor(value = 0) {this.value = value;}add(num) {this.value += num;return this;}subtract(num) {this.value -= num;return this;}multiply(num) {this.value *= num;return this;}getResult() {return this.value;}
}const calc = new Calculator(10);
const result = calc.add(5).subtract(3).multiply(2).getResult(); // 24
注意事項
- 不可變對象:如果需要保持對象不可變,鏈式調用可能不適用,因為每次方法調用都會返回新對象。
- 調試困難:過長的鏈式調用可能增加調試難度,建議適度拆分。
- 錯誤處理:鏈式調用中某個方法出錯時,可能需要額外的錯誤處理機制。
鏈式調用是一種強大的模式,但需根據具體場景合理使用。
面試題(wxg)
var data = [{ price: 13, name: 'A-apple' },{ price: 9, name: 'B-apple' },{ price: 16, name: 'A-orange' },{ price: 10, name: 'B-orange' },{ price: 20, name: null }
];var find = function (origin) {// your code are here...
};// 查找 data 中,符合條件的數據,并進行排序
var result = find(data).where({ 'name': /^A/ }).orderBy('price', 'desc');
console.log(result);
// 預期輸出: [ { price: 16, name: 'A-orange' }, { price: 13, name: 'A-apple' } ]
分析:where
函數中傳遞的參數表示條件,key
是 data
中的屬性,value
是比較的規則(正則表達式);orderBy 傳遞兩個參數,第一個表示比較哪個屬性,第二個是排序規則(正序或倒序)
// 原始數據
var data = [{ price: 13, name: 'A-apple' },{ price: 9, name: 'B-apple' },{ price: 16, name: 'A-orange' },{ price: 10, name: 'B-orange' },{ price: 20, name: null }
];// 實現find函數
var find = function (origin) {// 創建一個查詢對象var query = {data: origin,// where方法用于過濾數據where: function(conditions) {this.data = this.data.filter(function(item) {// 遍歷條件對象,篩選出符合所有條件的記錄for (var key in conditions) {var condition = conditions[key];// 如果條件值是正則表達式if (condition instanceof RegExp) {if (!condition.test(item[key])) {return false;}} // 如果條件值是普通值else {if (item[key] !== condition) {return false;}}}return true;});return this; // 返回this以支持鏈式調用},// orderBy方法用于排序orderBy: function(field, direction) {this.data.sort(function(a, b) {var aVal = a[field];var bVal = b[field];// 處理null值if (aVal === null) aVal = 0;if (bVal === null) bVal = 0;if (direction === 'desc') {return bVal - aVal; // 降序} else {return aVal - bVal; // 升序}});return this.data; // 返回排序后的數組}};return query;
};// 查找 data 中,符合條件的數據,并進行排序
var result = find(data).where({ 'name': /^A/ }).orderBy('price', 'desc');
console.log(result);// 預期輸出: [ { price: 16, name: 'A-orange' }, { price: 13, name: 'A-apple' } ]