Home > Back-end >  Can't get JavaScript function to return values to itself without overriding previous results
Can't get JavaScript function to return values to itself without overriding previous results

Time:01-25

I have a function...

function createDatabase(data){  
    items = {};
    for (field in data){
        if (typeof data[field] == "object"){
            items.field = createDatabase(data[field]);
        } else {
            topic = data[field]
            items[field] = topic;
        }
    };
    return items;
}

And I call it with...

result = {"fields": createDatabase(jsonData)};
console.log(result);

My problem is that the result is only ever the final result of the recursive function calls. So the output is, for example...

{
  fields: {
    '0': 'Red',
    '1': 'White',
    '2': 'Blue'
  }
}

But red, white and blue don't appear until the end of a 3,000 line file. What I'm aiming for is to get a sort of replicated version of the original JSON file, with embedded documents and all. I'll be doing something else obviously, but I'm trying to nail this iterative process first. It's like every time the code runs, it overwrites what was there before.

I'd like this line below to add on the results from another function call to an object:

items.field = createDatabase(data[field]);

EDIT

The start of my JSON file looks like this:

{
"Applied Sciences": {
    "Agriculture": {
        "Agricultural Economics": [
            "Agricultural Environment And Natural Resources",
            "Developmental Economics",
            "Food And Consumer Economics",
            "Production Economics And Farm Management"
            ],
        "Agronomy": [
            "Agroecology",
            "Biotechnology",
            "Plant Breeding",
            "Soil Conservation",
            "Soil Science",
            "Theoretical Modeling"
            ],

I am hoping to make the output of my code basically resemble this. Once I get this working, at each stage, I want to add some stuff to each item to build a database schema with, but I can't get past this first part. All I end up with is the final array of the final object at the bottom of the file. I have changed ".field" to "[field]" in the function, but this still doesn't help.

CodePudding user response:

The scope is the current context of execution in which values and expressions are "visible" or can be referenced. (https://developer.mozilla.org/en-US/docs/Glossary/Scope)

function createDatabase(data){  
    const items = {};
    for (field in data){
        if (typeof data[field] == "object"){
            items.field = createDatabase(data[field]);
            // Not sure if it should be items[field]
        } else {
            const topic = data[field]
            items[field] = topic; 
           // Can be written as items[field] = data[field]
        }
    };
    return items;
}

Difference

function createDatabase(data){  
    items = {}; // Resets globalThis variable - items
    for (field in data){
        if (typeof data[field] == "object"){
            items.field = createDatabase(data[field]);
            
        } else {
            topic = data[field] // Resets globalThis variable - topic
            items[field] = topic;
        }
    };
    return items;
}

The variable items isn't declared for the function scope because there is no modifier such as var, let or const. This defaults to the global object which is window. The statement items={} always executes as window.items={}.

CodePudding user response:

Object and Array cloning

Since it seems you need to clone a value of any type you need a function that will first understand what's the type of the passed value and then will behave accordingly.

Before saying anything it could be worthwhile reminding that there's a native function to clone objects in javascript using structuredClone

https://developer.mozilla.org/en-US/docs/Web/API/structuredClone

Anyway since you might be interested to get into the internals to add your logics, this example could be a boilerplate to begin with.

Here in this demo you have such function as getCopy that will return a new Array or a new Object if the target is an array or an object; in the first case iterating over all its items and pushing each value into the new array as the value returned from a recursive call to getCopy, and in the second case iterating over all its own properties and pushing them in the new object as the value returned from a recursive call to getCopy.

In case the target is nor Array nor Object the value will not be cloned and returned as is.

In the demo I console.log the cloned object to show that it will behave independently from the original object even if it was changed in the meanwhile.

There are some things to be aware of before using it. I'm taking for granted that the only object type you'll encounter will be a properties bag. Otherwise it will behave incorrectly if having values like Date for example.

Here How do I correctly clone a JavaScript object? there's a much more in depth coverage of the topic.

JSON !== object

It's common to confuse JSON with actual objects. JSON stands for Javascript Object Notation and it's just a serialization format while an object is a real object in memory.

So a json string is something like const json = '{prop: "value"}' while const obj = {prop: "value"} is the object itself

const data = {
  "Applied Sciences": {
    "Agriculture": {
      "Agricultural Economics": [
        "Agricultural Environment And Natural Resources",
        "Developmental Economics",
        "Food And Consumer Economics",
        "Production Economics And Farm Management"
      ],
      "Agronomy": [
        "Agroecology",
        "Biotechnology",
        "Plant Breeding",
        "Soil Conservation",
        "Soil Science",
        "Theoretical Modeling"
      ]
    }
  }
};

//returns a deep clone of target
const getCopy = (target) => {  
  //if target is Array
  //!!!Array is also instanceof Object so it appears before in the chain
  if (target instanceof Array) {
    const copy = [];
    for (item of target) {
      copy.push(getCopy(item));
    }
    return copy;
  }
  //if target is Object  
  if (target instanceof Object) {
    const copy = {};
    for ([propName, propValue] of Object.entries(target)) {
      copy[propName] = getCopy(propValue);
    }
    return copy;
  }  
  //otherwise return the target as is
  return target;
}

const copy = getCopy(data);

//changing a property on the original data to see if the clone is affected or not
data['Applied Sciences']['Agriculture']['Agronomy'][0] = "CHANGED";

//echoing both the cloned object and the original data
console.log(copy);
console.log(data);

  • Related