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

我希望能够在对象上生成动态属性,我尝试通过创建一个函数来实现此目的,该函数接受一个输入对象,然后返回一个接受参数的函数。该参数用于设置动态属性。


我的问题是,一旦创建了该函数,我似乎不会每次都获得一个新对象,而是该函数在先前分配的对象上设置该属性。


我曾尝试重新分配对象但无济于事,我已经测试了可行的替代方案(不太理想的代码),但我想知道为什么我的初始解决方案不起作用。


/* 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 }

}


不负相思意
浏览 130回答 2
2回答

jeck猫

短篇小说这是引用同一个对象的简单问题。为了证明这一点,比较两个对象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等)的对象。然后,我操作这个克隆的对象并返回它。现在不存在操作相同引用对象的威胁。如果这有帮助,或者您需要更好的解释,请告诉我。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript