【问题标题】:Automatically add method at the end of method chain在方法链末尾自动添加方法
【发布时间】:2021-05-12 15:30:56
【问题描述】:

我正在构建一个 JavaScript 类,我想在方法链的末尾返回一个结果,而不调用特定的方法。

示例 1:myDate('01/01/2000').add(1, 'day') 应返回 01/02/2000

示例 2:myDate('01/01/2000').add(1, 'day').format('MMMM D YYYY') 应返回 January 2 2000

我知道使用 JS class 可以做到这一点,因为看到它在 DayJs 中工作,我只是不明白如何:https://github.com/iamkun/dayjs/blob/dev/src/index.js#L77

目前,我所拥有的看起来像这样:

class MyDate {
  constructor(date) {
    this.date = date;
  }

  add(count, unit) {
    this.date = // function
    return this; // to enable method chaining
  }

  format() {
    this.date = // function
    return this.date; // to return the desired result
  }

  get() {
    return this.date;
  }
}

// wrapper function to instantiate class on function call
const myDate = date => new MyDate(date);

通过此设置,我得到以下行为:

示例 3:myDate('01/01/2000').add(1, 'day') 返回 { date: 01/02/2000} 而不是 01/02/2000

示例 4:myDate('01/01/2000').add(1, 'day').format('MMMM D YYYY') 按预期返回 January 2 2000

示例 5:myDate('01/01/2000').add(1, 'day').get() 返回 01/02/2000,但我想消除唠叨的 get()...

我用谷歌搜索了这个问题,“js 检测方法链结束”等,但我找不到任何结果可以解释它是如何工作的。

感谢您的帮助!

【问题讨论】:

  • 在 DayJs 或 MomentJs 中,您还必须使用 .format () 来获取带有字符串的日期,否则它会返回一个对象,就像您的班级所做的那样。
  • 我不确定你为什么认为 DayJS 做的事情明显不同。只有你可以决定一个函数将返回什么——而且没有办法知道有人使用你的 API 将如何使用它,例如,如果他们想要或需要一个他们仍然想要的中间值怎么办能上链吗?
  • @AlTheLazyMonkey @Dave Newton,你们都是对的,感谢您向我指出,我认为您可以从可链接的方法返回 this 以外的其他内容,但我错了。这里有一个小示范给那些仍有疑问的人:replit.com/@RilDev/DayJSClassExamples#index.js

标签: javascript class method-chaining


【解决方案1】:

从逻辑上讲,类上的add 方法应该返回对象实例而不是特定的成员变量。

到目前为止,您所拥有的一切都是完美的,这就是任何用户都希望它能够工作的方式。

想象一下,您必须添加另一个成员变量,例如 time 到您的类中,并且您想要链接类似 object.add(1, 'day').add(5, 'hour') 的东西。只有当您的 add 函数返回您的类的实例时,您才能实现此目的。

在末尾附加一个get() 方法也很好。考虑著名的moment.js 包。甚至他们有一个format() 方法来获取实际的日期对象。

希望这能澄清你的困惑。

【讨论】:

  • 谢谢你,这很清楚。我仍然想知道,如何将mapfilter 链接到一个数组上?例如array.map()array.filter()array.map().filter() 都返回可用的东西(不是this)。我想这是prototype 的东西,我还没有得到...chromium.googlesource.com/external/v8/+/refs/heads/master/src/…
  • prototype 只不过是类结构。即使使用Array,您必须了解的是,在所有这些函数中,主类对象(即Array)正在被返回。就像我们在您的情况下也决定返回 MyDate 对象而不是其他一些原始类型
  • 看起来我们越来越接近我想要的东西了!我一直在尝试(没有成功)将函数发回整个班级的概念。 replit.com/@RilDev/ClassChainableMethods#index.js 如果可能的话,你能给我发一个链接到一个类,当这样使用时会发回一个可用的结果:calculator(1)calculator(1).add(2)calculator(1).add(2).multiply(3)。我确信可以使用 JavaScript!
  • @RilDev usable 是什么意思?您想将它们与原始类型一起使用吗?列出一些你认为需要改变的情况。其中之一将是直接console.log 而无需调用display。您还有哪些其他用例?
  • 感谢您容忍我!我想模仿这种行为:Array(1, 2, 3) 返回[1, 2, 3]Array(1, 2, 3).map(n => n+1) 返回[2, 3, 4]Array(1,2,3).map(n => n+1).filter(n => n < 4) 返回[2, 3]。在每种情况下,无论是单独调用还是与方法链一起调用,它总是会返回一个 usable array,而无需在链的末尾添加 getValue() 方法。你知道怎么做吗?或者这种技术怎么称呼?
【解决方案2】:

回想起来,我想做的是一个具有以下特点的类:

  • import myDate from "./myDate.js"
  • import { isMyDate } from "./myDate.js"
  • 无需使用new关键字来实例化
  • 可以传递无限数量的参数
  • 使用函数链接
  • console.log(myDate(params)) 输出自定义字符串 MyDate<date_in_ms)>
  • ${myDate(params)} 输出自定义字符串 date_in_ms

这是一个可能的实现:

// Custom console.log
// Deno: https://doc.deno.land/builtin/stable#Deno.inspect
const inspect = Symbol.for("Deno.customInspect")
// Node: https://nodejs.org/api/util.html#util_util_inspect_custom
// const inspect = Symbol.for('nodejs.util.inspect.custom');

class MyDate {
  constructor(date = new Date(), options) {
    // Set the class's properties
    this._date = date;
    this._options = options;

    // Run initialization tasks
    this.initialize();
  }

  initialize() {
    // if Date, convert time to milliseconds
    if (this._date instanceof Date) {
      this._date = this._date.getTime();
    }
  }

  // Output the result
  format() {
    return this._date;
  }

  // Chainable function
  add(amount) {
    this._date += amount;
    return this;
  }

  // Output all the parameters past after the first one
  options() {
    return this._options;
  }

  // Custom console.log
  [inspect]() {
    return `MyDate<${this._date}>`;
  }

  // Custom String output
  toString() {
    return `${this._date}`;
  }
}

// Automatically instantiate class
const myDate = (date, ...options) => {
  return new MyDate(date, options);
}

// Stand-alone function
const isMyDate = date => date instanceof MyDate;
// Access the stand-alone funtion from the MyDate instance
myDate.isMyDate = date => isMyDate(date);

export default myDate;
export { isMyDate };

链接到 Dev.to 文章:https://dev.to/rildev/modern-es6-class-48pb

实时概念验证链接:https://replit.com/@RilDev/ModernES6Class

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-16
    • 1970-01-01
    • 2010-10-25
    • 2019-04-06
    • 1970-01-01
    • 2015-10-28
    相关资源
    最近更新 更多