创建一个接受对象字面量的函数,并从该对象的成员创建一个 class

Create a function that takes an object literal and create a class from that object's members

我的问题:

var Person = makeClass( // Make a class with 2 instance methods which are initialize and say 
    {
        initialize: function(name) {
            this.name = name;
        },
        say: function(message) {
            return this.name + " says: " + message;
        }
    }
);

documentation of the @lends tag of jsdoc 中,我发现他们正在使用一个辅助函数,他们说它可以接受一个对象文字并从该对象的成员创建一个 class。在上面的示例中,makeClass 函数创建了一个 Person class,它有 2 个实例方法(或者它们也可以是静态方法),它们是 initializesay.我想知道我们是如何创建那种功能的。

我想知道的:

我试过重新创建那种功能,但是对我来说真的很难,我不知道有什么办法可以做到。所以希望你们能给我一个重新创建这个 makeClass 函数的方法。
我也想知道这种创建class的方式是不是很奇怪,或者你可以认为makeClass这种函数有用没用。

我为什么要创建那个函数的原因:

如果你问我原因,那么我想知道函数里面的“成分”,以便理解JSDoc的@lends标签,我想真正了解这个@lends的用例JSDoc 中的标记。但是面对这种奇怪的创建 class 的方式(这对我来说很奇怪,我以前总是使用 ES6 class )我真的很难理解 @lends 标签。

首先,您可以浏览一下 MDN docs on classes。在那里您会找到一些重要的信息:

Classes are in fact just "special functions"

并且,稍微解释一下:

Just as you can define function expressions ... you can define class expressions

所以,如果 class 表达式可以像函数表达式一样创建,而 classes 只是“特殊函数”,暂停一下问一下可能会更容易我们自己:我们如何编写一个创建函数的函数

有不止一种方法可以解决这个问题,但希望根据您上面的示例,这是有意义的:

const makeFunction = function(valToAdd) {
  return function(val) {
    return val + valToAdd;
  }
}

const addTwo = makeFunction(2);
addTwo(2)  // 4

现在,将 makeFunction 翻译成 makeClass 希望更简单一些。范例是相同的,但我们必须做更多的工作来创建实例方法:

const makeClass = function(obj) {
  // Anonymous class expression
  const dynamicClass = class {};
  
  // Define properties on our class
  for (const [name, value] of Object.entries(obj)) {
    // Notice we define properties on the prototype so instances of the class can access them
    Object.defineProperty(dynamicClass.prototype, name, {
      value,
      writable: true,
      configurable: true
    })
  }
  return dynamicClass;
}

// Create a Person class with methods `initialize` and `say`
const Person = makeClass({
  initialize: function(name) {
    this.name = name;
  },
  say: function(message) {
    return this.name + " says: " + message;
  }
})

// Create an instance
const person = new Person()

person.initialize("Sam")
person.say("Hello!") // Sam says: Hello!

并回答您的一些具体问题:

I also want to know if this kind of creating class way is strange or not, or you can think the kind of function like makeClass is useful or not.

我认为这是一种创建 classes 的奇怪方式,尽管它在某些用例中可能很有用。一般来说,这种范式被称为 metaprogramming,通常用于整合共享功能。权衡是复杂性很容易膨胀并使其他使用您的代码的人感到困惑。

I want to ... understand the @lends tag of JSDoc.

由于 makeClass 创建实例方法的方式(本质上是复制它们),JSDoc 不了解创建的 class 可以使用哪些方法。所以这现在应该有意义了(来自 JSDoc 文档):

The @lends tag tells JSDoc that all the member names of that object literal are being "loaned" to a variable named Person.

Person 变量是我们的 class 并且用 @lends 注释对象文字告诉 JSDoc 我们正在“借出” initializesay 个成员。