创建 JavaScript 类时,动态遍历对象。

huangapple go评论78阅读模式
英文:

Create JS classes dynamically while looping through object

问题

Here's the translated code snippet without the comments:

// function for dependency injection
addNumbers = (numbers) => {
    let result = 0;
    
    numbers.forEach((number) => {
        result = result + number;
    })
    
    console.log(`\nThe result is ${result}`);
}

// class without parameters
class Log {
    
    constructor() {
        console.log('My only job is to log this text!\n');
    }
}

// class with parameters
class Greeting {
    
    constructor(params) {
        this.sayHello(params);
    }

    sayHello(params) {
        for (const [key, name] of Object.entries(params)) {
            console.log(`Hello ${name}, nice to meet you!`);
        }
    }
}

// class with parameters and dependency injection
class Addition {
    
    constructor(params) {
        this.injectedMethod = params['dependency'];
        this.injectedMethod(params['numbers']);
    }
}

classParams = {
  Log: '',
  Greeting: {
    name1: 'Alice',
    name2: 'Bob'
  },
  Addition: {
    numbers: [1, 2, 3, 4, 5],
    dependency: addNumbers
  }
}

// I'd like to have a loop that replaces the following code and iterates through classParams, creating the classes with their respective parameters
new Log();
new Greeting(classParams['Greeting']);
new Addition(classParams['Addition']);

And the code you tried to use, with some adjustments:

for (const [object, params] of Object.entries(classParams)) {
    if (typeof window[object] === 'function') {
        new window[object](params);
    }
}

This adjusted code should help you create instances of classes based on the values in the classParams object.

英文:

I'd like to create some kind of factory to automate the process of creating JS classes. The factory should loop through an object that contains classes names and their respective parameters. The following simplified code sample hopefully demonstrates what I mean:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

// function for dependency injection
addNumbers = (numbers) =&gt; {
    let result = 0;
    
    numbers.forEach((number) =&gt; {
        result = result + number;
    })
    
    console.log(`\nThe result is ${result}`);
}



// class without parameters
class Log {
    
    constructor() {
        console.log (&#39;My only job is to log this text!\n&#39;);
    }
}



// class with parameters
class Greeting {
    
    constructor(params) {
        this.sayHello(params);
    }

    sayHello(params) {
        for (const [key, name] of Object.entries(params)) {
            console.log(`Hallo ${name}, nice to meet you!`);
        }
    }
}



// class with parameters
// and dependency injection
class Addition {
    
    constructor(params) {
        this.injectedMethod = params[&#39;dependency&#39;];
        this.injectedMethod(params[&#39;numbers&#39;]);
    }
}



classParams = {

  Log: &#39;&#39;,

  Greeting: {
    name1: &#39;Alice&#39;,
    name2: &#39;Bob&#39;
  },

  Addition: {
    numbers: [1, 2, 3, 4, 5],
    dependency: addNumbers
  }
}



// Here comes the critical part:
// I&#39;d like to have a loop that replaces the 
// following code and iterates through
// classParams, creating the classes with
// their respective parameters
new Log();
new Greeting(classParams[&#39;Greeting&#39;]);
new Addition(classParams[&#39;Addition&#39;]);

<!-- end snippet -->

I tried something like

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

for (const [object, params] of Object.entries(classParams)) {
    new [object](params);
  }

<!-- end snippet -->

.. but that won't work because inside the loop I don't get the class as an object but only as a string. I tried some things I found online, but the best I could achive was having no errors - but having no working classes either.

What am I getting wrong?

答案1

得分: 1

以下是翻译好的代码部分:

    const addNumbers = e => {
      let o = 0;
      e.forEach(e => {
        o += e
      }), console.log(`
      结果是 ${o}`)
    };
    class Log {
      constructor() {
        console.log("我的唯一工作是记录这个文本!\n")
      }
    }
    class Greeting {
      constructor(e) {
        this.sayHello(e)
      }
      sayHello(e) {
        for (let [o, t] of Object.entries(e)) console.log(`Hallo ${t}, 很高兴见到你!`)
      }
    }
    class Addition {
      constructor(e) {
        this.injectedMethod = e.dependency,
        this.injectedMethod(e.numbers)
      }
    }
    const classParams = {
      Log: "",
      Greeting: {
        name1: "Alice",
        name2: "Bob"
      },
      Addition: {
        numbers: [1, 2, 3, 4, 5],
        dependency: addNumbers
      }
    };
    const classes = {
      Log,
      Greeting,
      Addition
    };
    for (const [k, v] of Object.entries(classParams)) {
      new classes[k](v)
    }
英文:

You can put all the classes into an object and use bracket notation to access classes by name using it.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const addNumbers=e=&gt;{let o=0;e.forEach(e=&gt;{o+=e}),console.log(`
The result is ${o}`)};class Log{constructor(){console.log(&quot;My only job is to log this text!\n&quot;)}}class Greeting{constructor(e){this.sayHello(e)}sayHello(e){for(let[o,t]of Object.entries(e))console.log(`Hallo ${t}, nice to meet you!`)}}class Addition{constructor(e){this.injectedMethod=e.dependency,this.injectedMethod(e.numbers)}}const classParams={Log:&quot;&quot;,Greeting:{name1:&quot;Alice&quot;,name2:&quot;Bob&quot;},Addition:{numbers:[1,2,3,4,5],dependency:addNumbers}};

const classes = {Log, Greeting, Addition};
for (const [k, v] of Object.entries(classParams)) {
  new classes[k](v);
}

<!-- end snippet -->

答案2

得分: 1

Objects only use strings for keys

Object类只使用字符串作为键。

Unfortunately, JavaScript doesn't have support for values as keys with the Object class.
不幸的是,JavaScript不支持将值用作Object类的键。

There are, however, many options available to store classes with an argument or arguments to call them with.
然而,有许多选项可用于存储带有参数的类以及调用它们的参数。

Using an Object and eval to get the class

使用Objecteval来获取类

This is a safe usage of eval, so no need to worry about that.
这是对eval的安全使用,所以不需要担心。

Using an Array or a Map to store the class itself

使用ArrayMap来存储类本身

Using one Object to store the classes and another to store the arguments

使用一个Object来存储类,另一个来存储参数

Sidenote

附注

If your constructor has multiple parameters or no parameters, I would recommend using an array to hold the arguments and using the spread syntax (i.e. ...) to pass the arguments to the class.
如果您的构造函数有多个参数或没有参数,我建议使用数组来保存参数,并使用扩展语法(即...)将参数传递给类。

Also if you need to create multiple of the same class with different arguments, I would recommend the Array technique as shown above.
此外,如果您需要创建具有不同参数的多个相同类的实例,我建议使用上面所示的Array技术。

英文:

Objects only use strings for keys

Unfortunately, JavaScript doesn't have support for values as keys with the Object class. There are, however, many options available to store classes with an argument or arguments to call them with. Below is a non-exhaustive list of such:

Using an Object and eval to get the class

This is a safe usage of eval, so no need to worry about that.

class Example { constructor(arg) { console.log(arg) } }
const classesToGenerate = {
  Example: &#39;Hello World&#39;
}
for (const className in classesToGenerate) {
  new (eval(className))(classesToGenerate[className])
}

Using an Array or a Map to store the class itself

class Example { constructor(arg) { console.log(arg) } }
let classesToGenerate = new Map([
  [Example, &#39;Hello World!&#39;]
])
classesToGenerate.forEach((arg, Class) =&gt; {
  new Class(arg)
})

// Using an Array is barely different but probably more appropriate
classesToGenerate = [
  [Example, &#39;Hello World!&#39;]
]
classesToGenerate.forEach(([Class, arg]) =&gt; {
  new Class(arg)
})

Using one Object to store the classes and another to store the arguments

Credit goes to @Unmitigated for this technique.

class Example { constructor(arg) { console.log(arg) } }
const classesToGenerate = {
  classes: { Example },
  args: { Example: &#39;Hello World&#39; }
}
for (const className in classesToGenerate.classes) {
  new classesToGenerate.classes[className](classesToGenerate.args[className])
}

Sidenote

If your constructor has multiple parameters or no parameters, I would recommend using an array to hold the arguments and using the spread syntax (i.e. ...) to pass the arguments to the class.

Also if you need to create multiple of the same class with different arguments, I would recommend the Array technique as shown above.

huangapple
  • 本文由 发表于 2023年3月31日 03:23:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/75892204.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定