如何在Angular中复制对象并丢失其引用?
使用AngularJS,我可以使用angular.copy(object)
,但我在Angular中使用它时会出现一些错误。
EXCEPTION:ReferenceError:
angular
未定义
答案 0 :(得分:156)
假设您使用的是ES6,则可以使用var copy = Object.assign({}, original)
。适用于现代浏览器;如果您需要支持旧浏览器,请查看此polyfill
<强>更新强>
使用TypeScript 2.1+,可以使用ES6速记对象扩展符号:
const copy = { ...original }
答案 1 :(得分:44)
直到我们有更好的解决方案,您可以使用以下内容:
duplicateObject = <YourObjType> JSON.parse(JSON.stringify(originalObject));
编辑:澄清
请注意:上述解决方案仅仅是一个快速修复的衬垫,在Angular 2正在积极开发时提供。我希望我们最终可能得到相当于angular.copy()
。因此,我不想编写或导入深度克隆库。
此方法在解析日期属性时也存在问题(它将成为字符串)。
请不要在生产应用中使用此方法。仅在您的实验项目中使用它 - 您正在学习Angular 2的那些项目。
答案 2 :(得分:14)
使用lodash作为bertandg指示。 angular不再使用此方法的原因是因为angular 1是一个独立的框架,并且外部库经常遇到角度执行上下文的问题。 Angular 2没有那个问题,所以请使用你想要的任何库。
答案 3 :(得分:14)
对于浅复制,您可以使用Object.assign这是一个ES6功能
let x = { name: 'Marek', age: 20 };
let y = Object.assign({}, x);
x === y; //false
请勿将其用于深度克隆
答案 4 :(得分:14)
深层复制具有嵌套对象的对象的替代方法是使用lodash的cloneDeep方法。
对于Angular,你可以这样做:
使用npm install lodash
或cloneDeep
安装lodash。
在您的组件中,导入import * as cloneDeep from 'lodash/cloneDeep';
...
clonedObject = cloneDeep(originalObject);
并使用它:
{{1}}
它只为您的构建添加了18kb,非常值得获益。
如果您需要更多地了解使用lodash的cloneDeep的原因,我还写了article here。
答案 5 :(得分:8)
如果要复制类实例,也可以使用Object.assign,但是需要将新实例作为第一个参数(而不是{})传递:
<div id="logmodal" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal contenido-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title"><i class="fa fa-user-circle"> </i> Login</h4>
</div>
<div class="modal-body">
<%--<form id="Conectar">--%>
<div class="form-group">
<input type="text" id="txtUsuario" class="form-control" runat="server" placeholder="Usuario Web"/>
</div>
<div class="form-group">
<input type="password" id="txtPassword" class="form-control" runat="server" placeholder="Password"/>
</div>
<div class="form-group">
<asp:Button ID="Button1" runat="server" Text="LOGIN" CssClass="btn btn-default" OnClick="Button1_Click" />
</div>
<%--</form>--%>
<asp:Label ID="LblErrors" runat="server" Text=""></asp:Label>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal" >Cerrar</button>
</div>
</div>
</div>
</div>
答案 6 :(得分:5)
正如其他人已经指出的那样,使用lodash或下划线可能是最好的解决方案。但如果您不需要其他任何库,您可以使用以下内容:
function deepClone(obj) {
// return value is input is not an Object or Array.
if (typeof(obj) !== 'object' || obj === null) {
return obj;
}
let clone;
if(Array.isArray(obj)) {
clone = obj.slice(); // unlink Array reference.
} else {
clone = Object.assign({}, obj); // Unlink Object reference.
}
let keys = Object.keys(clone);
for (let i=0; i<keys.length; i++) {
clone[keys[i]] = deepClone(clone[keys[i]]); // recursively unlink reference to nested objects.
}
return clone; // return unlinked clone.
}
这就是我们决定做的事情。
答案 7 :(得分:1)
您可以像克隆数组一样
this.assignCustomerList = Object.assign([], this.customerList);
然后像克隆对象一样
this.assignCustomer = Object.assign({}, this.customer);
答案 8 :(得分:0)
我需要此功能只是构成我的应用程序“模型”(原始后端数据转换为对象)。因此,我最终使用了Object.create(从指定的原型创建新对象)和Object.assign(对象之间的复制属性)的组合。需要手动处理深层副本。我为此创建了a gist。
答案 9 :(得分:0)
发生了同样的问题,并且不想使用任何插件进行深度克隆:
static deepClone(object): any {
const cloneObj = (<any>object.constructor());
const attributes = Object.keys(object);
for (const attribute of attributes) {
const property = object[attribute];
if (typeof property === 'object') {
cloneObj[attribute] = this.deepClone(property);
} else {
cloneObj[attribute] = property;
}
}
return cloneObj;
}
信用:I made this function more readable,请在下面检查其功能的例外情况
答案 10 :(得分:0)
我已经创建了一个用于Angular 5或更高版本的服务,它使用angularjs的angular.copy ()
基础,对我来说很好用。此外,还有其他功能,例如isUndefined
等,希望对您有所帮助。
像任何优化一样,很高兴知道。问候
import { Injectable } from '@angular/core';
@Injectable({providedIn: 'root'})
export class AngularService {
private TYPED_ARRAY_REGEXP = /^\[object (?:Uint8|Uint8Clamped|Uint16|Uint32|Int8|Int16|Int32|Float32|Float64)Array\]$/;
private stackSource = [];
private stackDest = [];
constructor() { }
public isNumber(value: any): boolean {
if ( typeof value === 'number' ) { return true; }
else { return false; }
}
public isTypedArray(value: any) {
return value && this.isNumber(value.length) && this.TYPED_ARRAY_REGEXP.test(toString.call(value));
}
public isArrayBuffer(obj: any) {
return toString.call(obj) === '[object ArrayBuffer]';
}
public isUndefined(value: any) {return typeof value === 'undefined'; }
public isObject(value: any) { return value !== null && typeof value === 'object'; }
public isBlankObject(value: any) {
return value !== null && typeof value === 'object' && !Object.getPrototypeOf(value);
}
public isFunction(value: any) { return typeof value === 'function'; }
public setHashKey(obj: any, h: any) {
if (h) { obj.$$hashKey = h; }
else { delete obj.$$hashKey; }
}
private isWindow(obj: any) { return obj && obj.window === obj; }
private isScope(obj: any) { return obj && obj.$evalAsync && obj.$watch; }
private copyRecurse(source: any, destination: any) {
const h = destination.$$hashKey;
if (Array.isArray(source)) {
for (let i = 0, ii = source.length; i < ii; i++) {
destination.push(this.copyElement(source[i]));
}
} else if (this.isBlankObject(source)) {
for (const key of Object.keys(source)) {
destination[key] = this.copyElement(source[key]);
}
} else if (source && typeof source.hasOwnProperty === 'function') {
for (const key of Object.keys(source)) {
destination[key] = this.copyElement(source[key]);
}
} else {
for (const key of Object.keys(source)) {
destination[key] = this.copyElement(source[key]);
}
}
this.setHashKey(destination, h);
return destination;
}
private copyElement(source: any) {
if (!this.isObject(source)) {
return source;
}
const index = this.stackSource.indexOf(source);
if (index !== -1) {
return this.stackDest[index];
}
if (this.isWindow(source) || this.isScope(source)) {
throw console.log('Cant copy! Making copies of Window or Scope instances is not supported.');
}
let needsRecurse = false;
let destination = this.copyType(source);
if (destination === undefined) {
destination = Array.isArray(source) ? [] : Object.create(Object.getPrototypeOf(source));
needsRecurse = true;
}
this.stackSource.push(source);
this.stackDest.push(destination);
return needsRecurse
? this.copyRecurse(source, destination)
: destination;
}
private copyType = (source: any) => {
switch (toString.call(source)) {
case '[object Int8Array]':
case '[object Int16Array]':
case '[object Int32Array]':
case '[object Float32Array]':
case '[object Float64Array]':
case '[object Uint8Array]':
case '[object Uint8ClampedArray]':
case '[object Uint16Array]':
case '[object Uint32Array]':
return new source.constructor(this.copyElement(source.buffer), source.byteOffset, source.length);
case '[object ArrayBuffer]':
if (!source.slice) {
const copied = new ArrayBuffer(source.byteLength);
new Uint8Array(copied).set(new Uint8Array(source));
return copied;
}
return source.slice(0);
case '[object Boolean]':
case '[object Number]':
case '[object String]':
case '[object Date]':
return new source.constructor(source.valueOf());
case '[object RegExp]':
const re = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
re.lastIndex = source.lastIndex;
return re;
case '[object Blob]':
return new source.constructor([source], {type: source.type});
}
if (this.isFunction(source.cloneNode)) {
return source.cloneNode(true);
}
}
public copy(source: any, destination?: any) {
if (destination) {
if (this.isTypedArray(destination) || this.isArrayBuffer(destination)) {
throw console.log('Cant copy! TypedArray destination cannot be mutated.');
}
if (source === destination) {
throw console.log('Cant copy! Source and destination are identical.');
}
if (Array.isArray(destination)) {
destination.length = 0;
} else {
destination.forEach((value: any, key: any) => {
if (key !== '$$hashKey') {
delete destination[key];
}
});
}
this.stackSource.push(source);
this.stackDest.push(destination);
return this.copyRecurse(source, destination);
}
return this.copyElement(source);
}
}
答案 11 :(得分:0)
我以及您都遇到了angular.copy和angular.expect工作的问题,因为它们在不添加某些依赖项的情况下不会复制对象或创建对象。我的解决方法是这样:
copyFactory = (() ->
resource = ->
resource.__super__.constructor.apply this, arguments
return
this.extendTo resource
resource
).call(factory)
答案 12 :(得分:0)
let newObj = JSON.parse(JSON.stringify(obj))
JSON.stringify()
方法将JavaScript对象或值转换为JSON字符串
答案 13 :(得分:0)
如果您还没有使用lodash,我不建议您仅为此一种方法安装它。我建议改用更狭specialized的专业库,例如'clone':
npm install clone