为了账号安全,请及时绑定邮箱和手机立即绑定

返回现有对象的函数设置属性的函数。JS

返回现有对象的函数设置属性的函数。JS

不负相思意 2021-08-20 16:46:34
我希望能够在对象上生成动态属性,我尝试通过创建一个函数来实现此目的,该函数接受一个输入对象,然后返回一个接受参数的函数。该参数用于设置动态属性。我的问题是,一旦创建了该函数,我似乎不会每次都获得一个新对象,而是该函数在先前分配的对象上设置该属性。我曾尝试重新分配对象但无济于事,我已经测试了可行的替代方案(不太理想的代码),但我想知道为什么我的初始解决方案不起作用。/* Returns a function which will assign a 'required' property to all objects within the given object */const generateSchemaField = obj => {    obj = Object.assign({}, obj);    return function(required = false) {        Object.keys(obj).forEach(key => {            Object.assign(obj[key], {                required,            });        });        return obj;    };};/* The way the above function would be invoked*/const userEmailUsingGenerateSchemaField = generateSchemaField({    user_email: {        type: 'string',        description: 'A user email',    },});/* The below function does not encounter the same problem */const userEmailNotUsingGenerateSchemaField = function(required = false) {    let obj = {        user_email: {            type: 'string',            description: 'A user email',        },    };    Object.keys(obj).forEach(key => {        Object.assign(obj[key], {            required,        });    });    return obj;}; let firstResultUsing = userEmailUsingGenerateSchemaField();let secondResultUsing = userEmailUsingGenerateSchemaField(true);console.log(firstResultUsing);console.log(secondResultUsing);预期产出{  user_email: { type: 'string', description: 'A user email', required: false }}{  user_email: { type: 'string', description: 'A user email', required: true }}实际{  user_email: { type: 'string', description: 'A user email', required: true }}{  user_email: { type: 'string', description: 'A user email', required: true }}
查看完整描述

2 回答

?
jeck猫

TA贡献1909条经验 获得超7个赞

短篇小说


这是引用同一个对象的简单问题。


为了证明这一点,比较两个对象


console.log(firstResultUsing === secondResultUsing)

你会看到它打印true证明它们都引用了同一个对象。


向下滚动以获取解决方案!


长篇大论


在这一行:


const userEmailUsingGenerateSchemaField = generateSchemaField({

  user_email: {

    type: 'string',

    description: 'A user email',

  },

})

这里发生的事情是你的generateSchemaField函数正在返回一个函数,它有一个闭包,obj它只是


{

  user_email: {

    type: 'string',

    description: 'A user email',

  },

}

现在在这一行:


const firstResultUsing = userEmailUsingGenerateSchemaField()

该函数被评估并返回修改后的对象


{

  user_email: {

    type: 'string',

    description: 'A user email',

    required: false

  },

}

记住返回的对象仍然具有相同的引用 obj


现在再次在线:


const secondResultUsing = userEmailUsingGenerateSchemaField(true)

这里发生的事情obj是修改了相同的引用对象,并使用属性更新了它required: true


这就是为什么当你们console.log都在展示时,required: true因为他们都引用了同一个对象。


解决方案


const generateSchemaField = obj => {

  return function(required = false) {

    const objClone = JSON.parse(JSON.stringify(obj));

    Object.keys(objClone).forEach(key => {

      Object.assign(objClone[key], {

        required,

      });

    });

    return objClone;

  };

};

让我们分解一下。我删除了,obj = Object.assign({}, obj);因为它没有任何好处。这似乎是一条多余的线。


接下来,我做了一个深克隆的obj。记住Object.assign不会工作,因为它只是创建一个浅拷贝/克隆,在这里它不会工作,因为键email_id持有对对象的引用。请注意,深度克隆JSON.parse(JSON.stringify(obj))仅适用于具有 JSON 安全值(无函数undefined等)的对象。


然后,我操作这个克隆的对象并返回它。现在不存在操作相同引用对象的威胁。


如果这有帮助,或者您需要更好的解释,请告诉我。


查看完整回答
反对 回复 2021-08-20
  • 2 回答
  • 0 关注
  • 129 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信