You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在函数中返回this是否为创建带方法对象的推荐模式?含ES6方案咨询

关于函数返回this的链式调用模式:是否推荐、替代方案与ES6实现

嘿,这个问题问得特别好!我来帮你梳理清楚这个链式调用模式的来龙去脉~

先明确:你用的是「链式调用/Builder模式」

你提到的在函数里返回this(或上下文对象)实现连续调用的方式,其实是很经典的链式调用模式(也常归为Builder模式的一种)。核心是让方法调用后返回当前对象,从而可以连续调用同一对象的其他方法,让代码更简洁流畅。

这个模式是否推荐?分场景看!

  • ✅ 适合的场景:
    • 当你需要构建复杂的配置对象、查询语句(比如你的示例里的数据库查询Stub)、或者连续执行同一上下文的操作时,链式调用能大幅提升代码可读性和简洁度。比如jQuery的$('div').addClass('red').fadeIn()就是典型场景。
    • 封装工具类/SDK时,链式调用能让API更友好,降低用户的使用成本。
  • ❌ 不适合的场景:
    • 如果只是简单的独立函数调用,强行链式会增加代码耦合度,反而让逻辑晦涩,调试也更麻烦(链式中某一步出错很难定位)。
    • 当方法有明确的业务返回值(比如计算结果)时,返回this会覆盖原本的返回值,造成语义混淆。

为什么你在代码里很少见到它?

其实这个模式并不少见,只是使用场景相对集中:

  • 多数业务代码以处理业务逻辑为主,很少需要连续构建复杂对象/操作,所以用得少;
  • 很多库(比如Lodash、Axios的拦截器配置)会用,但你可能没注意到;
  • 现代前端更倾向于纯函数、Immutable风格的代码,这种无副作用的写法有时候会替代链式调用。

更优/常用的实现方式(避坑!你示例里有个小问题)

先提一下你示例里的陷阱:你用了箭头函数,而箭头函数没有自己的this,这里的return this其实指向外层上下文(比如全局window或者模块的this),根本不是你想要的stubs对象!这会导致链式调用失败。

推荐的实现方式有三种:

1. 显式返回上下文对象(最稳妥)

不管用箭头函数还是普通函数,直接返回要链式的对象,避免this的绑定问题:

const state = {};
const stubs = {};

stubs.collection = sinon.stub().callsFake((collection) => {
  state.collection = collection;
  return stubs; // 直接返回stubs,而非this
});

stubs.orderBy = sinon.stub().callsFake((field, direction) => {
  state.orderBy = { field, direction };
  return stubs;
});

// 使用:链式调用正常工作
stubs.collection('users').orderBy('name', 'asc');

2. 用类封装(更清晰的面向对象写法)

如果逻辑比较复杂,用ES6类封装状态和方法,返回this是很标准的写法:

class QueryStubBuilder {
  constructor() {
    this.state = {};
    this.stubs = {
      collection: sinon.stub().callsFake((collection) => {
        this.state.collection = collection;
        return this.stubs;
      }),
      orderBy: sinon.stub().callsFake((field, direction) => {
        this.state.orderBy = { field, direction };
        return this.stubs;
      })
    };
  }

  getStubs() {
    return this.stubs;
  }
}

// 使用
const builder = new QueryStubBuilder();
const query = builder.getStubs();
query.collection('users').orderBy('name', 'asc');

3. Immutable风格的链式(无副作用)

如果追求纯函数、无副作用的写法,可以每次调用都返回新对象,不修改原对象:

const createQueryStub = (initialState = {}) => ({
  collection: (collection) => createQueryStub({...initialState, collection}),
  orderBy: (field, direction) => createQueryStub({...initialState, orderBy: {field, direction}}),
  getState: () => initialState
});

// 使用:每次调用返回新对象,原对象不受影响
const query = createQueryStub().collection('users').orderBy('name', 'asc');
console.log(query.getState()); // { collection: 'users', orderBy: { field: 'name', direction: 'asc' } }

ES6的现代实现方案

除了上面的类和闭包,还有两个进阶方案:

1. 用Proxy实现动态链式

如果方法是动态生成的,或者需要拦截所有属性访问,可以用ES6的Proxy实现自动链式:

const createDynamicQuery = () => {
  const state = {};
  return new Proxy({}, {
    get(target, prop) {
      if (prop === 'getState') return () => state;
      // 动态生成方法,调用后返回Proxy本身实现链式
      return (...args) => {
        state[prop] = args;
        return target;
      };
    }
  });
};

// 使用:不管调用什么方法都能链式
const query = createDynamicQuery().collection('users').orderBy('name', 'asc').limit(10);
console.log(query.getState()); // { collection: ['users'], orderBy: ['name', 'asc'], limit: [10] }

2. 用ES模块+闭包封装

在模块里使用时,可以用闭包维护状态,对外暴露可链式的方法,避免全局变量污染:

// queryStub.js
import sinon from 'sinon';

export const createQueryStub = () => {
  const state = {};
  const stubs = {
    collection: sinon.stub().callsFake((col) => {
      state.collection = col;
      return stubs;
    }),
    orderBy: sinon.stub().callsFake((field, dir) => {
      state.orderBy = { field, dir };
      return stubs;
    })
  };
  return { stubs, getState: () => state };
};

总结

  • 链式调用(返回this/上下文对象)是合法且实用的模式,但要根据场景使用,不要滥用;
  • 你之前示例里的箭头函数this是个陷阱,建议直接返回目标对象;
  • ES6里用类、闭包+箭头函数、Proxy都能实现更现代、更安全的链式调用;
  • 业务代码里用得少是因为场景不匹配,库/工具类里其实很常见。

内容的提问来源于stack exchange,提问作者cooldude101

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 08:36:06