Search code examples
javascriptobjectpropertieshashtableenumerable

How to update the enumerable of an object property?


I define a object as follows:

var obj = {};
var name = "nonenumerable";
var value = "hello world";

Object.defineProperty(obj, name, {value: value,
  writable : true,
  enumerable : false,
  configurable : true
});

console.log(obj); 
//output in code snippet console: {}
//output in browser console: { nonenumerable: "hello world" }

Now i want to store the object into my local storage with

localStorage.setItem("localObj", JSON.stringify(obj));

I know that JsonObjects do not include "non enumerables", consequently my property is not stored. My problem is that i use the object as a kind of "hashtable".

var obj = {
  1: { id: 1, start: 3, end: 6 },
  2: { id: 2, start: 5, end: 8 },
  3: { id: 3, start: 2, end: 4 }
};
Object.defineProperty(obj, "all", {value: {},
  writable : true,
  enumerable : false,
  configurable : true
});
obj.all.start = 0;
obj.all.end = 10;

function setStart(id, add){
  if(add) obj[id].start += 1;
  else obj[id].start -= 1
  updateContent("start", id, obj[id].start);
}

function setAllStart(start, add){
  if(add) obj.all.start += 1;
  else obj.all.start -= 1
  updateContent("start", "all", obj.all.start);
  for(id in obj){
    obj[id].start = obj.all.start;
    updateContent("start", id, obj[id].start);
  }
}

function setEnd(id, add){
  if(add) obj[id].end += 1;
  else obj[id].end -= 1
  updateContent("end", id, obj[id].end);
}

function setAllEnd(start, add){
  if(add) obj.all.end += 1;
  else obj.all.end -= 1
  updateContent("end", "all", obj.all.end);
  for(id in obj){
    obj[id].end = obj.all.end;
    updateContent("end", id, obj[id].end);
  }
}

function updateContent(selector, id, content){
   document.querySelector("#" + selector + "-" + id).innerHTML = content;
}
.value {
  display: inline-block;
}
<div>
  AllStart:
  <button type="button" onclick="setAllStart(3, false);">-</button>
  <div id="start-all" class="value">0</div>
  <button type="button" onclick="setAllStart(3, true);">+</button>
</div>
<div>
  AllEnd:
  <button type="button" onclick="setAllEnd(3, false);">-</button>
  <div id="end-all" class="value">10</div>
  <button type="button" onclick="setAllEnd(3, true);">+</button>
</div>
<div>
  Start 1:
  <button type="button" onclick="setStart(1, false);">-</button>
  <div id="start-1" class="value">3</div>
  <button type="button" onclick="setStart(1, true);">+</button>
</div>
<div>
  End 1:
  <button type="button" onclick="setEnd(1, false);">-</button>
  <div id="end-1" class="value">6</div>
  <button type="button" onclick="setEnd(1, true);">+</button>
</div>
<div>
  Start 2:
  <button type="button" onclick="setStart(2, false);">-</button>
  <div id="start-2" class="value">5</div>
  <button type="button" onclick="setStart(2, true);">+</button>
</div>
<div>
  End 2:
  <button type="button" onclick="setEnd(2, false);">-</button>
  <div id="end-2" class="value">8</div>
  <button type="button" onclick="setEnd(2, true);">+</button>
</div>
<div>
  Start 3:
  <button type="button" onclick="setStart(3, false);">-</button>
  <div id="start-3" class="value">2</div>
  <button type="button" onclick="setStart(3, true);">+</button>
</div>
<div>
  End 3:
  <button type="button" onclick="setEnd(3, false);">-</button>
  <div id="end-3" class="value">4</div>
  <button type="button" onclick="setEnd(3, true);">+</button>
</div>

My questions:

1) Can i update the enumerable of my property to true after defineProperty ?

2) Can i step over the "nonenumerable" key if its defined as obj.all = {} in the for-loop without an if-statement?

Thank you in advance.


Solution

  • Helper function

    function load(inp) {
        var spec = function (o) {
            Object.defineProperty(o, 'all', { 
                writable: true,
                enumerable: false,
                configurable : true,
                value: o.all || {}
            });
            Object.defineProperty(o, "toString", {
                value: function () {
                    Object.defineProperty(this, 'all', { enumerable: true});
                    var ret = JSON.stringify(this);
                    Object.defineProperty(this, 'all', { enumerable: false});
                    return ret;
                }
            });
            return o;
        };
        return spec(typeof inp == "string" ? JSON.parse(inp) : inp);
    }
    

    you can initialise the object like this

    var obj = load({
        1: { id: 1, start: 3, end: 6 },
        2: { id: 2, start: 5, end: 8 },
        3: { id: 3, start: 2, end: 4 }
    });
    obj.all.start = 0;
    obj.all.end = 10;
    

    or even like this

    var obj1 = load({
        1: { id: 1, start: 3, end: 6 },
        2: { id: 2, start: 5, end: 8 },
        3: { id: 3, start: 2, end: 4 },
        all: {
            start: 0,
            end: 10
        }
    });
    

    to store it

    localStorage.setItem('testing', obj)
    

    to load it from storage

    var obj2 = load(localStorage.getItem('testing'));
    
    console.log(obj.toString() == obj2.toString());
    // true