【问题标题】:Spread syntax returns unexpected object传播语法返回意外对象
【发布时间】:2019-07-23 21:03:54
【问题描述】:

我正在使用节点并且我已经使用过。

babel 节点

    "start": "nodemon --exec babel-node --presets es2015 index.js"

我的传播语法没有按预期工作。这是我的代码。

   export const login = async (parentValue, { email, password }) => {
  try {
    const user = await User.findOne({
      email
    });
    console.log(user);

    if (!user.authenticateUser(password)) {
      throw new Error('Wrong password');
    }
    const dummyObject = {
      ...user
    };
    console.log({ dummyObject });
    return { ...user };
  } catch (e) {
    console.log(e);
    throw new Error(e.message);
  }
};

我使用console.log(user) 的那一行,它工作正常。 它返回 { id: xxx, name: xxxx }

我在console.log(dummyObject) 上收到了意想不到的数据; 这就是我得到的。

{ jojo: 
{ '$__': 
      InternalCache {
        strictMode: true,
        selected: {},
        shardval: undefined,
        saveError: undefined,
        validationError: undefined,
        adhocPaths: undefined,
        removing: undefined,
        inserting: undefined,
        saving: undefined,
        version: undefined,
        getters: {},
        _id: 5c798295f53323b34cabf1ca,
        populate: undefined,
        populated: undefined,
        wasPopulated: false,
        scope: undefined,
        activePaths: [Object],
        pathsToScopes: {},
        cachedRequired: {},
        session: undefined,
        ownerDocument: undefined,
        fullPath: undefined,
        emitter: [Object],
        '$options': [Object] },
     isNew: false,
     errors: undefined,
     _doc: 
      { _id: 5c798295f53323b34cabf1ca,
        fullName: 'sarmad',
        password: '$2a$10$c.XDX75ORXYA4V/hUXWh.usVf2TibmKfY.Zpu3cpTssFaYvsGyhte',
        email: 'sarmad@gmail.com',
        createdAt: 2019-03-01T19:05:57.454Z,
        updatedAt: 2019-03-01T19:05:57.454Z,
        __v: 0 },
     '$init': true } }

我做错了吗?从技术上讲,它应该返回用户对象 注意:我不想使用 Object.assign

【问题讨论】:

  • 不,它看起来非常好,到目前为止,这是您的数据对象的副本,而不仅仅是您期望的用户对象;)我在这里猜测传播运算符全部取用,而原始用户对象仅显示要枚举的几个属性
  • 我在创建用户时使用了相同的方法。它在那里工作。可能 user.create 和 user.find 的返回数据不同?

标签: javascript node.js spread-syntax


【解决方案1】:

看起来您正在使用 mongoose,并且看起来您正在使用扩展运算符获取 mongoose 对象属性。您需要转换为 JSON 以摆脱这些。

尝试: const dummyObject = { ...user.toJSON() };

您还可以: const dummyObject = { ...user.toObject() };

^ 这可能是首选方式

另一种解决方案是在进行查询时只请求一个普通对象。例如:

Schema.findOne(query).lean()

这将返回一个普通对象而不是猫鼬对象。

【讨论】:

  • 完美:),我可以知道发生这种情况的原因吗?创建用户时没有发生。
  • 我不太清楚 Mongoose 的内部结构,但有件事告诉我,当你传播 user 时,你也在传播其他隐藏的属性。您的 user 对象具有这些属性,但它们很可能隐藏在 console.log 中,或者可能 mongoose 会覆盖 console.log 对 mongoose 对象的作用。
  • 您的解决方案有效。现在只有一个问题。它返回了 _id 并且我的 graphql 现在无法识别它,无论如何。那是别的东西。
  • 那是因为它可能不再是ObjectId 类型,而是一个字符串。您可以通过获取 ObjectId 类型来解决此问题:const { ObjectId } = mongoose.Types;,然后包装 _id:const dataToGraphQL = ObjectId(dummyObject._id),或者您尝试获取它。
  • 谢谢 :) 这是一个非常有用的信息
【解决方案2】:

你会得到不同的日志,因为 mongoose 使用自定义检查功能

在节点中试试这个:

const obj = {
  [Symbol.for('nodejs.util.inspect.custom')]() {
    return "totally not an object";
  }
}

console.log(obj); // "totally not an object"

由于 mongoose inspect 是在对象的原型上定义的,因此在您使用 ... 时不会复制它,因为 spread 只复制对象自己的属性。

class Obj {
  [Symbol.for('nodejs.util.inspect.custom')]() {
    return "totally not an object";
  }
}

const obj = new Obj();
const obj2 = { ...obj };


console.log(obj); // "totally not an object"
console.log(obj2); // {}

您可以通过为复制的对象设置原型来修复它:

Reflect.setPrototypeOf(obj2, Reflect.getPrototypeOf(obj))

但由于您正在处理自定义对象,因此不应真正使用对象扩展。传播仅对 POJO 是安全的。否则你可能很容易陷入麻烦(使用隐藏的 props、getter、setter 和原型地狱)

https://repl.it/repls/ToughModestInstructionset

https://github.com/Automattic/mongoose/blob/master/lib/document.js#L2853:L2869

https://nodejs.org/api/all.html#util_util_inspect_custom

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-01
    • 2023-03-03
    • 2016-04-14
    • 2021-12-14
    相关资源
    最近更新 更多