考虑在浅克隆只有一个原始属性的标准对象时所采取的基于 ES3 的步骤:
- 创建一个新的空对象。
- 为该空对象添加一个键。
- 为该键分配一个值。
- 返回对象。
这些步骤可以使用手动功能完成,如下所示:
function es3ShallowClone(incomingObj){
var cloneOfObj = {}; // 1
for(var key in incomingObj)
cloneOfObj[key] = incomingObj[key]; // 2 and 3
return cloneOfObj; // 4
}
使用 es3ShallowClone 函数,您可以这样进行克隆:
var obj = {a:"b"};
var newObj = es3ShallowClone(obj);
Object.assign( {}, obj ) 是(自 2009 年 ES5 发布以来)一种生成与 es3ShallowClone 相同的输出的内置方式:
let newAssignedObj = Object.assign( {}, obj );
Object.assign 仅复制可枚举的属性,并且 Object.assign 不传输原型。
///////////////////////////////////////
更多“权力:”
如果您希望克隆具有不可枚举属性的其他标准对象,则需要使用 Object.getOwnPropertyDescriptors 和 Object.defineProperty;可能与 Object.create 一致。
手动浅克隆具有不可枚举属性的标准对象时所采取的基于 ES5 的步骤:
- 创建一个新的空对象。
- 从传入对象中获取包含描述符的数组。
- “浅克隆”描述符,然后应用描述符克隆您的空对象。
- 返回对象。
例如:
function es5ShallowClone(incomingObj){
let cloneOfObj = {}; // 1
let descriptors = Object.getOwnPropertyDescriptors(incomingObj); // 2
for(var key in descriptors)
Object.defineProperty( cloneOfObj, key, descriptors[key] ); // 3
return cloneOfObj; // 4
}
首先,让我们创建一个具有不可枚举属性的示例对象:
制作描述符:
let someDescriptor = {
'a': {
value: 'b',
writable: true,
configurable:true,
enumerable:false
};
创建一个对象并将描述符分配给它:
let obj2 = Object.create( {}, someDescriptor );
然后克隆它:
let newObj2 = es5ShallowClone(obj2);
代替 es5ShallowClone,您可以改为:
let newObjToo = Object.create( {}, Object.getOwnPropertyDescriptors(obj2) );
///////////////////////////////////////
为了获得更多“力量”,您还需要转移原型;请注意,我对“转移”一词的使用有点笨拙,因为原型并没有离开原始对象……两个对象最终都引用了同一个原型。
我们需要对 es5ShallowClone 函数进行的唯一更改是第 1 步;以便它根据传入对象的原型创建一个对象:
function es5ShallowCloneWithPrototype(incomingObj){
let cloneOfObj = new incomingObj.constructor(); // 1
let descriptors = Object.getOwnPropertyDescriptors(incomingObj); // 2
for(var key in descriptors)
Object.defineProperty( cloneOfObj, key, descriptors[key] ); // 3
return cloneOfObj; // 4
}
首先,我们将定义一个构造函数,它可以创建一个具有不可枚举属性和原型的对象:
function objConstructor(){
let someDescriptor = {
'a': {
value: 'b',
writable: true,
configurable:true,
enumerable:false
};
}
let returnObj = Object.create( {}, someDescriptor );
}
objConstructor.prototype.extraInfo = “javascript rocks”;
然后我们将使用该构造函数来创建一个花哨的新对象:
let constructedObj = new objConstructor();
现在,我们可以克隆该ConstructedObj,在它的所有荣耀中,因此:
let newCon = es5ShallowCloneWithPrototype(constructedObj);
或者,我们可以使用 ES5 带给我们的内置魔法来克隆我们的ConstructedObj:
let newCon2 = Object.create(
Object.getPrototypeOf(constructedObj),
Object.getOwnPropertyDescriptors(constructedObj)
);
///////////////////////////////////////
希望这个简短的概述有助于澄清描述符的处理方式与克隆过程中处理常规 ol 对象的方式不同。
要仔细查看 ES3 或自 ES5 以来可用于克隆函数的信息,并查看在枚举期间如何呈现 getter 和对象值,请查看以下 codepen 链接,然后打开浏览器的控制台。 .. 您可能想清除控制台,然后再次单击运行按钮以查看捕获信息的最佳表示。 PS:使用 ES3 风格的克隆,setter 的名称被添加到你的克隆中并保持 undefined 的值。使用 ES5 样式的克隆时,如果 getter 和 setter 引用了不可克隆器可访问范围内的值,则这些 getter 和 setter 可能会导致错误。)
https://codepen.io/Ed_Johnsen/pen/GRmjajr
所有的好东西。