我有一个对象.我想将其复制为对象,以便更改不修改.我意识到复制从内置 JavaScript 对象派生的对象将导致额外的、不需要的属性。这不是问题,因为我正在复制我自己的文本构造对象之一。x
y
y
x
如何正确克隆 JavaScript 对象?
网友回答:
如果你在对象中不使用s,functions,undefined,regExp或Infinity,一个非常简单的行是:Date
JSON.parse(JSON.stringify(object))
const a = {
string: 'string',
number: 123,
bool: false,
nul: null,
date: new Date(), // stringified
undef: undefined, // lost
inf: Infinity, // forced to 'null'
}
console.log(a);
console.log(typeof a.date); // Date object
const clone = JSON.parse(JSON.stringify(a));
console.log(clone);
console.log(typeof clone.date); // result of .toISOString()
这适用于包含对象、数组、字符串、布尔值和数字的所有类型的对象。
另请参阅这篇关于浏览器结构化克隆算法的文章,该算法在向工作人员和从工作人员发布消息时使用。它还包含用于深度克隆的功能。
网友回答:
有一个新的JS标准称为结构化克隆。它适用于许多浏览器(请参阅我可以使用吗)。
const clone = structuredClone(object);
对 JavaScript 中的任何对象执行此操作并不简单或直接。您将遇到错误地从对象的原型中选取属性的问题,这些属性应保留在原型中,而不是复制到新实例中。例如,如果要向 添加一个方法,如某些答案所示,则需要显式跳过该属性。但是,如果还有其他您不知道的附加方法或其他中间原型,该怎么办?在这种情况下,您将复制不应复制的属性,因此您需要使用该方法检测不可预见的非本地属性。clone
Object.prototype
Object.prototype
hasOwnProperty
除了不可枚举的属性之外,当您尝试复制具有隐藏属性的对象时,还会遇到更棘手的问题。例如, 是函数的隐藏属性。此外,对象的原型使用 属性 引用,该属性也是隐藏的,并且不会被遍历源对象的属性的 for/in 循环复制。我认为可能是特定于Firefox的JavaScript解释器,在其他浏览器中可能有所不同,但是您了解了图片。并非所有内容都是可枚举的。如果您知道隐藏属性的名称,则可以复制它,但我不知道有什么方法可以自动发现它。prototype
__proto__
__proto__
寻求优雅解决方案的另一个障碍是正确设置原型继承的问题。如果源对象的原型是 ,那么只需创建一个新的通用对象即可,但如果源的原型是 的某个后代,那么您将缺少使用该过滤器跳过的原型中的其他成员,或者这些成员在原型中,但首先不可枚举。一种解决方案可能是调用源对象的属性来获取初始复制对象,然后复制属性,但这样您仍然不会获得不可枚举的属性。例如,对象将其数据存储为隐藏成员:Object
{}
Object
hasOwnProperty
constructor
Date
function clone(obj) {
if (null == obj || "object" != typeof obj) return obj;
var copy = obj.constructor();
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr];
}
return copy;
}
var d1 = new Date();
/* Executes function after 5 seconds. */
setTimeout(function(){
var d2 = clone(d1);
alert("d1 = " + d1.toString() + "nd2 = " + d2.toString());
}, 5000);
的日期字符串将比 的日期字符串晚 5 秒。使一个与另一个相同的一种方法是调用该方法,但该方法特定于类。我不认为这个问题有一个防弹的通用解决方案,尽管我很高兴错了!d1
d2
Date
setTime
Date
当我必须实现一般的深度复制时,我最终妥协了,假设我只需要复制一个普通的、、或。最后 3 种类型是不可变的,所以我可以执行浅拷贝而不必担心它会改变。我进一步假设包含在或也将是该列表中的 6 种简单类型之一。这可以通过如下代码实现:Object
Array
Date
String
Number
Boolean
Object
Array
function clone(obj) {
var copy;
// Handle the 3 simple types, and null or undefined
if (null == obj || "object" != typeof obj) return obj;
// Handle Date
if (obj instanceof Date) {
copy = new Date();
copy.setTime(obj.getTime());
return copy;
}
// Handle Array
if (obj instanceof Array) {
copy = [];
for (var i = 0, len = obj.length; i < len; i++) {
copy[i] = clone(obj[i]);
}
return copy;
}
// Handle Object
if (obj instanceof Object) {
copy = {};
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]);
}
return copy;
}
throw new Error("Unable to copy obj! Its type isn't supported.");
}
上面的函数将充分适用于我提到的 6 种简单类型,只要对象和数组中的数据形成树结构即可。也就是说,对象中对相同数据的引用不超过一个。例如:
// This would be cloneable:
var tree = {
"left" : { "left" : null, "right" : null, "data" : 3 },
"right" : null,
"data" : 8
};
// This would kind-of work, but you would get 2 copies of the
// inner node instead of 2 references to the same copy
var directedAcylicGraph = {
"left" : { "left" : null, "right" : null, "data" : 3 },
"data" : 8
};
directedAcyclicGraph["right"] = directedAcyclicGraph["left"];
// Cloning this would cause a stack overflow due to infinite recursion:
var cyclicGraph = {
"left" : { "left" : null, "right" : null, "data" : 3 },
"data" : 8
};
cyclicGraph["right"] = cyclicGraph;
它将无法处理任何 JavaScript 对象,但只要您不假设它只适用于您扔给它的任何东西,它就足以满足许多目的。
网友回答:
在 ECMAScript 6 中,有 Object.assign 方法,它将所有可枚举的自身属性的值从一个对象复制到另一个对象。例如:
var x = {myProp: "value"};
var y = Object.assign({}, x);
但请注意,这是一个浅层副本 – 嵌套对象仍作为引用进行复制。
模板简介:该模板名称为【如何正确克隆 JavaScript 对象?】,大小是暂无信息,文档格式为.编程语言,推荐使用Sublime/Dreamweaver/HBuilder打开,作品中的图片,文字等数据均可修改,图片请在作品中选中图片替换即可,文字修改直接点击文字修改即可,您也可以新增或修改作品中的内容,该模板来自用户分享,如有侵权行为请联系网站客服处理。欢迎来懒人模板【JavaScript】栏目查找您需要的精美模板。