Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to merge JavaScript class instance with object?

I want to merge the properties/values of an object with a class instance. (I'm not sure what the correct terminology is in JS, but the example should clarify)

My attempts were with the spread syntax. See below.

I have a File-instance:

const files = listOfFilesFromDragNdrop();
let file = files[0];

console.log(file)

Outputs something like:

File(2398)
lastModified: 1530519711960
lastModifiedDate: Mon Jul 02 2018 10:21:51 GMT+0200
name: "my_file.txt"
preview: "blob:http://localhost:8080/6157f5d5-925a-4e5d-a466-24576ba1bf7c"
size: 2398
type: "text/plain"
webkitRelativePath: ""

After this is added, I use FileReader.readAsText() to obtain the contents, and wrap it in an object like:

contentObject = getFileContentFromFile()
console.log(contentObject)

Will output something like:

{ 
    preview: "blob:http://localhost:8080/6157f5d5-925a-4e5d-a466-24576ba1bf7c",
    content: "Lorem ipsum some text here." 
}

I would like to end up with a merged object like:

{ 
    // "preview" is the key used to map files and content
    preview: "blob:http://localhost:8080/6157f5d5-925a-4e5d-a466-24576ba1bf7c",

    // "text" is the new field with the content from contentObject
    text: "Lorem ipsum some text here." 

    // The other fields are from the File instance
    name: "my_file.txt",
    size: 2398,
    type: "text/plain",
    lastModified: 1530519711960,
    // ...        
}

What I first tried was:

const mergedObject = {
    ...file,
    text: contentObject.content
}

and similarily (aware that text key would become content) I tried

const mergedObject = {
    ...file,
    ...contentObject
}

But, Then I only get the contentObject fields, i.e. the mergedObject is similar to contentObject. Interestingly, if I do

const mergedObject = {
    ...file
}

the mergedObject is a File instance. I assume that the spread operator does not work for class instances in the same way as it does for objects? How can I achieve a merged object?

More info that is non-essential

  • The FileReader is implemented in a redux middleware and dispatches a new action with the { preview: '1234..ef', text: 'Lorem ipsum'} object as payload after it has completed the read.
  • I'm mapping the content to the file with the preview-field, and want to return the merged object in a "files"-reducer with something like: return files.map(file => file.preview !== payload.preview? file: {...file, text: payload.content}
like image 695
Thomas Fauskanger Avatar asked Jul 10 '18 16:07

Thomas Fauskanger


People also ask

Can we merge two objects in JavaScript?

JavaScript Merge Objects To merge objects into a new one that has all properties of the merged objects, you have two options: Use a spread operator ( ... ) Use the Object. assign() method.

How do you join two objects in JavaScript?

The easiest way to merge two objects in JavaScript is with the ES6 spread syntax / operator ( ... ). All you have to do is insert one object into another object along with the spread syntax and any object you use the spread syntax on will be merged into the parent object.

How do I merge two objects in Node JS?

You should use "Object. There's no need to reinvent the wheel for such a simple use case of shallow merging. The Object. assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object. It will return the target object.


3 Answers

To merge a class instance and an object, in ES6, you can use Object.assign() to merge all the properties in object and maintain the original prototype for class instance. Spread operator only merge all the properties but not prototypes.

In you case, try:

const mergedObject = Object.assign(file, contentObject)

Remember in this case your original file object will be changed.

like image 170
Jiaqi Guo Avatar answered Sep 22 '22 08:09

Jiaqi Guo


You may just have to do something like this...

const mergedObject = {
  lastModified: file.lastModified,
  lastModifiedDate: file.lastModifiedDate,
  name: file.name,
  size: file.size,
  type: file.type,
  webkitRelativePath: file.webkitRelativePath,
  text: contentObject.content,
  preview: contentObject.preview,
}

You could write a utility function to pull the pseudo properties from the file instance:

// Error is a like File with a pseudo property named message
let error = new Error('my error message')
error.status = 404;

const pick = (objectLike, properties) =>
    properties.reduce(
        (acc, key) => {
            acc[key] = objectLike[key];
            return acc;
        },
        {}
    );

const contentObject = {
    content: 'content text',
    preview: 'http://url.io',
};

const mergedObject = {
  ...pick(error, Object.getOwnPropertyNames(error)),
  ...contentObject,
}
console.log(JSON.stringify(mergedObject));

Lodash has a pick function you could use for this.

like image 25
Doug Coburn Avatar answered Sep 22 '22 08:09

Doug Coburn


Spread syntax like loops iterates over enumerable properties. And as you can see the code below shows that name property of a File object is not enumerable. So the only way to get those properties is one by one.

document.querySelector('input').addEventListener('change', e => {
  const file = e.target.files[0];
  console.log(file.propertyIsEnumerable('name'));
});
<input type="file">
like image 20
Hikmat G. Avatar answered Sep 21 '22 08:09

Hikmat G.