Search code examples
javascriptmergeecmascript-6ecmascript-2016

What is the fastest way in ES7 to perform a merge of an object of object of string?


I have an object that contains object that contains string.

  const userKeyframes = {
    from: {
      opacity: 1,
    },
    '40%': {
      transform: 'skew(20deg)',
      opacity: 1,
    },
    '80%': {
      transform: 'skew(-5deg)',
      opacity: 1,
    },
    to: {
      transform: 'translate3d(-100%, 0, 0) skew(10deg)',
      opacity: 0,
    },
  };

I use to do like this with ImmutableJS :

  const merge = fromJS(make(options)).mergeDeep(userKeyframes);

I have tried this (https://www.webpackbin.com/bins/-KiVy6f5eWDb44W4dXtE) but didn't worked :

  const merge = make(options);
  Object.keys(userKeyframes).forEach((key) => {
    Object.assign(merge[key], userKeyframes[key]);
  });

I don't think I wan't to keep immutableJS only for this.

What is the fastest way in ES7 to perform a merge of two of them without any third party library ?


Solution

  • The issue is that you assume merge[key] exists for all keys, but obviously this is not guaranteed. So Object.assign(merge[key], .......) might have the first argument as undefined, which does not yield the desired effect (but an error).

    Instead, create a new object for the first argument, and assign the result to merge[key]:

    Object.keys(userKeyframes).forEach((key) => {
        merge[key] = Object.assign({}, userKeyframes[key]);
    });
    

    However, the above will overwrite whatever is in merge[key] before the assignment happens. There are two alternatives you could use to deal with this differently:

    You could perform the assignment only when merge[key] does not yet exist, so that you only assign userKeyframes[key] in that case:

    Object.keys(userKeyframes).forEach((key) => {
        if (!(key in merge)) {
            merge[key] = Object.assign({}, userKeyframes[key]);
        }
    });
    

    Or, alternatively, you may want to truly merge the two objects when both already exist, meaning you want to have all the properties from userKeyframes[key], but also keep any other properties that were already in merge[key] which would get destroyed by the first solution.

    In that case, provide both merge[key] and userKeyframes[key] as 2nd and 3rd arguments to Object.assign, given that undefined values in all but the first argument do not pose a problem:

    Object.keys(userKeyframes).forEach((key) => {
        merge[key] = Object.assign({}, merge[key], userKeyframes[key]);
    });
    

    In this last piece of code, when merge[key] already had a value, its properties that do not occur in userKeyframes[key] will stay, and those that do, get overwritten with those from userKeyframes[key], as stated in the documentation on MDN:

    Later sources' properties will ... overwrite earlier ones.