【问题标题】:What is this data structure with default property and type-like object in JS?这个在 JS 中具有默认属性和类类型对象的数据结构是什么?
【发布时间】:2020-01-18 08:23:28
【问题描述】:

我注意到在一些 JS 对象中,它们具有一些特殊行为的属性。例如Sequelize中的模型对象,如果我将模型记录到控制台,我看到该对象包含_data_changed_modelOptions等属性。

但是,当访问对象本身时,_data 属性似乎是其默认属性。例如:

const userModel = UserModel.findOne(...);
console.log(userModel.email);   // this prints the email field of the record
console.log(userModel._data.dataValues.email)  // this also prints the email of the record

看来我不必从_data.dataValues 访问email。我可以直接从userModel 对象访问它。

当我打印整个对象时,我还注意到_data.dataValues 中的值被打印出来了。

有了这个:

console.log(JSON.stringify(userModel))

我会得到这个结果:

{
   name: 'John',
   email: 'john@smith.com'
}

但是有了这个:

console.log(userModel)

我会得到这个:

t {
   _data: user {   // what is that 'user'  before the object? is it a type definition?
      dataValues: {
         name: 'John',
         email: 'john@smith.com'
      }
      _previousDataValues: {
         name: 'John',
         email: 'john@smith.com'
      }
      _modelOptions: {
         ...
      }
      ...
   }
}

这看起来与通常的 JS 对象有点不同,因为它似乎有一个对象的“类型”,这些属性是“内部的”,打印出来时不可见。

起初我以为它是一个类,但我尝试打印我创建的一个类,并将输出与此模型的控制台输出进行比较,它们看起来不同。

我不经常在 JS 中看到这种数据结构。 JS 和 Node 中的这个数据结构具体是什么?与 JS 中的常规对象相比,这个“特殊”对象有什么不同和有用的地方?

【问题讨论】:

  • 可能表明该对象是一个实例的类 - 例如,有一个 class user 被调用,结果分配给 _data 属性,这是我的猜测跨度>
  • JSON.stringify(user) 将打印user.toJSON() 的结果,它可以返回任何它想要的结果。

标签: javascript node.js data-structures


【解决方案1】:

实现这些行为形式并没有什么特别之处。这可以使用Object.definePropertyObject.defineProperties 轻松完成。

这是一个例子

function Person(fName, lName) {
  this._data = {
    fName: fName,
    lName: lName
  }
  
  Object.defineProperties(this, {
    fName: {
      get : function () {
        return this._data.fName;
      },
      set: function (value) {
        this._data.fName = value;
      }
    },
    lName: {
      get : function () {
        return this._data.lName;
      },
      set: function (value) {
        this._data.lName = value;
      }
    }
  });  
}

const ratul = new Person("Ratul", "sharker");

console.log(ratul);

console.log(ratul.fName);
ratul.fName = "Ra2l";
console.log(ratul.fName);

这里enumerable 属性默认设置为false(查看定义属性文档。)如果您将其设置为true,那么它将出现在console.log(ratul) 中。

这类行为在 sequelize 中的主要用途是跟踪值的变化。直接来自Sequelize github

setDataValue(key, value) {
    const originalValue = this._previousDataValues[key];

    if (!_.isEqual(value, originalValue)) {
      this.changed(key, true);
    }

    this.dataValues[key] = value;
  }

跟踪数据值变化的最明显原因是在调用Model.save 时,然后sequelize 可以优化哪些属性/属性应该sequelize 写入db。

This is where Object.defineProperty 被使用,在refreshAttributes 中声明,从init 调用。

Object.defineProperty(this.prototype, key, attributeManipulation[key]);

【讨论】:

    猜你喜欢
    • 2010-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-06
    • 1970-01-01
    • 1970-01-01
    • 2019-07-21
    相关资源
    最近更新 更多