Javascript TypeScript 中的深度克隆(保留类型)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/34201483/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Deep clone in TypeScript (preserving types)
提问by Julian B
I need to deep clone an object in TypeScript. This shouldn't be a problem as libraries like Lodash provide appropriate functions for that. However, these seem to discard type information.
我需要在 TypeScript 中深度克隆一个对象。这应该不是问题,因为像 Lodash 这样的库为此提供了适当的功能。但是,这些似乎丢弃了类型信息。
> var a = new SomeClass();
> a instanceof SomeClass;
< true
> var b = _.cloneDeep(a);
> b instanceof SomeClass;
< false
Is there a way to clone objects in TypeScript while preserving this typing information?
有没有办法在保留此类型信息的同时克隆 TypeScript 中的对象?
回答by Retsam
Typescript isn't discarding type information here. In the DefinitelyTyped lodash.d.tsfile, you can see that cloneDeep
is defined as
Typescript 不会在这里丢弃类型信息。在DefinitelyTyped lodash.d.ts文件中,你可以看到它cloneDeep
被定义为
cloneDeep<T>(
val: T,
customizer?: (value: any) => any,
thisArg?: any
) : T
Ignoring the arguments we don't care about, it takes a T
as input, and spits out a T
as output. So Typescript isn't losing any type information; it considers the output of cloneDeep
to be the same type as the input.
忽略我们不关心的参数,它将 aT
作为输入,并吐出 aT
作为输出。所以 Typescript 不会丢失任何类型信息;它认为 的输出cloneDeep
与输入的类型相同。
You should be able to verify this via your editor: assuming you have some editor that lets you inspect the type of variables or autocompletes methods (which I'd highly recommend, if you don't).
您应该能够通过您的编辑器验证这一点:假设您有一些编辑器可以让您检查变量的类型或自动完成方法(如果您不这样做,我强烈建议您这样做)。
Why then is the typeof
not working as you expect? It's because the Typescript type information doesn't carry over to runtime. instanceof
is a native JS operator, which Typescript doesn't change the behavior of, which you can see by running this snippet:
那么为什么typeof
没有按您预期的那样工作?这是因为 Typescript 类型信息不会延续到运行时。 instanceof
是一个原生的 JS 操作符,Typescript 不会改变它的行为,你可以通过运行这个片段来看到它:
"use strict";
class A {}
let a = new A();
let b = _.cloneDeep(a);
if (b instanceof A) {
alert("b is an instance of A");
} else {
alert("b is not an instance of A");
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>
The reason that b instanceof A
is false is that instanceof
is checking against constructors: x instanceof A
returns true if the function A
is a constructor somewhere in x's prototype chain (see the MDN documentation on instanceof). Lodash, however, doesn't use constructors when it clones objects. It can't. (How would it know what arguments to pass?) It creates a plain JS object that has all the methods of the cloned object, but doesn't reproduce it's prototype chain.
b instanceof A
错误的原因instanceof
是检查构造函数:x instanceof A
如果函数A
是 x 原型链中某处的构造函数,则返回 true (请参阅有关instanceof的 MDN 文档)。然而,Lodash 在克隆对象时不使用构造函数。它不能。(它怎么知道要传递什么参数?)它创建一个普通的 JS 对象,该对象具有克隆对象的所有方法,但不重现它的原型链。
Lodash's clone
(and most of lodash's methods, really) is best used when dealing with raw JS Objects. If you're using it in conjunction with constructors and instanceof
checking things get a bit murky.
clone
在处理原始 JS 对象时,最好使用Lodash (以及大多数 lodash 的方法)。如果您将它与构造函数结合使用并且instanceof
检查事情会变得有点模糊。
One solution here is to avoid the instanceof
checking, and do something akin to duck typing; don't check that the object's constructor is a particular function, but check that the object has the properties that you expect it to.
这里的一种解决方案是避免instanceof
检查,并做一些类似于鸭子打字的事情;不要检查对象的构造函数是否是特定函数,而是检查对象是否具有您期望的属性。
Another solution is, as suggested in the comments, implement a clone method on your class itself, which wouldn't use lodash.
另一种解决方案是,如评论中所建议的,在您的类本身上实现一个克隆方法,该方法不会使用 lodash。
class A() {
clone() {
var cloned = new A(); //pass appropriate constructor args
//make other necessary changes to make the state match
return cloned;
}
}
回答by Martin Vseticka
There is an interesting blog post about deep cloning http://blog.soulserv.net/understanding-object-cloning-in-javascript-part-ii/. You can use the author's implementation of the deep cloning clone()
function:
有一篇关于深度克隆的有趣博客文章http://blog.soulserv.net/understanding-object-cloning-in-javascript-part-ii/。可以使用作者的深度克隆clone()
功能实现:
class SomeClass {
constructor(public test) {
}
}
let c = new SomeClass("Hey!");
c.test = "Hey!";
console.log(c instanceof SomeClass); // returns true
let cloneC = clone(c, /* resolve circular references */ true);
console.log(cloneC instanceof SomeClass); // returns true
[clone() source code] [Complete source code]
[ clone() 源代码] [完整的源代码]
回答by Julian Torregrosa
You can create your own deep clone using JSON stringify and parse methods:
您可以使用 JSON stringify 和 parse 方法创建自己的深度克隆:
export function deepClone<T>(obj: T): T {
return JSON.parse(JSON.stringify(obj)) as T;
}
回答by Radouane ROUFID
You can use Lodash#cloneDeeputility. Example of use :
您可以使用Lodash#cloneDeep实用程序。使用示例:
import * as _ from "lodash";
...
{
this.cloned = _.cloneDeep(data);
}