【问题标题】:Cannot enum properties when using Object.create使用 Object.create 时无法枚举属性
【发布时间】:2013-09-20 12:17:08
【问题描述】:

我有一个类似的对象

var Profile = Object.create(null);
Object.defineProperties(Profile, {
    id: {
        value: "",
        enumerable: true
    },
    name: {
        value: "",
        enumerable: true
    },
    active: {
        value: true,
        enumerable: true
    }
});

现在我想创建一个 Profile 实例并为其指定 id 和名称,并保持活动默认为 true,所以我这样做:

var p1 = Object.create(Profile, {
    id: {
        value: "123",
        enumerable: true
    },
    name: {
        value: "hello world",
        enumerable: true
    }
});

然后我得到了一个名为 p1 的对象,但我在其中找不到“活动”

Object.getOwnPropertyNames(p1);

我也不能使用 JSON.stringify(p1) 来序列化属性“active”,但我需要属性“active”可以是可序列化的。

这是我使用 Object.create 的错误方式吗?我只想创建一个可序列化的“类”并获得它的可序列化“实例”。我该怎么做?

【问题讨论】:

  • 您的属性不可配置且不可写...
  • 为什么不只是 { id: "123", name: "hello world" } ?无论如何,JavaScript 天生就是肮脏的......
  • @EliasVanOotegem 但是p1.id 还是变成了123 而p1.name 变成了“hello world”,我不知道为什么......
  • @Virus721 因为我想要一个像“类”这样的模板来制作对象,并且它有一些默认值,我只需要更改一些与默认值不同的值然后得到一个“完整”目的。和这里一样,active不用改,我只写id和name,希望JSON.stringify()可以序列化属性“active”但不行。
  • @Sunny:因为active 属性在您的p1 对象中不存在。 You have to understand how JS resolves properties to their respective values。您在p1 上调用JSON.stringify,该对象不知道任何active 属性。直到你尝试访问p1.active JS 才会检查Object.prototype 之前的"parent" 对象,并尝试将表达式p1.active 解析为一个值。

标签: javascript object serialization ecmascript-5


【解决方案1】:

由于您使用了Object.create,您并没有真正将任何内容克隆/复制到结果对象中(您调用p1)。首先,您必须了解 JS 在访问对象属性时如何解析它们:

J [     p1.active     ]<=========================================================\ \
S p1[active] ==> JS checks instance for property divide                           | |
O  /\ ||                                                                          | |
N  || || --> property found @instance? return value-------------------------------| |
=  || ||                                                                          | |
   || ===========> p1.prototype is found: Profile, check that object              | |
N  ||      ||                                                                     | |
O  ||      ||--> Profile.active found @Profile instance, return-------------------| |
T  ||      ||                                                                     | |
   ||      ==========> Profile.prototype.active (== Object.prototype.active)      | |
J  ||          ||                                                                 | |
S  ||          ||--> property found @Object.prototype, return---------------------|_|
O  ||          ||                                                                 |=|
N  ||          =======>prototype is null, return "undefined.active"~~~~~~~~~~~~~~~|X|
   ||                                                                             \ /
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~< TypeError can't read property 'x' of undefined

基本上就是这样,会发生什么。现在调用JSON.stringify(p1) 时,JS 将转向p1 对象,并处理其属性(定义@instance 级别的属性)。 p1 对象不知道Profile 上定义了active 属性
JSON.stringify 只检查我用 JSON 标记的步骤(第一个循环), JSON 对所有其他检查(原型链)不感兴趣。 9/10,这只是Object.prototype,你不想把它串起来,现在好吗?

说实话,对于您(似乎)想要完成的事情,最简单的解决方案是:

p1 = JSON.parse(JSON.stringify(Profile));
p1.id = 123;
p1.name = 'hello world';
console.log(JSON.stringify(p1));//will show active property!

查看我上一条评论中的链接,了解有关此问题的更多详细信息

【讨论】:

  • 感谢您的解释,我了解 Object.create() 中发生了什么以及 js 如何找到“活动”。而且我认为我需要的是“实例”而不是“子类”,但是 Object.create() 只能创建“子类”,如果我想获得一个“实例”,我应该使用 new Profile() 就像我在 Tibos 中评论回答?
  • @Sunny:是的,要么创建一个新实例,要么以我上次的 sn-p 为例:JSON.parse(JSON.stringify(Profile)),这有效地复制了对象(不是方法,也不是它的原型链,而是您最终将得到一个新对象,该对象具有在@instance 级别定义的所有属性,包括active 属性)
  • 强大的图表你有 der。谢谢,这实际上是我最近遇到的问题,你的解释清楚了:)
【解决方案2】:

来自 MDN 页面上的 getOwnPropertyNames:

返回直接找到的所有属性(可枚举或不可枚举)的数组 在给定的对象上。

active 属性在 p1 的 proto 对象上,而不是在 p1 上。

您可以使用for in 构造遍历 p1 的所有属性(包括原型链上的属性)。要创建平面对象,您可以这样做:

for (var key in obj) {
  if (!obj.hasOwnProperty(key)) {
    obj[key] = obj[key];
  }
}

Object.getOwnPropertyNames: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames

for in: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in

Object.create: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create

【讨论】:

  • 似乎是个好方法,谢谢。顺便说一句,我找到了一种使用新函数创建对象的方法,例如:var Profile = function(syntax){this.id="";this.name="";this.active=false;for(var i in syntax){this[i]=syntax[i];}}new Profile({id:123, name: "abc"}),Object.create() 比 new Function 好吗?
猜你喜欢
  • 1970-01-01
  • 2016-12-11
  • 1970-01-01
  • 2022-06-18
  • 2011-02-16
  • 1970-01-01
  • 1970-01-01
  • 2019-06-12
  • 1970-01-01
相关资源
最近更新 更多