3

The first way:

const logger = () => ({
  log(msg) {
    console.log(msg)
  }
})
class Component {
  constructor() {
    Object.assign(this, logger())
  }
}

The second way:

const logger = {
  log(msg) {
    console.log(msg)
  }
}
class Component {
  constructor() {
    Object.assign(this, logger)
  }
}

Now, what is the difference between the two?

const obj = new Component()
obj.log('what is the difference?')

I see the first piece of pattern multiple times in people's code. Is there a name for this IFFE-ish pattern? In what scenario do we use this pattern?

I simplified it to the second piece of code, still works. It seems to work the same?

Andreas
  • 21,535
  • 7
  • 47
  • 56
Tom
  • 15,781
  • 14
  • 69
  • 111
  • 3
    Unless a property of the object gets changed, the first `logger` doesn't make a whole lot of sense I think, just declaring an object literal (2nd way) is easier – CertainPerformance Dec 18 '19 at 12:19
  • 2
    I'd call that a *factory function*. – Jonas Wilms Dec 18 '19 at 12:20
  • 1
    The difference will be that the former `logger` object will always be unique. Might be important if you modify it somewhere. – deceze Dec 18 '19 at 12:22
  • 1
    I'm not sure what you're asking--the difference is clear; are you asking *why* you'd use the first one? You might use a form of the first one to pass in an argument unique to a logger instance, like the name of the component it's used in, which could be closed over and used in all subsequent logging messages. – Dave Newton Dec 18 '19 at 12:27

2 Answers2

4

The first example creates a new object (and a new log function) every time an instance of Component is created.

The second example reuses the same one each time (so any changes to log would be shared).

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
  • No it wouldn't return the same object in any case. Since the constructor is not using the object itself, but the return of Object assign – Guilherme Lúcio Dec 18 '19 at 12:36
  • 1
    @GuilhermeLúcio — Which copies all the properties, including the `log` function, so any changes to `log` would be shared. – Quentin Dec 18 '19 at 13:31
1

In short, they will yield the same result on your example. That's because Object.assign itself will always return a new object, which is composed by the objects you passed as arguments. In both cases you are calling it with the same arguments, being the case you are invoking a factory function to create the object, or if you are passing a simple object literal, so any mutation on the instance objects will not affect the original object.

Object.assign documentation

The difference being that on the second case, the log function is shared across all instances, that's because running a factory function will create a new object every time, therefore a new function, but having it inside of an object and referencing the object will return the same function.

The first approach would be useful if you had to pass in arguments to create a dynamic object based on them. The danger of this approach is that because you are returning a new function every time, you could potentially be creating some performance issues depending how many instances you intend to create. You could solve this problem by having a third option

const log = (msg) => console.log(msg);

const logger = () => ({ log });

class Component {
  constructor() {
    Object.assign(this, logger())
  }
}
  • This ignores that you can do `this.log.foo = 'bar'`, which modifies the `log` function. That still makes a difference. – deceze Dec 18 '19 at 12:41
  • That would happen regardless the approach, you can still modify the instance object as you wish. That wouldn't modify the original object because Object.assign returned a copy of it. The original object is not touched by changing anything on the instance in both cases – Guilherme Lúcio Dec 18 '19 at 12:47
  • `Object.assign` only "copies" the `{}` wrapper. It does not copy the `log` function itself! In that case it *does* make a difference whether that `log` function is a singleton or not. – deceze Dec 18 '19 at 12:49