如何更新对象属性的可枚举?

Posted

技术标签:

【中文标题】如何更新对象属性的可枚举?【英文标题】: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”的值。 【参考方案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

【讨论】:

这是一个非常好的解决方案,辅助函数非常好。我已经解决了这个问题,但这与我的解决方案非常相似。

以上是关于如何更新对象属性的可枚举?的主要内容,如果未能解决你的问题,请参考以下文章

用来枚举属性的对象工具函数

可枚举属性和不可枚举属性(for...in循环和Objec.keys()和Object.getOwnPropertyNames())

Object.defineProperty()讲解

遍历对象属性

Object.keysObject.getOwnPropertyNames区别

与枚举类型的属性的可解码一致性