1

I would like to know if it's possible to avoid defining properties in a factory function. I tried using destructuring and arguments.

Let's me explain myself better. Let's suppose we have the following factory function:

const create_game = (name, artist, release) => 
  ({
    name,
    artist,
    release,
    load() {
      console.log('Loading game...')
    }
  })

I already used a destructuring technique, called property value shorthand, so I don’t have to repeat myself for property assignments.

name: name,

My question is if I can go further doing some kind of magic similar to this:

const create_game = (name, artist, release) => 
  ({
    ...args,
    load() {
      console.log('Loading game...')
    }
  })

Is it possible?

Chumpocomon
  • 661
  • 1
  • 6
  • 12
  • 1
    instead of using 3 arguments, use 1 (an object) like so `(params) => ({...params, load() {console.log('loading')}})` – AngelSalazar May 19 '20 at 22:06

2 Answers2

1

If you convert your arguments to an object, you can do this:

const create_game = attributes => 
  ({
    ...attributes,
    load() {
      console.log('Loading game...')
    }
  })

create_game({ name: '...', artist: '...', release: '...' })

Otherwise, you can use this hack to get function parameter names and do magic, if you want future readers of your code to scratch their heads. Look at this monstrosity:

var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
var ARGUMENT_NAMES = /([^\s,]+)/g;
function getParamNames(func) {
  var fnStr = func.toString().replace(STRIP_COMMENTS, '');
  var result = fnStr.slice(fnStr.indexOf('(')+1, fnStr.indexOf(')')).match(ARGUMENT_NAMES);
  if(result === null)
     result = [];
  return result;
}

function create_game (name, artist, release) {
  const _arguments = arguments 
  const argumentNames = getParamNames(create_game)

  const argsObject = argumentNames.reduce(
    (acc, argName, index) => ({ ...acc, [argName]: _arguments[index] }), {})

  return ({
    ...argsObject,
    load() {
      console.log('Loading game...')
    }
  })
}

create_game('asdf', 'qwer', 'uiop')
// => {name: "asdf", artist: "qwer", release: "uiop", load: ƒ}
ichigolas
  • 7,595
  • 27
  • 50
0

Is it possible?

No, because the js engine doesn't have the argument names available.

I think this is overkill, but you can "inject" the array of names and reduce it using the ...rest object.

const create_game = (names, ...args) => 
  (Object.assign({
    load() {
      console.log('Loading game...')
    }
  }, names.reduce((a, c, i) => Object.assign(a, {[c]: args[i]}), {})));
  
console.log(create_game(["name", "artist", "release"], "Ele", "Foo", "Bar"))
Community
  • 1
  • 1
Ele
  • 33,468
  • 7
  • 37
  • 75
  • 'No, because the js engine doesn't have the argument names available.' Not correct, the engine does offer a way (a horrible hack) to know the argument names. – ichigolas May 19 '20 at 23:12
  • @nicooga Can you explain to me, how horrible is that hack? is the hack is related to your answer, let me tell you the engine, in that case, knows the names because you're declaring, otherwise it's not possible. – Ele May 20 '20 at 08:22
  • Of course. How could anyone know the name of something, if no one gave it a name? I do not understand your point. – ichigolas May 21 '20 at 23:07