Javascript objects for the php guy :(

Hi all,

So here i am, a php developer that is use to using arrays in all sorts of ways all the time, i was like okay javascript’s array’s will most likely have the same or close to syntax, so start coding…one day later and a little bold spot on my head from scratching so much :frowning: i’m admitting defeat and asking the fine people here for help.

I start explaining here
I started to code my multidimensional array as i would in php (i know every language has it’s own ways)

What i did was:

// $ <--- i use this to know it's a variable
array[$category][$subCate] = $subCateName;

Then i learned that arrays only use numerical values for keys and what i want is a object which you can change the key to your liking :smile: so i changed my array to a object {} but then i learned that you can’t just go and make the object as i did above, you need to do something like this because i’m using variables for keys

array[$category] = $subCate;
array[$category][$subCate] = $subCateName;

i do the above because i want to have the keys set dynamically and you can’t for some reason have a variable in object brackets because it will be used literal :frowning: why javascript??

This is the object i need and i have no clue what to do to get it so. Little side note, as you can see subCate has multiple children so i did try to use push to push the other objects in but i learned that push is only for arrays as well

{
    categoryName1:{
        subCatName1:{
            someKey: Val,
            someOtherKey: Val
        }
    }
}

Does anyone have some advice for me to get my objects to be like the above? how would i construct this?

Thank you all for ready :slight_smile:

The way that you approach this entirely depends on the information that you are building it from.

You could do it slowly, such as like this:

var myObject = {};
myObject[$category] = {};
myObject[$category][$subcate] = {};
myObject[$category][$subcate]['someKey'] = 'Val';
myObject[$category][$subcate]['someOtherKey'] = 'Val';

The above can be simplified a lot too, depending on what you know you’re working with.

You can also generate the object using JSON notation:

function createObj($category, $subCate, val1, val2) {
    return JSON.parse(
        '{"' + $category + '":' +
            '{"' + $subCate + '":' +
                '{"' + '"someKey":' + val1 + ',' +
                    '"someOtherKey":' + val2 +
                '}' +
            '}' +
        '}'
    );
}
createObj('someCategory', 'subcategory', 3, 5);

The above could also be done as a single line in the function:

function createObj($category, $subCate, val1, val2) {
    return JSON.parse('{"' + $category + '":{"' + $subCate + '":{"' + '"someKey":' + val1 + ',' + '"someOtherKey":' + val2 + '}' + '}' + '}');
}
createObj('someCategory', 'subcategory', 3, 5);

But I’m sure you’ll agree that it’s easier to figure out what the previous code example is doing.

There are also techniques that can be used to add the object information on to an already existing object. How these things are done depends entirely on the needs of the situation.

2 Likes

Hi @Paul_Wilkins thank you for clearing that first one up for me :slight_smile: i always set the value as the next child element not just a object, thank you for clearing that. I’m really wondering how one would go about making the first code snippet shorter seeing as it’s the closest thing to php style syntax.

I really like the JSON approach you have, but to be honest it looks like a lot of typing compared to the first one, haha don’t get me wrong i really don’t mind the amount i typing (for goodness sake we are coders :smiley: ) i just mean that there must be a shorthand way of getting the job done, i know it depends on the objects i need to create so i will give you a small example of the information i’m working with.

I have a page which a user can fill in information on hunting, and i’m going to save the information with ajax because i need to add input fields dynamically for the user to put more info in if they want. I’m constructing one big object with all the sections of the page so when i have the JSON array in php i can easily process the information, Example of objects needed

{
    basic-info:{
        starting-time: 0103
        date: 02102015
    },
    locations:
        a-location-name1:{
            weather:{
                1304: some-weather-info,
                14:20: some-weather-info
            }
            animals:{
                animal-type1:{
                    male: 1,
                    female: 1,
                    times:{
                        male: 1340,
                        female: 1400
                    }
                }
            }
        }
    }
}

There is more information that needs to go in but that is a rough idea of what i’m working with, i’m first building the main object and then constructing the smaller objects, that is why i also wanted to know how to append objects to each other, i guess if i’m not mistaken i can do something like mainObj['locations'] = locationObj;

Thank you so much for the help so far.

JavaScript does not automatically add parent pieces of the structure for you, so you need to add things with some trepidation - always making sure that the pathway down there exists first, before adding more properties.

So for example, if you were wanting to add to the a-location-name1 section, you would need to make sure that other parts leading to it exist, before adding your weather data.

if (!mainObj['locations']) {
    mainObj['locations'] = {};
}
if (!mainObj['locations']['a-location-name1']) {
    mainObj['locations']['a-location-name1'] = {};
}
if (!mainObj['locations']['a-location-name1']['weather']) {
    mainObj['locations']['a-location-name1']['weather'] = {};
}
mainObj['locations']['a-location-name1']['weather']['1304'] = '12345';

Fortunately though, we can use the || operator to act as a default operator, so that if something looks falsy, we can assign something else instead.

mainObj['locations'] = mainObj['locations'] || {};

The above will leave ‘basic-info’ untouched if it already exists. If it doesn’t though, it will start it off as an empty object.

I’m not sure if there’s an easier way than that, when it comes to multiply nested locations either.

mainObj['locations'] = mainObj['locations'] || {};
mainObj['locations']['a-location-name1'] = mainObj['locations']['a-location-name1'] || {};
mainObj['locations']['a-location-name1']['weather'] = mainObj['locations']['a-location-name1']['weather'] || {};
mainObj['locations']['a-location-name1']['weather']['1304'] = '12345';

We can though reduce the number of levels of indirection, by assigning a reference to a variable.

var currentLocation;
mainObj['locations'] = mainObj['locations'] || {};
mainObj['locations']['a-location-name1'] = mainObj['locations']['a-location-name1'] || {};

currentLocation = mainObj['locations']['a-location-name1'];
currentLocation['weather'] = currentLocation['weather'] || {};
currentLocation['weather']['1304'] = '12345';

Which even though we are referring to the currentLocation variable, will end up updating with the main object.

Even though it looks like a lot for this one example, it only takes around 18 lines to replicate the same sort of technique for the full JSON example object, over at http://jsfiddle.net/kqyx6gv3/

It is also possible to make the programming side of it easier too, by passing some info to a function and having that do the checks for you, before it adds that info to the main object.

3 Likes

After you have those details in place, you can then work on the more interesting parts, which look like this:

updateBasicInfo(mainObj, '0103', '02102015');
addWeather(mainObj, 'a-location-name1', '1304', '12345');
addWeather(mainObj, 'a-location-name1', '1420', '67890');
addAnimalSighting(mainObj, 'a-location-name1', 'animal-type1', 'male', '1340');
addAnimalSighting(mainObj, 'a-location-name1', 'animal-type1', 'female', '1400');

You can explore the updated code at: http://jsfiddle.net/pmw57/kqyx6gv3/1/

1 Like

So to be clear the whole structruing you’re creating is to insure that there is nothing that will break the chain of objects and the above quote tests to see if there is a object already set and if not then create that part of the chain.

I like the function idea you have but i think that my code does not need it because it will not be used on other areas, but still great to have that idea if ever i need to reuse the code somewhere else :smile:

Thank you so much for all the help and enlightening me to how objects work Paul :+1: i think i will be able to handle the objects now :grin: but if i get stuck again i’m coming back and demanding a refund :yum:

Yes, spot on. Without that, if you try to access a non-existing property, the code will stop executing with a TypeError.

Uncaught TypeError: Cannot set property 'starting-time' of undefined

The functions are not necessarily to allow reuse. JavaScript is a functional language. Functions are cheap, and make it easier for us coders to understand what is going on.

I think for example that you may find one of these code samples easier to follow than the other:

var location;
mainObj['locations'] = mainObj['locations'] || {};
mainObj['locations']['a-location-name1'] = mainObj['locations']['a-location-name1'] || {};
location = mainObj['locations']['a-location-name1'];
location['weather'] = location['weather'] || {};
location['weather']['1304'] = 12345;

The below code is an easier-to-understand version of the above code.

function getLocation(mainObj, locationName) {
    mainObj['locations'] = mainObj['locations'] || {};
    mainObj['locations'][locationName] = mainObj['locations'][locationName] || {};
    return mainObj['locations'][locationName];
}
function getWeather(location) {
    location['weather'] = location['weather'] || {};
    return location['weather'];
}
function addWeather(mainObj, locationName, time, weatherInfo) {
    var location = getLocation(mainObj, locationName),
        weather = getWeather(location);
    weather[time] = weatherInfo;
}
addWeather(mainObj, 'a-location-name1', '1304', '12345');

The second code example does take a few more lines, but the trade-off in terms of enhanced code clarity makes it a no-brainer. Especially if you don’t want to be scratching your head for a few hours when 6 months or a few years time has passed.

After all, as Uncle Bob says when it comes to refactoring your code and extracting functions, “Extract till you just can’t extract any more. Extract till you drop.”

1 Like

I’ve updated the jsfiddle code to reflect the above advice. http://jsfiddle.net/pmw57/kqyx6gv3/3/

Here’s the current state of the code example.

<div id="json"></div>
var mainObj = {};

function updateBasicInfo(mainObj, startingTime, date) {
    mainObj['basic-info'] = mainObj['basic-info'] || {};
    mainObj['basic-info']['starting-time'] = startingTime;
    mainObj['basic-info']['date'] = date;
}

function getLocation(mainObj, locationName) {
    mainObj['locations'] = mainObj['locations'] || {};
    mainObj['locations'][locationName] = mainObj['locations'][locationName] || {};
    return mainObj['locations'][locationName];
}

function getWeather(location) {
    location['weather'] = location['weather'] || {};
    return location['weather'];
}

function addWeather(mainObj, locationName, time, weatherInfo) {
    var location = getLocation(mainObj, locationName),
        weather = getWeather(location);
    weather[time] = weatherInfo;
}
function getAnimal(location, animalType) {
    location['animals'] = location['animals'] || {};
    location['animals'][animalType] = location['animals'][animalType] || {};
    return location['animals'][animalType];
}

function getAnimalTimes(animal) {
    animal['times'] = animal['times'] || {};
    return animal['times'];
}
function addAnimalTime(animal, sex, time) {
    var animalTimes = getAnimalTimes(animal);
    animal[sex] = (animal[sex] || 0) + 1;
    animal['times'][sex] = animal['times'][sex] || [];
    animal['times'][sex].push(time);
}

function addAnimalSighting(mainObj, locationName, animalType, sex, time) {
    var location, animal;
    location = getLocation(mainObj, locationName);
    animal = getAnimal(location, animalType);
    addAnimalTime(animal, sex, time);
}

updateBasicInfo(mainObj, '0103', '02102015');
addWeather(mainObj, 'a-location-name1', '1304', '12345');
addWeather(mainObj, 'a-location-name1', '1420', '67890');
addAnimalSighting(mainObj, 'a-location-name1', 'animal-type1', 'male', '1340');
addAnimalSighting(mainObj, 'a-location-name1', 'animal-type1', 'female', '1400');

document.querySelector('#json').innerHTML = JSON.stringify(mainObj, null, 4);
1 Like

Oh okay i see your point, thank you for clearing it up for me with the functions, i didn’t see the whole reason for using a function but looking at it now it seems to be much easier to get back to after some time away from it :slight_smile: plus the nice thing about the function layout is if we want to add another section to our object we can simply copy, past and change some naming and we are good to go with a new section of objects

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.