7

I am creating a game with many objects, these objects all have their own functions that get called. I have one object that does not do anything and is just for cloning, when this object is cloned everything but the functions get cloned. the x-y gets cloned as well as other this like weight and strength. but the functions don't get cloned. The method I use for cloning is this.

objects[1] = JSON.parse(JSON.stringify(objects[0]))

This is not the only clone method I have tried, but all of them gave me the same result. I expect this to clone the object from objects[0] to objects[1] with everything including functions. (they are in an array so I can execute their functions). But only everything but functions are cloned.

Here is an example I made in node.js. (I don't have the anything solid in code as I like to test if it will work before putting it all together).

var original = {}; original.a = true; original.b = null; original.c = 82; original.d = "a string LOL"; original.e = function() { console.log("everything does not work?"); } original.f = [0, "a", true, false]; console.log(original) console.log(JSON.stringify(original)); console.log(JSON.stringify(JSON.parse(JSON.stringify(original))));

6
  • 4
    You can't keep functions once converted to JSON, as JSON is a string. Commented Apr 3, 2021 at 23:42
  • @evolutionxbox the string is not important, just that the objects don't get cloned, and I showed that what I tried did not work. Commented Apr 3, 2021 at 23:45
  • 1
    What do you mean the string is not important? It's the reason why using JSON does not work... Commented Apr 3, 2021 at 23:54
  • What I mean by the string is not important is that I don't have to use JSON strings, If there was another way, I could do it. Commented Apr 4, 2021 at 4:04
  • ah I see. Hopefully the given answers will help you there Commented Apr 4, 2021 at 10:16

3 Answers 3

4

It's not possible to stringify functions using JSON.stringify. Only a subset of primitives are valid JSON. For completeness, function source code can be retrieved with toString and rebuilt with the Function constructor, but that's messy and unnecessary.

You can use Object.assign or spread syntax:

var original = {}; original.a = true; original.b = null; original.c = 82; original.d = "a string LOL"; original.e = function() { console.log("everything does not work?"); } original.f = [0, "a", true, false]; var copy = Object.assign({}, original); var spread = {...original}; copy.f = [42, 45]; spread.f = [1, 2]; copy.e(); console.log(original.f, copy.f, spread.f);

Note that this isn't a deep (recursive) copy, so if you have nested objects, you'll have a shared alias. See What is the most efficient way to deep clone an object in JavaScript? if you want to deep copy.

You also mention you "have one object that does not do anything and is just for cloning". It sounds like you want a class or constructor of some sort. Absent more information, I prefer a function that returns an object and acts as a closure on any hidden properties you might want (you could also use a traditional constructor with this as described here):

const makeFoo = () => ({ a: true, b: null, c: 82, d: "a string LOL", e: function () { console.log("everything does not work?"); }, f: [0, "a", true, false], }); const foos = [...Array(3)].map(makeFoo); foos[0].c = 42; console.log(foos);

You can parameterize some or all of these attributes with optional default values:

const makeFoo = props => { const defaults = { a: true, b: null, c: 82, d: "a string LOL", e: function () { console.log("everything does not work?"); }, f: [0, "a", true, false], }; return {...defaults, ...props}; }; const foos = [...Array(3)].map(() => makeFoo({a: false, b: 5})); foos[0].c = 42; console.log(foos);

...but I'm speculating a lot on your use case.


Lodash's _.clone() and _.cloneDeep() functions also work:

const deepObj = {x: {f: () => console.log("it worked")}}; const shallowObj = {f: () => console.log("it worked")}; _.clone(shallowObj).f(); _.cloneDeep(deepObj).x.f();
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.js"></script>

Sign up to request clarification or add additional context in comments.

Comments

2

The best option out there is the cloneDeep method offered by lodash. This will clone all primitives and all nested objects, and ofc you won't loose functions declarations

2 Comments

cloneDeep based on lodash.com/docs/4.17.15#clone, it will return empty object for functions
@MikhailZaretsky Even though the docs do say that, the behavior seems to indicate otherwise: _.cloneDeep({f: () => console.log("it worked")}).f(); works as expected. I think the docs are referring to when the argument itself is a function: console.log(_.cloneDeep(() => console.log("it worked"))); returns {}. In other words, this answer is totally valid for OP's use case.
-4

You can use the same structured clone mechanism that the HTML standard includes for sending data between realms: structuredClone

const clone = structuredClone(original); 

1 Comment

no you cannot b/c OP specifically asked for cloning an object that may have functions as values. structuredClone() will throw an error when it encounters a function.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.