【问题标题】:How to update the enumerable of an object property?如何更新对象属性的可枚举?
【发布时间】:2017-07-12 14:53:47
【问题描述】:

我定义一个对象如下:

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" }

现在我想将对象存储到我的本地存储中

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

我知道 JsonObjects 不包括“不可枚举”,因此我的属性没有被存储。我的问题是我将该对象用作一种“哈希表”。

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>

我的问题:

1) 我可以在 defineProperty 之后将我的属性的enumerable 更新为true 吗?

2) 如果在for-loop 中定义为obj.all = {} 而没有if-statement,我可以跳过“不可枚举”键吗?

提前谢谢你。

【问题讨论】:

  • for...in 只“循环”通过枚举 - 不是吗?
  • 是的。这就是为什么我将属性“all”定义为“nonenumerable”。
  • 那么,有什么问题吗?为什么它需要“成为”可枚举的? obj.all 确实具有 helloworld! 的值 - 如果您使用 enumerable: true 创建它 - 不会追溯调用前一个循环
  • 我更新了代码sn-p。我需要一个函数来一次更改所有值并自行更改每个值。这就是为什么用enumerable: false 定义obj.all 然后我需要将它存储在localStorage 中,以使用第二页上的数据。当我回到选择页面时,我还需要再次知道“all”的值。

标签: javascript object properties hashtable enumerable


【解决方案1】:

Object.defineProperty() 也可用于修改现有属性的描述符。对于您的用例,更好的方法是序列化原始对象的副本:

var open = {};
Object.assign(open, obj);
open.all = obj.all;
localStorage.setItem("localObj", JSON.stringify(open));

【讨论】:

  • 感谢您的提示,我可以修改现有属性的描述符。不幸的是我不能使用对象的副本,因为我需要在加载对象时将对象与克隆合并。
【解决方案2】:

正如 ccprog 的回答中提到的,我可以使用 Object.defineProperty() 来修改我的对象属性。

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" }


Object.defineProperty(obj, name, {
  enumerable : true
});
console.log(obj);

【讨论】:

    【解决方案3】:

    辅助函数

    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);
    }
    

    你可以像这样初始化对象

    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;
    

    甚至像这样

    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
        }
    });
    

    存储它

    localStorage.setItem('testing', obj)
    

    从存储中加载它

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

    【讨论】:

    • 这是一个非常好的解决方案,辅助函数非常好。我已经解决了这个问题,但这与我的解决方案非常相似。
    猜你喜欢
    • 2021-11-29
    • 1970-01-01
    • 2017-03-05
    • 1970-01-01
    • 2018-12-18
    • 1970-01-01
    • 1970-01-01
    • 2010-09-10
    相关资源
    最近更新 更多