I have a code that generates how many users I wanted to create in an array.
let x;
const collection = {
count: 2,
array: [],
create: function(ind) {
this.array.push({
name: "user " ind,
alert: function() {
alert(this.name);
}
});
}
};
for(let i = 0; i < collection.count; i ) {
collection.create(i);
};
When I tried to convert it to string,
x = JSON.stringify(collection.array);
console.log(x);
It just shows this. It doesn't save the function inside the object. Which means, I can't call the user to broadcast the user name itself.
'[{"name":"user0"},{"name":"user1"}]'
Is it even possible to convert this array with functions in it to string with just JavaScript?
CodePudding user response:
Taking into account two comments of mine ...
Instead of transporting redundant functional overhead like suggested by an answer via e.g.
'[{ "name": "user 1", "alertStr": "function() { console.log(this.name); }" }]'
per object, the receiving side should parse the plain object data and add the functional part right after via e.g map ...
function logName () { console.log(this.name); } const itemList = JSON .parse(data) .map(item => ({ ...item, logName }));
And how about deserializing via
JSON.parse
then? The result is an array with two objects where each object features analertStr
property with the redundant string value of'function() { console.log(this.name); }'
. How does this help the OP without having to use aneval
based approach (either directly viaeval
or by parsing andnew Function( ... )
)? In addition, I considerFunction.prototype.toString
not a reliable method for the suggested purpose of saving a function's implementation.
.., I want to draw the OP's attention to the replacer
parameter/function of JSON.stringify
and the reviver
parameter/function of JSON.parse
.
The next provided example code has a more educational purpose, and any production code should try to avoid this solution by navigating around and/or solving the OP's real problem.
// slightly improved OP example code
function logName() {
console.log(this.name);
}
const collection = {
count: 2,
array: [],
create: function(idx) {
this.array.push({
name: `user ${ idx }`,
logName,
});
},
};
for (let i = 0; i < collection.count; i ) {
collection.create(i);
};
console.log({
collectionArray: collection.array,
});
collection.array[0].logName();
collection.array[1].logName();
console.log({
plainlyStringified: JSON.stringify(collection.array),
});
// serializing with a map/index based approach for function implementations
const functionImplementationIndex = {
logName: ['console.log(this.name);'],
//total: ['a', 'b', 'return a b;'],
}
function serializeFunction(key, value) {
if (typeof value === 'function') {
value = {
isFunction: true,
newFuncArgs: functionImplementationIndex[key] ?? [],
};
}
return value;
}
const serializedArrayData =
JSON.stringify(collection.array, serializeFunction);
console.log({ serializedArrayData });
// deserializing/parsing again
function deserializeFunction(key, value) {
if (
value.hasOwnProperty('isFunction')
&& (value.isFunction === true)
) {
value = new Function(...(value.newFuncArgs ?? []));
}
return value;
}
const deserializedArray =
JSON.parse(serializedArrayData, deserializeFunction);
console.log({ deserializedArray });
console.log({
collectionArray: collection.array,
});
deserializedArray[0].logName();
deserializedArray[1].logName();
.as-console-wrapper { min-height: 100%!important; top: 0; }
CodePudding user response:
Not really. But you can do a some trick.
You can stringify function with .toString()
method
For example
fn = () => 'hello world';
fn.toString(); // "() => 'hello world'"
So you can add this "hack" to array:
const collection = {
count: 2,
array: [],
create: function(ind) {
const name = "user " ind;
const alert = function() { console.log(this.name); };
const alertStr = alert.toString();
this.array.push({ name, alert, alertStr });
}
};
collection.create(1);
collection.create(2);
collection.array[0].alert()
collection.array[1].alert()
console.log(JSON.stringify(collection.array));
.as-console-wrapper { max-height: 100% !important; top: 0; }