在 JSON.stringify 期间获取原型中定义的动态 属性

get dynamic property defined in prototype during JSON.stringify

我在原型对象中定义了一个可枚举的 属性,并希望它在我将原型对象转换为 JSON 时出现。

我的第一个想法是将它设置为 JSON 但是因为我真的不想之后将它保留在对象中所以我将不得不或多或少地在函数中克隆整个对象并且设置必要的 属性.

重新定义目标对象中的 属性 并仅代理当前对象的上下文似乎也不是一个选项,因为我不能真正使用 applycall 获取动态属性时。

到目前为止,我能提出的可行解决方案似乎需要大量代码,而且不够灵活和简洁,所以我想知道是否有解决此任务的最佳实践。

这里有一个例子,它看起来有点合成,但我相信它仍然传达了这个想法:

function ProjectFolder() {
  this.files = [];
  Object.defineProperty(this, 'size', {enumerable: true, get: function() {
    return this.files.length;
  }});
}

function GithubProjectFolder() {
  this.files = ['.gitignore', 'README.md'];
}
GithubProjectFolder.prototype = new ProjectFolder();

var project1 = new ProjectFolder();
JSON.stringify(project1);
// output:  {"files":[],"size":0}
// size is present

var project = new GithubProjectFolder();    
JSON.stringify(project);
// output:  {"files":[".gitignore","README.md"]}
// size is absent

I'll have to more or less clone the whole object in the function and set the necessary property.

是的,这没有任何问题。这就是 .toJSON 应该工作的方式:

ProjectFolder.prototype.toJSON = function toJSON() {
    var obj = {};
    for (var p in this) // all enumerable properties, including inherited ones
        obj[p] = this[p];
    return obj;
};

不过,还有两点我想说明:

  • 当文件夹的 size 已经编码在 files 数组的长度中时,它实际上不需要单独存储在 JSON 中。这些冗余数据似乎是多余的,并且会混淆反序列化。除非有什么需要这个 属性 存在,否则我建议简单地忽略它。
  • ProjectFolder 中,.size 是每个实例自己的 属性 - 在 GithubProjectFolder 中不是。这表明you're doing inheritance wrong。更好:

    function GithubProjectFolder() {
      ProjectFolder.call(this);
      this.files.puhs('.gitignore', 'README.md');
    }
    GithubProjectFolder.prototype = Object.create(ProjectFolder.prototype);
    

    如果您单独解决这个问题,size 将出现在您的 project.

  • 的序列化中