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

标签 javascript node.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 }
}

最佳答案

短篇小说

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

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

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 不会工作,因为它只是创建一个浅拷贝/克隆,在这里它不会工作,因为 key email_id 持有一个对一个对象的引用。 请注意,使用 JSON.parse(JSON.stringify(obj)) 的深度克隆仅适用于具有 JSON 安全值的对象(无函数或 undefined 等... ).

然后,我正在操纵这个克隆的对象并将其返回。 现在没有操纵相同引用对象的威胁。

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

关于javascript - 返回现有对象的函数设置属性的函数。 JS,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57183398/

相关文章:

javascript - jQuery循环插件切换到另一个选项卡后停止滑动

node.js - Mongoose pre.save() 异步中间件未按预期工作

node.js - 如何使用 bash 查看 process.env 的内容?

javascript - 错误 : spawn npm ENOENT

javascript - Arduino yun vs tessel vs espruino

javascript - 选择没有特定属性的跨度,然后添加从另一个文件托管的 o​​nclick 函数

javascript - 如何避免延迟反模式

javascript - JS 将对象添加到数组

javascript - 调用 something.then(Promise.reject) 结果错误,为什么简写不起作用

javascript - 对对象数组中的项目进行分组和排序