Skip to content

链式调用的实现方式

原理:返回 this

链式调用不是 JavaScript 的特性,而是一种设计模式——每个方法执行完后返回对象自身(this),下一个方法就能继续在同一个对象上调用。

一个简单的实现:

javascript
class Calculator {
  constructor(value) {
    this.value = value;
  }

  add(num) {
    this.value += num;
    return this;
  }

  subtract(num) {
    this.value -= num;
    return this;
  }

  multiply(num) {
    this.value *= num;
    return this;
  }

  divide(num) {
    this.value /= num;
    return this;
  }

  getValue() {
    return this.value;
  }
}

const result = new Calculator(10)
  .add(5)       // 15
  .subtract(2)  // 13
  .multiply(3)  // 39
  .divide(4)    // 9.75
  .getValue();

console.log(result); // 9.75

每个运算方法修改内部状态后返回 this,下一次调用自然能找到同一个对象的当前状态。getValue() 是例外——它返回计算结果而不是 this,标志着链式调用的结束。

与 Promise 链式调用的区别

Promise 的 .then() 也支持链式调用,但它的"返回 this"逻辑不同:.then() 每次都返回一个新的 Promise,而不是原 Promise 自身。这种不可变性避免了状态污染——每个 .then() 拿到的是上一个 .then() 返回的新值,不会互相干扰。

javascript
fetch('/api/user/1')
  .then((res) => res.json())
  .then((user) => fetch(`/api/order/${user.id}`))
  .then((res) => res.json())
  .then((orders) => console.log(orders));

每一步都返回新的 Promise,链上每个环节相对独立。这与 Calculator 示例中"同一个对象不断被修改"的方式不同——Calculator 是有状态可变对象的链,Promise 是不可变数据流的链。

实际开发中的应用

jQuery 是链式调用的经典使用者:

javascript
$('#userCard')
  .addClass('active')
  .css('background', '#f5f5f5')
  .fadeIn(300);

现代前端中,数组方法的链式组合也很常见:

javascript
const activeOrderIds = orderList
  .filter((order) => order.status === 'active')
  .map((order) => order.id)
  .sort((a, b) => a - b);

filtermapsort 都返回新数组,设计上遵循了不可变性——这和 Promise 链的思路一致,跟 Calculator 那种"修改自身然后返回 this"的思路不同。两种方式没有绝对的优劣:可变链适合需要逐步构建状态的场景,不可变链更适合数据处理和异步流程。

边界注意

返回 this 的链式调用暗藏一个风险:使用者可能忽略调用顺序带来的副作用。一个方法修改了内部状态,会影响后续所有方法的执行结果——这对于喜欢把链式调用的代码拆开复用的开发者来说是个陷阱。如果设计链式 API,方法名的语义需要足够清晰,让调用顺序的意图不言自明。