如何克隆任何对象,包括特殊类型?

How to clone any object, including special types?

我需要编写一个 returns 对象克隆的函数。

类似于:

// non recursive clone
function clone( obj ) {
  const newObj = Object.create( Object.getPrototypeOf(obj) );
  return Object.assign( newObj, obj );
}

这当然只适用于对象,不适用于基本类型:它不适用于 undefinednull、布尔值、数字、字符串、符号。

...但它也不适用于其他类型,例如Array, Set, Map.

我想支持尽可能多的类型,我最好的办法是逐个处理 特殊 类型。

我认为带有 Internal Methods or Internal Slots 的对象可能会产生问题。我不太确定这一点,我找不到包含内部方法或插槽的标准类型列表。

Object.create() 不能正确创建哪些标准类型?

Which standard types cannot correctly be created by Object.create() exactly?

确实是全部。您谈论的那些特殊类型只能使用 newReflect.construct 创建,提供将创建内部插槽的内置构造函数。

I could not find a list of standard types with Internal Methods or Slots.

它就在规范中,chapter 9 Exotic Objects(对于内部方法)。您可以很好地处理普通对象(Object.create 创建一个),但是您会遇到函数对象、绑定函数对象、数组对象、字符串对象、参数对象、类型化数组对象、模块名称空间对象和代理的问题。此外,您可以通过搜索 OrdinaryCreateFromConstructorGeneratorBooleanError 和所有其他本机错误的用法来查找具有特殊内部插槽的对象, Number, Date, RegExp, Map, Set, WeakMap, WeaskSet, ArrayBuffer, DataView, Promise) 和 ObjectCreate (ListIterator, Arguments, 所有类型数组, StringIterator, ArrayIterator, MapIterator, SetIterator).

I'd like to support as many types as I can

您应该决定(并记录)哪些受支持,哪些不受支持。特别是对于递归克隆来说,这将是一件麻烦事。还要确保记录您如何处理不可枚举或符号键控的自有属性和 getters/setters,默认的 Object.assign 行为可能不是您想要的。

how to do this is handling special types case by case?

我会在所有支持类型的原型上定义一个 Symbol.for("clone") 方法,这样很容易扩展。可能在不支持克隆的情况下使用已知值代替 and/or 默认复制算法没有意义,例如在迭代器或函数对象上,以便可以使用错误消息处理或忽略它们。