0

I want to create a class based on this object structure:

var ourStorage = {
"variableItem1":    {
    "drawer": ""
  },
"variableItem2": {
    "top drawer": {
      "folder1": "",
      "folder2": "harhar"
    },
    "bottom drawer": ""
  }
};

var accessStr = 'variableItem2'
var drawerPart = 'top drawer'
console.log(ourStorage[accessStr][drawerPart].folder2)

Basically, I want to be able to access the object contents via this style since I will be working a lot on parameter modifications:

ourStorage[accessStr][drawerPart].folder2

So my questions are:

  1. How do I convert this to class while maintaining this kind of structure? Is it possible?

  2. If I want to insert another item/object (e.g. variableItem3) - how do I do that?

  3. If I also want to insert another item/object on the deeper level (e.g. middle drawer), how do I also do that?

Thanks much!!

1
  • Why do you want a class? Is it because you want multiple instances of objects of this structure? Commented Feb 19, 2020 at 5:08

3 Answers 3

1

There are 2 options by which you can do this.

Option1: initializing the class, by passing in the required object as param

class Storage 
{
  constructor(init)
  {
    return init;
}
}

let ourStorage = new Storage({
    "variableItem1":   {
        "drawer": ""
      },
    "variableItem2": {
        "top drawer": {
          "folder1": "",
          "folder2": "harhar"
        },
        "bottom drawer": ""
      }
    });

var accessStr = 'variableItem2'
var drawerPart = 'top drawer'
console.log(ourStorage[accessStr][drawerPart].folder2);

Option 2: Initializing the object inside the constructor of the class

class Storage 
{
  constructor(init)
  {
    return {
    "variableItem1":   {
        "drawer": ""
      },
    "variableItem2": {
        "top drawer": {
          "folder1": "",
          "folder2": "harhar"
        },
        "bottom drawer": ""
      }
    };
}
}

let ourStorage = new Storage();

var accessStr = 'variableItem2'
var drawerPart = 'top drawer'
console.log(ourStorage[accessStr][drawerPart].folder2);
Sign up to request clarification or add additional context in comments.

1 Comment

This helps. Thanks!
0

There are a number of ways you can turn that into a class, but if you want to interact with it as if it's json (dot or bracket notation) then I'd say keep it as json and just make a class for interacting with the stored structure.

In the snippet, I made a storage class that let's you pass in json as a staring structure.

we then give this class 2 methods: get and update.

update will let you slap in any new node, wherever you want (you could add a new variableItem5 with drawers, folders, cabinets and wardrobes with as many nested nodes as you want)

then with the get method you can use the bracket notation like you're looking for:

console.log(os.get[accessStr][drawerPart]);

var ourStorage = {
"variableItem1":    {
    "drawer": ""
  },
"variableItem2": {
    "top drawer": {
      "folder1": "",
      "folder2": "harhar"
    },
    "bottom drawer": ""
  }
};

var accessStr = 'variableItem2'
var drawerPart = 'top drawer'

class OurStorage{
    constructor(startingStorage = {}){
        this.storage = startingStorage;
    }
    get get(){
        return JSON.parse(JSON.stringify(this.storage));
    }
    update(store = {}){
        this.storage = $.extend(true, this.storage, store);
    }
}

var os = new OurStorage(ourStorage);
console.log(os.get[accessStr]);
console.log(os.get[accessStr][drawerPart]);
os.update({"variableItem2": {
    "secretBananaFolder":{"id":"bananas"}
}});

console.log(os.get[accessStr]);

os.update({"variableItem3": {
    "top drawer": {
      "folder1": "",
      "folder2": "Awesome!"
    },
    "bottom drawer": ""
}});

  
accessStr = "variableItem3";
 
console.log(os.get[accessStr][drawerPart]);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Comments

0

One option is to create a "Model" class that has a data property which stores all values assigned to it. Use a get/set/unset API to modify the data properties. Use a parse method to get a plain object representation of the model. This allows you to create nested models.

If you are creating an application I recommend creating an API rather than accessing properties directly on the data model. The syntax may seem a little bit longer, but in the long run if you need to perform data transformations it will be easier to add methods to the class. As it stands with your initial approach, if you want to add other methods to the class then you risk overwriting them with actual data. Better to have a data property that stores all the values. Otherwise, you would not necessarily need to create a class, you could just use a plain object as you are doing.

https://jsfiddle.net/cnu6ryab/

Class

const Model = class {
  constructor() {}
  get data() {
    if(!this._data) this._data = {}
    return this._data
  }
  setDataProperty(key, value) {
    if(!this.data[key]) {
      Object.defineProperties(this.data, {
        ['_'.concat(key)]: {
          configurable: true,
          writable: true, 
          enumerable: false,
        },
        [key]: {
          configurable: true,
          enumerable: true,
          get() { return this['_'.concat(key)] },
          set(value) { this['_'.concat(key)] = value }
        },
      })
    }
    this.data[key] = value
    return this
  }
  unsetDataProperty(key) {
    if(this.data[key]) {
      delete this.data[key]
    }
    return this
  }
  get() {
    if(arguments[0]) return this.data[arguments[0]]
    return Object.entries(this.data)
      .reduce((_data, [key, value]) => {
        _data[key] = value
        return _data
      }, {})
  }
  set() {
    if(arguments.length === 2) {
      this.setDataProperty(arguments[0], arguments[1])
    } else if(
      arguments.length === 1 &&
      !Array.isArray(arguments[0]) &&
      typeof arguments[0] === 'object'
    ) {
      Object.entries(arguments[0]).forEach(([key, value]) => {
        this.setDataProperty(key, value)
      })
    }
    return this
  }
  unset() {
    if(arguments[0]) {
      this.unsetDataProperty(arguments[0])
    } else {
      Object.keys(this.data).forEach((key) => {
        this.unsetDataProperty(key)
      })
    }
    return this
  }
  parse(data = this.data) {
    return Object.entries(data).reduce((_data, [key, value]) => {
      if(value instanceof Model) {
        _data[key] = value.parse()
      } else {
        _data[key] = value
      }
      return _data
    }, {})
  }
}

Usage

let model = new Model()
// Add a property
model.set('a', 1)
console.log(model.get())

/*
{
  "a": 1
}
*/

// Add multiple properties
model.set({
  'b': 2,
  'c': { a: 1, b: 2, }
})
console.log(model.get())
/*
{
  "a": 1,
  "b": 2,
  "c": {
    "a": 1,
    "b": 2
  }
}
*/

// Replace a property
model.set({
  a: ['meh', 'heh',]
})
console.log(model.get())
/*
{
  "a": [
    "meh",
    "heh"
  ],
  "b": 2,
  "c": {
    "a": 1,
    "b": 2
  }
}
*/

// Remove a single properties
model.unset('a')
console.log(model.get())
/*
{
  "b": 2,
  "c": {
    "a": 1,
    "b": 2
  }
}
*/

// Remove all properties
model.unset()
console.log(model.get())
/*
{}
*/

// Add another property
model.set('a', 2354234)

// Create a nested model
let nestedModel = new Model()
nestedModel.set('nestedValue', 35234534254)
model.set('nestedModel', nestedModel)
console.log(model.parse())
/*
{
  "a": 2354234,
  "nestedModel": {
    "nestedValue": 35234534254
  }
}
*/

// Update the nested model
model.get('nestedModel').set('someNewValue', 'asdfasgaerwkjghak')
console.log(model.parse())
/*
{
  "a": 2354234,
  "nestedModel": {
    "nestedValue": 35234534254,
    "someNewValue": "asdfasgaerwkjghak"
  }
}
*/

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.