JS一些实用方法介绍(hasOwnProperty()、Array.isArray()、Object.entries()、Reflect.set())

本文详细介绍了JavaScript中四个重要的实用方法:hasOwnProperty()用于检查对象自身属性,Array.isArray()判断值是否为数组,Object.entries()获取对象的键值对数组,以及Reflect.set()用于设置对象属性。每个方法都通过示例进行了解释并提供了MDN的官方参考链接。

1.hasOwnProperty()

hasOwnProperty() 方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性

举例:

let tempObj ={propName:'666'};

tempObj.propName2 ='999'

console.log(tempObj.hasOwnProperty('propName'))//返回true

console.log(tempObj.hasOwnProperty('propName2'))//返回true

具体可参考:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty

2.Array.isArray()

Array.isArray() 用于确定传递的值是否是一个 Array

举例:

let tempArry = [1,2,3];

console.log(Array.isArray(tempArry))//返回true

console.log(Array.isArray([1]))//返回true

console.log(Array.isArray(new Array()))//返回true

console.log(Array.isArray({}))//返回false

console.log(Array.isArray(true))//返回false

具体可参考https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray

3.Object.entries()

Object.entries()方法返回一个给定对象自身可枚举属性的键值对数组.

举例:

const object1 = {

a: 'somestring',

b: 42

};

for(let [key,value] of Object.entries(object1)){

console.log(key+': '+value)//a: somestring b: 42

}

const obj = { 0: 'a', 1: 'b', 2: 'c' };

console.log(Object.entries(obj)); //返回 [ ['0', 'a'], ['1', 'b'], ['2', 'c'] ]

具体可参考:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/entries

4.Reflect.set()

静态方法 Reflect.set() 工作方式就像在一个对象上设置一个属性。

语法:Reflect.set(target, propertyKey, value[, receiver])

target:设置属性的目标对象。

propertyKey:设置的属性的名称。

value:设置的值。

receiver:如果遇到 setter,this 将提供给目标调用。

举例:

// Object

let objTest = {};

Reflect.set(objTest, "prop", "value"); // true

console.log(objTest.prop); // "value"

 

// Array

var arrTest = ["duck1", "duck2", "duck3"];

Reflect.set(arrTest, 2, "goose"); // true

console.log(arrTest[2]); // "goose"

具体可参考https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect/set

将下面reflect-metadata源码改成好理解的代码,并且在文件上方屏蔽eslint校验:let Reflect; (function (Reflect) { // Metadata Proposal // https://rbuckton.github.io/reflect-metadata/ (function (factory) { let root = typeof globalThis === 'object' ? globalThis : typeof global === 'object' ? global : typeof self === 'object' ? self : typeof this === 'object' ? this : sloppyModeThis(); let exporter = makeExporter(Reflect); if (typeof root.Reflect !== 'undefined') { exporter = makeExporter(root.Reflect, exporter); } factory(exporter, root); if (typeof root.Reflect === 'undefined') { root.Reflect = Reflect; } function makeExporter(target, previous) { return function (key, value) { Object.defineProperty(target, key, { configurable: true, writable: true, value }); if (previous) { previous(key, value); } }; } function functionThis() { try { return Function('return this;')(); } catch (_) { } } function indirectEvalThis() { try { return (void 0, eval)('(function() { return this; })()'); } catch (_) { } } function sloppyModeThis() { return functionThis() || indirectEvalThis(); } })((exporter, root) => { let hasOwn = Object.prototype.hasOwnProperty; // feature test for Symbol support let supportsSymbol = typeof Symbol === 'function'; let toPrimitiveSymbol = supportsSymbol && typeof Symbol.toPrimitive !== 'undefined' ? Symbol.toPrimitive : '@@toPrimitive'; let iteratorSymbol = supportsSymbol && typeof Symbol.iterator !== 'undefined' ? Symbol.iterator : '@@iterator'; let supportsCreate = typeof Object.create === 'function'; // feature test for Object.create support let supportsProto = { __proto__: [] } instanceof Array; // feature test for __proto__ support let downLevel = !supportsCreate && !supportsProto; let HashMap = { // create an object in dictionary mode (a.k.a. "slow" mode in v8) create: supportsCreate ? function () { return MakeDictionary(Object.create(null)); } : supportsProto ? function () { return MakeDictionary({ __proto__: null }); } : function () { return MakeDictionary({}); }, has: downLevel ? function (map, key) { return hasOwn.call(map, key); } : function (map, key) { return key in map; }, get: downLevel ? function (map, key) { return hasOwn.call(map, key) ? map[key] : undefined; } : function (map, key) { return map[key]; }, }; // Load global or shim versions of Map, Set, and WeakMap let functionPrototype = Object.getPrototypeOf(Function); let _Map = typeof Map === 'function' && typeof Map.prototype.entries === 'function' ? Map : CreateMapPolyfill(); let _Set = typeof Set === 'function' && typeof Set.prototype.entries === 'function' ? Set : CreateSetPolyfill(); let _WeakMap = typeof WeakMap === 'function' ? WeakMap : CreateWeakMapPolyfill(); let registrySymbol = supportsSymbol ? Symbol.for('@reflect-metadata:registry') : undefined; let metadataRegistry = GetOrCreateMetadataRegistry(); let metadataProvider = CreateMetadataProvider(metadataRegistry); /** * Applies a set of decorators to a property of a target object. * @param decorators An array of decorators. * @param target The target object. * @param propertyKey (Optional) The property key to decorate. * @param attributes (Optional) The property descriptor for the target key. * @remarks Decorators are applied in reverse order. * @example * * class Example { * // property declarations are not part of ES6, though they are valid in TypeScript: * // static staticProperty; * // property; * * constructor(p) { } * static staticMethod(p) { } * method(p) { } * } * * // constructor * Example = Reflect.decorate(decoratorsArray, Example); * * // property (on constructor) * Reflect.decorate(decoratorsArray, Example, "staticProperty"); * * // property (on prototype) * Reflect.decorate(decoratorsArray, Example.prototype, "property"); * * // method (on constructor) * Object.defineProperty(Example, "staticMethod", * Reflect.decorate(decoratorsArray, Example, "staticMethod", * Object.getOwnPropertyDescriptor(Example, "staticMethod"))); * * // method (on prototype) * Object.defineProperty(Example.prototype, "method", * Reflect.decorate(decoratorsArray, Example.prototype, "method", * Object.getOwnPropertyDescriptor(Example.prototype, "method"))); * */ function decorate(decorators, target, propertyKey, attributes) { if (!IsUndefined(propertyKey)) { if (!IsArray(decorators)) { throw new TypeError(); } if (!IsObject(target)) { throw new TypeError(); } if (!IsObject(attributes) && !IsUndefined(attributes) && !IsNull(attributes)) { throw new TypeError(); } if (IsNull(attributes)) { attributes = undefined; } propertyKey = ToPropertyKey(propertyKey); return DecorateProperty(decorators, target, propertyKey, attributes); } else { if (!IsArray(decorators)) { throw new TypeError(); } if (!IsConstructor(target)) { throw new TypeError(); } return DecorateConstructor(decorators, target); } } exporter('decorate', decorate); // 4.1.2 Reflect.metadata(metadataKey, metadataValue) // https://rbuckton.github.io/reflect-metadata/#reflect.metadata /** * A default metadata decorator factory that can be used on a class, class member, or parameter. * @param metadataKey The key for the metadata entry. * @param metadataValue The value for the metadata entry. * @returns A decorator function. * @remarks * If `metadataKey` is already defined for the target and target key, the * metadataValue for that key will be overwritten. * @example * * // constructor * @Reflect.metadata(key, value) * class Example { * } * * // property (on constructor, TypeScript only) * class Example { * @Reflect.metadata(key, value) * static staticProperty; * } * * // property (on prototype, TypeScript only) * class Example { * @Reflect.metadata(key, value) * property; * } * * // method (on constructor) * class Example { * @Reflect.metadata(key, value) * static staticMethod() { } * } * * // method (on prototype) * class Example { * @Reflect.metadata(key, value) * method() { } * } * */ function metadata(metadataKey, metadataValue) { function decorator(target, propertyKey) { if (!IsObject(target)) { throw new TypeError(); } if (!IsUndefined(propertyKey) && !IsPropertyKey(propertyKey)) { throw new TypeError(); } OrdinaryDefineOwnMetadata(metadataKey, metadataValue, target, propertyKey); } return decorator; } exporter('metadata', metadata); /** * Define a unique metadata entry on the target. * @param metadataKey A key used to store and retrieve metadata. * @param metadataValue A value that contains attached metadata. * @param target The target object on which to define metadata. * @param propertyKey (Optional) The property key for the target. * @example * * class Example { * // property declarations are not part of ES6, though they are valid in TypeScript: * // static staticProperty; * // property; * * constructor(p) { } * static staticMethod(p) { } * method(p) { } * } * * // constructor * Reflect.defineMetadata("custom:annotation", options, Example); * * // property (on constructor) * Reflect.defineMetadata("custom:annotation", options, Example, "staticProperty"); * * // property (on prototype) * Reflect.defineMetadata("custom:annotation", options, Example.prototype, "property"); * * // method (on constructor) * Reflect.defineMetadata("custom:annotation", options, Example, "staticMethod"); * * // method (on prototype) * Reflect.defineMetadata("custom:annotation", options, Example.prototype, "method"); * * // decorator factory as metadata-producing annotation. * function MyAnnotation(options): Decorator { * return (target, key?) => Reflect.defineMetadata("custom:annotation", options, target, key); * } * */ function defineMetadata(metadataKey, metadataValue, target, propertyKey) { if (!IsObject(target)) { throw new TypeError(); } if (!IsUndefined(propertyKey)) { propertyKey = ToPropertyKey(propertyKey); } return OrdinaryDefineOwnMetadata(metadataKey, metadataValue, target, propertyKey); } exporter('defineMetadata', defineMetadata); /** * Gets a value indicating whether the target object or its prototype chain has the provided metadata key defined. * @param metadataKey A key used to store and retrieve metadata. * @param target The target object on which the metadata is defined. * @param propertyKey (Optional) The property key for the target. * @returns `true` if the metadata key was defined on the target object or its prototype chain; otherwise, `false`. * @example * * class Example { * // property declarations are not part of ES6, though they are valid in TypeScript: * // static staticProperty; * // property; * * constructor(p) { } * static staticMethod(p) { } * method(p) { } * } * * // constructor * result = Reflect.hasMetadata("custom:annotation", Example); * * // property (on constructor) * result = Reflect.hasMetadata("custom:annotation", Example, "staticProperty"); * * // property (on prototype) * result = Reflect.hasMetadata("custom:annotation", Example.prototype, "property"); * * // method (on constructor) * result = Reflect.hasMetadata("custom:annotation", Example, "staticMethod"); * * // method (on prototype) * result = Reflect.hasMetadata("custom:annotation", Example.prototype, "method"); * */ function hasMetadata(metadataKey, target, propertyKey) { if (!IsObject(target)) { throw new TypeError(); } if (!IsUndefined(propertyKey)) { propertyKey = ToPropertyKey(propertyKey); } return OrdinaryHasMetadata(metadataKey, target, propertyKey); } exporter('hasMetadata', hasMetadata); /** * Gets a value indicating whether the target object has the provided metadata key defined. * @param metadataKey A key used to store and retrieve metadata. * @param target The target object on which the metadata is defined. * @param propertyKey (Optional) The property key for the target. * @returns `true` if the metadata key was defined on the target object; otherwise, `false`. * @example * * class Example { * // property declarations are not part of ES6, though they are valid in TypeScript: * // static staticProperty; * // property; * * constructor(p) { } * static staticMethod(p) { } * method(p) { } * } * * // constructor * result = Reflect.hasOwnMetadata("custom:annotation", Example); * * // property (on constructor) * result = Reflect.hasOwnMetadata("custom:annotation", Example, "staticProperty"); * * // property (on prototype) * result = Reflect.hasOwnMetadata("custom:annotation", Example.prototype, "property"); * * // method (on constructor) * result = Reflect.hasOwnMetadata("custom:annotation", Example, "staticMethod"); * * // method (on prototype) * result = Reflect.hasOwnMetadata("custom:annotation", Example.prototype, "method"); * */ function hasOwnMetadata(metadataKey, target, propertyKey) { if (!IsObject(target)) { throw new TypeError(); } if (!IsUndefined(propertyKey)) { propertyKey = ToPropertyKey(propertyKey); } return OrdinaryHasOwnMetadata(metadataKey, target, propertyKey); } exporter('hasOwnMetadata', hasOwnMetadata); /** * Gets the metadata value for the provided metadata key on the target object or its prototype chain. * @param metadataKey A key used to store and retrieve metadata. * @param target The target object on which the metadata is defined. * @param propertyKey (Optional) The property key for the target. * @returns The metadata value for the metadata key if found; otherwise, `undefined`. * @example * * class Example { * // property declarations are not part of ES6, though they are valid in TypeScript: * // static staticProperty; * // property; * * constructor(p) { } * static staticMethod(p) { } * method(p) { } * } * * // constructor * result = Reflect.getMetadata("custom:annotation", Example); * * // property (on constructor) * result = Reflect.getMetadata("custom:annotation", Example, "staticProperty"); * * // property (on prototype) * result = Reflect.getMetadata("custom:annotation", Example.prototype, "property"); * * // method (on constructor) * result = Reflect.getMetadata("custom:annotation", Example, "staticMethod"); * * // method (on prototype) * result = Reflect.getMetadata("custom:annotation", Example.prototype, "method"); * */ function getMetadata(metadataKey, target, propertyKey) { if (!IsObject(target)) { throw new TypeError(); } if (!IsUndefined(propertyKey)) { propertyKey = ToPropertyKey(propertyKey); } return OrdinaryGetMetadata(metadataKey, target, propertyKey); } exporter('getMetadata', getMetadata); /** * Gets the metadata value for the provided metadata key on the target object. * @param metadataKey A key used to store and retrieve metadata. * @param target The target object on which the metadata is defined. * @param propertyKey (Optional) The property key for the target. * @returns The metadata value for the metadata key if found; otherwise, `undefined`. * @example * * class Example { * // property declarations are not part of ES6, though they are valid in TypeScript: * // static staticProperty; * // property; * * constructor(p) { } * static staticMethod(p) { } * method(p) { } * } * * // constructor * result = Reflect.getOwnMetadata("custom:annotation", Example); * * // property (on constructor) * result = Reflect.getOwnMetadata("custom:annotation", Example, "staticProperty"); * * // property (on prototype) * result = Reflect.getOwnMetadata("custom:annotation", Example.prototype, "property"); * * // method (on constructor) * result = Reflect.getOwnMetadata("custom:annotation", Example, "staticMethod"); * * // method (on prototype) * result = Reflect.getOwnMetadata("custom:annotation", Example.prototype, "method"); * */ function getOwnMetadata(metadataKey, target, propertyKey) { if (!IsObject(target)) { throw new TypeError(); } if (!IsUndefined(propertyKey)) { propertyKey = ToPropertyKey(propertyKey); } return OrdinaryGetOwnMetadata(metadataKey, target, propertyKey); } exporter('getOwnMetadata', getOwnMetadata); /** * Gets the metadata keys defined on the target object or its prototype chain. * @param target The target object on which the metadata is defined. * @param propertyKey (Optional) The property key for the target. * @returns An array of unique metadata keys. * @example * * class Example { * // property declarations are not part of ES6, though they are valid in TypeScript: * // static staticProperty; * // property; * * constructor(p) { } * static staticMethod(p) { } * method(p) { } * } * * // constructor * result = Reflect.getMetadataKeys(Example); * * // property (on constructor) * result = Reflect.getMetadataKeys(Example, "staticProperty"); * * // property (on prototype) * result = Reflect.getMetadataKeys(Example.prototype, "property"); * * // method (on constructor) * result = Reflect.getMetadataKeys(Example, "staticMethod"); * * // method (on prototype) * result = Reflect.getMetadataKeys(Example.prototype, "method"); * */ function getMetadataKeys(target, propertyKey) { if (!IsObject(target)) { throw new TypeError(); } if (!IsUndefined(propertyKey)) { propertyKey = ToPropertyKey(propertyKey); } return OrdinaryMetadataKeys(target, propertyKey); } exporter('getMetadataKeys', getMetadataKeys); /** * Gets the unique metadata keys defined on the target object. * @param target The target object on which the metadata is defined. * @param propertyKey (Optional) The property key for the target. * @returns An array of unique metadata keys. * @example * * class Example { * // property declarations are not part of ES6, though they are valid in TypeScript: * // static staticProperty; * // property; * * constructor(p) { } * static staticMethod(p) { } * method(p) { } * } * * // constructor * result = Reflect.getOwnMetadataKeys(Example); * * // property (on constructor) * result = Reflect.getOwnMetadataKeys(Example, "staticProperty"); * * // property (on prototype) * result = Reflect.getOwnMetadataKeys(Example.prototype, "property"); * * // method (on constructor) * result = Reflect.getOwnMetadataKeys(Example, "staticMethod"); * * // method (on prototype) * result = Reflect.getOwnMetadataKeys(Example.prototype, "method"); * */ function getOwnMetadataKeys(target, propertyKey) { if (!IsObject(target)) { throw new TypeError(); } if (!IsUndefined(propertyKey)) { propertyKey = ToPropertyKey(propertyKey); } return OrdinaryOwnMetadataKeys(target, propertyKey); } exporter('getOwnMetadataKeys', getOwnMetadataKeys); /** * Deletes the metadata entry from the target object with the provided key. * @param metadataKey A key used to store and retrieve metadata. * @param target The target object on which the metadata is defined. * @param propertyKey (Optional) The property key for the target. * @returns `true` if the metadata entry was found and deleted; otherwise, false. * @example * * class Example { * // property declarations are not part of ES6, though they are valid in TypeScript: * // static staticProperty; * // property; * * constructor(p) { } * static staticMethod(p) { } * method(p) { } * } * * // constructor * result = Reflect.deleteMetadata("custom:annotation", Example); * * // property (on constructor) * result = Reflect.deleteMetadata("custom:annotation", Example, "staticProperty"); * * // property (on prototype) * result = Reflect.deleteMetadata("custom:annotation", Example.prototype, "property"); * * // method (on constructor) * result = Reflect.deleteMetadata("custom:annotation", Example, "staticMethod"); * * // method (on prototype) * result = Reflect.deleteMetadata("custom:annotation", Example.prototype, "method"); * */ function deleteMetadata(metadataKey, target, propertyKey) { if (!IsObject(target)) { throw new TypeError(); } if (!IsUndefined(propertyKey)) { propertyKey = ToPropertyKey(propertyKey); } if (!IsObject(target)) { throw new TypeError(); } if (!IsUndefined(propertyKey)) { propertyKey = ToPropertyKey(propertyKey); } let provider = GetMetadataProvider(target, propertyKey, /* Create*/ false); if (IsUndefined(provider)) { return false; } return provider.OrdinaryDeleteMetadata(metadataKey, target, propertyKey); } exporter('deleteMetadata', deleteMetadata); function DecorateConstructor(decorators, target) { for (let i = decorators.length - 1; i >= 0; --i) { let decorator = decorators[i]; let decorated = decorator(target); if (!IsUndefined(decorated) && !IsNull(decorated)) { if (!IsConstructor(decorated)) { throw new TypeError(); } target = decorated; } } return target; } function DecorateProperty(decorators, target, propertyKey, descriptor) { for (let i = decorators.length - 1; i >= 0; --i) { let decorator = decorators[i]; let decorated = decorator(target, propertyKey, descriptor); if (!IsUndefined(decorated) && !IsNull(decorated)) { if (!IsObject(decorated)) { throw new TypeError(); } descriptor = decorated; } } return descriptor; } // 3.1.1.1 OrdinaryHasMetadata(MetadataKey, O, P) // https://rbuckton.github.io/reflect-metadata/#ordinaryhasmetadata function OrdinaryHasMetadata(MetadataKey, O, P) { let hasOwn = OrdinaryHasOwnMetadata(MetadataKey, O, P); if (hasOwn) { return true; } let parent = OrdinaryGetPrototypeOf(O); if (!IsNull(parent)) { return OrdinaryHasMetadata(MetadataKey, parent, P); } return false; } // 3.1.2.1 OrdinaryHasOwnMetadata(MetadataKey, O, P) // https://rbuckton.github.io/reflect-metadata/#ordinaryhasownmetadata function OrdinaryHasOwnMetadata(MetadataKey, O, P) { let provider = GetMetadataProvider(O, P, /* Create*/ false); if (IsUndefined(provider)) { return false; } return ToBoolean(provider.OrdinaryHasOwnMetadata(MetadataKey, O, P)); } // 3.1.3.1 OrdinaryGetMetadata(MetadataKey, O, P) // https://rbuckton.github.io/reflect-metadata/#ordinarygetmetadata function OrdinaryGetMetadata(MetadataKey, O, P) { let hasOwn = OrdinaryHasOwnMetadata(MetadataKey, O, P); if (hasOwn) { return OrdinaryGetOwnMetadata(MetadataKey, O, P); } let parent = OrdinaryGetPrototypeOf(O); if (!IsNull(parent)) { return OrdinaryGetMetadata(MetadataKey, parent, P); } return undefined; } // 3.1.4.1 OrdinaryGetOwnMetadata(MetadataKey, O, P) // https://rbuckton.github.io/reflect-metadata/#ordinarygetownmetadata function OrdinaryGetOwnMetadata(MetadataKey, O, P) { let provider = GetMetadataProvider(O, P, /* Create*/ false); if (IsUndefined(provider)) { return; } return provider.OrdinaryGetOwnMetadata(MetadataKey, O, P); } // 3.1.5.1 OrdinaryDefineOwnMetadata(MetadataKey, MetadataValue, O, P) // https://rbuckton.github.io/reflect-metadata/#ordinarydefineownmetadata function OrdinaryDefineOwnMetadata(MetadataKey, MetadataValue, O, P) { let provider = GetMetadataProvider(O, P, /* Create*/ true); provider.OrdinaryDefineOwnMetadata(MetadataKey, MetadataValue, O, P); } // 3.1.6.1 OrdinaryMetadataKeys(O, P) // https://rbuckton.github.io/reflect-metadata/#ordinarymetadatakeys function OrdinaryMetadataKeys(O, P) { let ownKeys = OrdinaryOwnMetadataKeys(O, P); let parent = OrdinaryGetPrototypeOf(O); if (parent === null) { return ownKeys; } let parentKeys = OrdinaryMetadataKeys(parent, P); if (parentKeys.length <= 0) { return ownKeys; } if (ownKeys.length <= 0) { return parentKeys; } let set = new _Set(); let keys = []; for (let _i = 0, ownKeys_1 = ownKeys; _i < ownKeys_1.length; _i++) { var key = ownKeys_1[_i]; var hasKey = set.has(key); if (!hasKey) { set.add(key); keys.push(key); } } for (let _a = 0, parentKeys_1 = parentKeys; _a < parentKeys_1.length; _a++) { var key = parentKeys_1[_a]; var hasKey = set.has(key); if (!hasKey) { set.add(key); keys.push(key); } } return keys; } // 3.1.7.1 OrdinaryOwnMetadataKeys(O, P) // https://rbuckton.github.io/reflect-metadata/#ordinaryownmetadatakeys function OrdinaryOwnMetadataKeys(O, P) { let provider = GetMetadataProvider(O, P, /* create*/ false); if (!provider) { return []; } return provider.OrdinaryOwnMetadataKeys(O, P); } // 6 ECMAScript Data Types and Values // https://tc39.github.io/ecma262/#sec-ecmascript-data-types-and-values function Type(x) { if (x === null) { return 1 /* Null */; } switch (typeof x) { case 'undefined': return 0 /* Undefined */; case 'boolean': return 2 /* Boolean */; case 'string': return 3 /* String */; case 'symbol': return 4 /* Symbol */; case 'number': return 5 /* Number */; case 'object': return x === null ? 1 /* Null */ : 6 /* Object */; default: return 6 /* Object */; } } // 6.1.1 The Undefined Type // https://tc39.github.io/ecma262/#sec-ecmascript-language-types-undefined-type function IsUndefined(x) { return x === undefined; } // 6.1.2 The Null Type // https://tc39.github.io/ecma262/#sec-ecmascript-language-types-null-type function IsNull(x) { return x === null; } // 6.1.5 The Symbol Type // https://tc39.github.io/ecma262/#sec-ecmascript-language-types-symbol-type function IsSymbol(x) { return typeof x === 'symbol'; } // 6.1.7 The Object Type // https://tc39.github.io/ecma262/#sec-object-type function IsObject(x) { return typeof x === 'object' ? x !== null : typeof x === 'function'; } // 7.1 Type Conversion // https://tc39.github.io/ecma262/#sec-type-conversion // 7.1.1 ToPrimitive(input [, PreferredType]) // https://tc39.github.io/ecma262/#sec-toprimitive function ToPrimitive(input, PreferredType) { switch (Type(input)) { case 0 /* Undefined */: return input; case 1 /* Null */: return input; case 2 /* Boolean */: return input; case 3 /* String */: return input; case 4 /* Symbol */: return input; case 5 /* Number */: return input; } let hint = PreferredType === 3 /* String */ ? 'string' : PreferredType === 5 /* Number */ ? 'number' : 'default'; let exoticToPrim = GetMethod(input, toPrimitiveSymbol); if (exoticToPrim !== undefined) { let result = exoticToPrim.call(input, hint); if (IsObject(result)) { throw new TypeError(); } return result; } return OrdinaryToPrimitive(input, hint === 'default' ? 'number' : hint); } // 7.1.1.1 OrdinaryToPrimitive(O, hint) // https://tc39.github.io/ecma262/#sec-ordinarytoprimitive function OrdinaryToPrimitive(O, hint) { if (hint === 'string') { let toString_1 = O.toString; if (IsCallable(toString_1)) { var result = toString_1.call(O); if (!IsObject(result)) { return result; } } var { valueOf } = O; if (IsCallable(valueOf)) { var result = valueOf.call(O); if (!IsObject(result)) { return result; } } } else { var { valueOf } = O; if (IsCallable(valueOf)) { var result = valueOf.call(O); if (!IsObject(result)) { return result; } } let toString_2 = O.toString; if (IsCallable(toString_2)) { var result = toString_2.call(O); if (!IsObject(result)) { return result; } } } throw new TypeError(); } // 7.1.2 ToBoolean(argument) // https://tc39.github.io/ecma262/2016/#sec-toboolean function ToBoolean(argument) { return Boolean(argument); } // 7.1.12 ToString(argument) // https://tc39.github.io/ecma262/#sec-tostring function ToString(argument) { return `${argument}`; } // 7.1.14 ToPropertyKey(argument) // https://tc39.github.io/ecma262/#sec-topropertykey function ToPropertyKey(argument) { let key = ToPrimitive(argument, 3 /* String */); if (IsSymbol(key)) { return key; } return ToString(key); } // 7.2 Testing and Comparison Operations // https://tc39.github.io/ecma262/#sec-testing-and-comparison-operations // 7.2.2 IsArray(argument) // https://tc39.github.io/ecma262/#sec-isarray function IsArray(argument) { return Array.isArray ? Array.isArray(argument) : argument instanceof Object ? argument instanceof Array : Object.prototype.toString.call(argument) === '[object Array]'; } // 7.2.3 IsCallable(argument) // https://tc39.github.io/ecma262/#sec-iscallable function IsCallable(argument) { // NOTE: This is an approximation as we cannot check for [[Call]] internal method. return typeof argument === 'function'; } // 7.2.4 IsConstructor(argument) // https://tc39.github.io/ecma262/#sec-isconstructor function IsConstructor(argument) { // NOTE: This is an approximation as we cannot check for [[Construct]] internal method. return typeof argument === 'function'; } // 7.2.7 IsPropertyKey(argument) // https://tc39.github.io/ecma262/#sec-ispropertykey function IsPropertyKey(argument) { switch (Type(argument)) { case 3 /* String */: return true; case 4 /* Symbol */: return true; default: return false; } } function SameValueZero(x, y) { return x === y || x !== x && y !== y; } // 7.3 Operations on Objects // https://tc39.github.io/ecma262/#sec-operations-on-objects // 7.3.9 GetMethod(V, P) // https://tc39.github.io/ecma262/#sec-getmethod function GetMethod(V, P) { let func = V[P]; if (func === undefined || func === null) { return undefined; } if (!IsCallable(func)) { throw new TypeError(); } return func; } // 7.4 Operations on Iterator Objects // https://tc39.github.io/ecma262/#sec-operations-on-iterator-objects function GetIterator(obj) { let method = GetMethod(obj, iteratorSymbol); if (!IsCallable(method)) { throw new TypeError(); } // from Call let iterator = method.call(obj); if (!IsObject(iterator)) { throw new TypeError(); } return iterator; } // 7.4.4 IteratorValue(iterResult) // https://tc39.github.io/ecma262/2016/#sec-iteratorvalue function IteratorValue(iterResult) { return iterResult.value; } // 7.4.5 IteratorStep(iterator) // https://tc39.github.io/ecma262/#sec-iteratorstep function IteratorStep(iterator) { let result = iterator.next(); return result.done ? false : result; } // 7.4.6 IteratorClose(iterator, completion) // https://tc39.github.io/ecma262/#sec-iteratorclose function IteratorClose(iterator) { let f = iterator.return; if (f) { f.call(iterator); } } // 9.1 Ordinary Object Internal Methods and Internal Slots // https://tc39.github.io/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots // 9.1.1.1 OrdinaryGetPrototypeOf(O) // https://tc39.github.io/ecma262/#sec-ordinarygetprototypeof function OrdinaryGetPrototypeOf(O) { let proto = Object.getPrototypeOf(O); if (typeof O !== 'function' || O === functionPrototype) { return proto; } // TypeScript doesn't set __proto__ in ES5, as it's non-standard. // Try to determine the superclass constructor. Compatible implementations // must either set __proto__ on a subclass constructor to the superclass constructor, // or ensure each class has a valid `constructor` property on its prototype that // points back to the constructor. // If this is not the same as Function.[[Prototype]], then this is definately inherited. // This is the case when in ES6 or when using __proto__ in a compatible browser. if (proto !== functionPrototype) { return proto; } // If the super prototype is Object.prototype, null, or undefined, then we cannot determine the heritage. let { prototype } = O; let prototypeProto = prototype && Object.getPrototypeOf(prototype); if (prototypeProto == null || prototypeProto === Object.prototype) { return proto; } // If the constructor was not a function, then we cannot determine the heritage. let { constructor } = prototypeProto; if (typeof constructor !== 'function') { return proto; } // If we have some kind of self-reference, then we cannot determine the heritage. if (constructor === O) { return proto; } // we have a pretty good guess at the heritage. return constructor; } // Global metadata registry // - Allows `import "reflect-metadata"` and `import "reflect-metadata/no-conflict"` to interoperate. // - Uses isolated metadata if `Reflect` is frozen before the registry can be installed. /** * Creates a registry used to allow multiple `reflect-metadata` providers. */ function CreateMetadataRegistry() { let fallback; if (!IsUndefined(registrySymbol) && typeof root.Reflect !== 'undefined' && !(registrySymbol in root.Reflect) && typeof root.Reflect.defineMetadata === 'function') { // interoperate with older version of `reflect-metadata` that did not support a registry. fallback = CreateFallbackProvider(root.Reflect); } let first; let second; let rest; let targetProviderMap = new _WeakMap(); let registry = { registerProvider, getProvider, setProvider, }; return registry; function registerProvider(provider) { if (!Object.isExtensible(registry)) { throw new Error('Cannot add provider to a frozen registry.'); } switch (true) { case fallback === provider: break; case IsUndefined(first): first = provider; break; case first === provider: break; case IsUndefined(second): second = provider; break; case second === provider: break; default: if (rest === undefined) { rest = new _Set(); } rest.add(provider); break; } } function getProviderNoCache(O, P) { if (!IsUndefined(first)) { if (first.isProviderFor(O, P)) { return first; } if (!IsUndefined(second)) { if (second.isProviderFor(O, P)) { return first; } if (!IsUndefined(rest)) { let iterator = GetIterator(rest); while (true) { let next = IteratorStep(iterator); if (!next) { return undefined; } let provider = IteratorValue(next); if (provider.isProviderFor(O, P)) { IteratorClose(iterator); return provider; } } } } } if (!IsUndefined(fallback) && fallback.isProviderFor(O, P)) { return fallback; } return undefined; } function getProvider(O, P) { let providerMap = targetProviderMap.get(O); let provider; if (!IsUndefined(providerMap)) { provider = providerMap.get(P); } if (!IsUndefined(provider)) { return provider; } provider = getProviderNoCache(O, P); if (!IsUndefined(provider)) { if (IsUndefined(providerMap)) { providerMap = new _Map(); targetProviderMap.set(O, providerMap); } providerMap.set(P, provider); } return provider; } function hasProvider(provider) { if (IsUndefined(provider)) { throw new TypeError(); } return first === provider || second === provider || !IsUndefined(rest) && rest.has(provider); } function setProvider(O, P, provider) { if (!hasProvider(provider)) { throw new Error('Metadata provider not registered.'); } let existingProvider = getProvider(O, P); if (existingProvider !== provider) { if (!IsUndefined(existingProvider)) { return false; } let providerMap = targetProviderMap.get(O); if (IsUndefined(providerMap)) { providerMap = new _Map(); targetProviderMap.set(O, providerMap); } providerMap.set(P, provider); } return true; } } /** * Gets or creates the shared registry of metadata providers. */ function GetOrCreateMetadataRegistry() { let metadataRegistry; if (!IsUndefined(registrySymbol) && IsObject(root.Reflect) && Object.isExtensible(root.Reflect)) { metadataRegistry = root.Reflect[registrySymbol]; } if (IsUndefined(metadataRegistry)) { metadataRegistry = CreateMetadataRegistry(); } if (!IsUndefined(registrySymbol) && IsObject(root.Reflect) && Object.isExtensible(root.Reflect)) { Object.defineProperty(root.Reflect, registrySymbol, { enumerable: false, configurable: false, writable: false, value: metadataRegistry, }); } return metadataRegistry; } function CreateMetadataProvider(registry) { // [[Metadata]] internal slot // https://rbuckton.github.io/reflect-metadata/#ordinary-object-internal-methods-and-internal-slots let metadata = new _WeakMap(); let provider = { isProviderFor (O, P) { let targetMetadata = metadata.get(O); if (IsUndefined(targetMetadata)) { return false; } return targetMetadata.has(P); }, OrdinaryDefineOwnMetadata, OrdinaryHasOwnMetadata, OrdinaryGetOwnMetadata, OrdinaryOwnMetadataKeys, OrdinaryDeleteMetadata, }; metadataRegistry.registerProvider(provider); return provider; function GetOrCreateMetadataMap(O, P, Create) { let targetMetadata = metadata.get(O); let createdTargetMetadata = false; if (IsUndefined(targetMetadata)) { if (!Create) { return undefined; } targetMetadata = new _Map(); metadata.set(O, targetMetadata); createdTargetMetadata = true; } let metadataMap = targetMetadata.get(P); if (IsUndefined(metadataMap)) { if (!Create) { return undefined; } metadataMap = new _Map(); targetMetadata.set(P, metadataMap); if (!registry.setProvider(O, P, provider)) { targetMetadata.delete(P); if (createdTargetMetadata) { metadata.delete(O); } throw new Error('Wrong provider for target.'); } } return metadataMap; } // 3.1.2.1 OrdinaryHasOwnMetadata(MetadataKey, O, P) // https://rbuckton.github.io/reflect-metadata/#ordinaryhasownmetadata function OrdinaryHasOwnMetadata(MetadataKey, O, P) { let metadataMap = GetOrCreateMetadataMap(O, P, /* Create*/ false); if (IsUndefined(metadataMap)) { return false; } return ToBoolean(metadataMap.has(MetadataKey)); } // 3.1.4.1 OrdinaryGetOwnMetadata(MetadataKey, O, P) // https://rbuckton.github.io/reflect-metadata/#ordinarygetownmetadata function OrdinaryGetOwnMetadata(MetadataKey, O, P) { let metadataMap = GetOrCreateMetadataMap(O, P, /* Create*/ false); if (IsUndefined(metadataMap)) { return undefined; } return metadataMap.get(MetadataKey); } // 3.1.5.1 OrdinaryDefineOwnMetadata(MetadataKey, MetadataValue, O, P) // https://rbuckton.github.io/reflect-metadata/#ordinarydefineownmetadata function OrdinaryDefineOwnMetadata(MetadataKey, MetadataValue, O, P) { let metadataMap = GetOrCreateMetadataMap(O, P, /* Create*/ true); metadataMap.set(MetadataKey, MetadataValue); } // 3.1.7.1 OrdinaryOwnMetadataKeys(O, P) // https://rbuckton.github.io/reflect-metadata/#ordinaryownmetadatakeys function OrdinaryOwnMetadataKeys(O, P) { let keys = []; let metadataMap = GetOrCreateMetadataMap(O, P, /* Create*/ false); if (IsUndefined(metadataMap)) { return keys; } let keysObj = metadataMap.keys(); let iterator = GetIterator(keysObj); let k = 0; while (true) { let next = IteratorStep(iterator); if (!next) { keys.length = k; return keys; } let nextValue = IteratorValue(next); try { keys[k] = nextValue; } catch (e) { try { IteratorClose(iterator); } finally { throw e; } } k++; } } function OrdinaryDeleteMetadata(MetadataKey, O, P) { let metadataMap = GetOrCreateMetadataMap(O, P, /* Create*/ false); if (IsUndefined(metadataMap)) { return false; } if (!metadataMap.delete(MetadataKey)) { return false; } if (metadataMap.size === 0) { let targetMetadata = metadata.get(O); if (!IsUndefined(targetMetadata)) { targetMetadata.delete(P); if (targetMetadata.size === 0) { metadata.delete(targetMetadata); } } } return true; } } function CreateFallbackProvider(reflect) { let { defineMetadata } = reflect, { hasOwnMetadata } = reflect, { getOwnMetadata } = reflect, { getOwnMetadataKeys } = reflect, { deleteMetadata } = reflect; let metadataOwner = new _WeakMap(); let provider = { isProviderFor (O, P) { let metadataPropertySet = metadataOwner.get(O); if (!IsUndefined(metadataPropertySet) && metadataPropertySet.has(P)) { return true; } if (getOwnMetadataKeys(O, P).length) { if (IsUndefined(metadataPropertySet)) { metadataPropertySet = new _Set(); metadataOwner.set(O, metadataPropertySet); } metadataPropertySet.add(P); return true; } return false; }, OrdinaryDefineOwnMetadata: defineMetadata, OrdinaryHasOwnMetadata: hasOwnMetadata, OrdinaryGetOwnMetadata: getOwnMetadata, OrdinaryOwnMetadataKeys: getOwnMetadataKeys, OrdinaryDeleteMetadata: deleteMetadata, }; return provider; } /** * Gets the metadata provider for an object. If the object has no metadata provider and this is for a create operation, * then this module's metadata provider is assigned to the object. */ function GetMetadataProvider(O, P, Create) { let registeredProvider = metadataRegistry.getProvider(O, P); if (!IsUndefined(registeredProvider)) { return registeredProvider; } if (Create) { if (metadataRegistry.setProvider(O, P, metadataProvider)) { return metadataProvider; } throw new Error('Illegal state.'); } return undefined; } // naive Map shim function CreateMapPolyfill() { let cacheSentinel = {}; let arraySentinel = []; let MapIterator = /** @class */ (function () { function MapIterator(keys, values, selector) { this._index = 0; this._keys = keys; this._values = values; this._selector = selector; } MapIterator.prototype['@@iterator'] = function () { return this; }; MapIterator.prototype[iteratorSymbol] = function () { return this; }; MapIterator.prototype.next = function () { let index = this._index; if (index >= 0 && index < this._keys.length) { let result = this._selector(this._keys[index], this._values[index]); if (index + 1 >= this._keys.length) { this._index = -1; this._keys = arraySentinel; this._values = arraySentinel; } else { this._index++; } return { value: result, done: false }; } return { value: undefined, done: true }; }; MapIterator.prototype.throw = function (error) { if (this._index >= 0) { this._index = -1; this._keys = arraySentinel; this._values = arraySentinel; } throw error; }; MapIterator.prototype.return = function (value) { if (this._index >= 0) { this._index = -1; this._keys = arraySentinel; this._values = arraySentinel; } return { value, done: true }; }; return MapIterator; }()); let Map = /** @class */ (function () { function Map() { this._keys = []; this._values = []; this._cacheKey = cacheSentinel; this._cacheIndex = -2; } Object.defineProperty(Map.prototype, 'size', { get () { return this._keys.length; }, enumerable: true, configurable: true, }); Map.prototype.has = function (key) { return this._find(key, /* insert*/ false) >= 0; }; Map.prototype.get = function (key) { let index = this._find(key, /* insert*/ false); return index >= 0 ? this._values[index] : undefined; }; Map.prototype.set = function (key, value) { let index = this._find(key, /* insert*/ true); this._values[index] = value; return this; }; Map.prototype.delete = function (key) { let index = this._find(key, /* insert*/ false); if (index >= 0) { let size = this._keys.length; for (let i = index + 1; i < size; i++) { this._keys[i - 1] = this._keys[i]; this._values[i - 1] = this._values[i]; } this._keys.length--; this._values.length--; if (SameValueZero(key, this._cacheKey)) { this._cacheKey = cacheSentinel; this._cacheIndex = -2; } return true; } return false; }; Map.prototype.clear = function () { this._keys.length = 0; this._values.length = 0; this._cacheKey = cacheSentinel; this._cacheIndex = -2; }; Map.prototype.keys = function () { return new MapIterator(this._keys, this._values, getKey); }; Map.prototype.values = function () { return new MapIterator(this._keys, this._values, getValue); }; Map.prototype.entries = function () { return new MapIterator(this._keys, this._values, getEntry); }; Map.prototype['@@iterator'] = function () { return this.entries(); }; Map.prototype[iteratorSymbol] = function () { return this.entries(); }; Map.prototype._find = function (key, insert) { if (!SameValueZero(this._cacheKey, key)) { this._cacheIndex = -1; for (let i = 0; i < this._keys.length; i++) { if (SameValueZero(this._keys[i], key)) { this._cacheIndex = i; break; } } } if (this._cacheIndex < 0 && insert) { this._cacheIndex = this._keys.length; this._keys.push(key); this._values.push(undefined); } return this._cacheIndex; }; return Map; }()); return Map; function getKey(key, _) { return key; } function getValue(_, value) { return value; } function getEntry(key, value) { return [key, value]; } } // naive Set shim function CreateSetPolyfill() { let Set = /** @class */ (function () { function Set() { this._map = new _Map(); } Object.defineProperty(Set.prototype, 'size', { get () { return this._map.size; }, enumerable: true, configurable: true, }); Set.prototype.has = function (value) { return this._map.has(value); }; Set.prototype.add = function (value) { return this._map.set(value, value), this; }; Set.prototype.delete = function (value) { return this._map.delete(value); }; Set.prototype.clear = function () { this._map.clear(); }; Set.prototype.keys = function () { return this._map.keys(); }; Set.prototype.values = function () { return this._map.keys(); }; Set.prototype.entries = function () { return this._map.entries(); }; Set.prototype['@@iterator'] = function () { return this.keys(); }; Set.prototype[iteratorSymbol] = function () { return this.keys(); }; return Set; }()); return Set; } // naive WeakMap shim function CreateWeakMapPolyfill() { let UUID_SIZE = 16; let keys = HashMap.create(); let rootKey = CreateUniqueKey(); return /** @class */ (function () { function WeakMap() { this._key = CreateUniqueKey(); } WeakMap.prototype.has = function (target) { let table = GetOrCreateWeakMapTable(target, /* create*/ false); return table !== undefined ? HashMap.has(table, this._key) : false; }; WeakMap.prototype.get = function (target) { let table = GetOrCreateWeakMapTable(target, /* create*/ false); return table !== undefined ? HashMap.get(table, this._key) : undefined; }; WeakMap.prototype.set = function (target, value) { let table = GetOrCreateWeakMapTable(target, /* create*/ true); table[this._key] = value; return this; }; WeakMap.prototype.delete = function (target) { let table = GetOrCreateWeakMapTable(target, /* create*/ false); return table !== undefined ? delete table[this._key] : false; }; WeakMap.prototype.clear = function () { // NOTE: not a real clear, just makes the previous data unreachable this._key = CreateUniqueKey(); }; return WeakMap; }()); function CreateUniqueKey() { let key; do { key = `@@WeakMap@@${CreateUUID()}`; } while (HashMap.has(keys, key)); keys[key] = true; return key; } function GetOrCreateWeakMapTable(target, create) { if (!hasOwn.call(target, rootKey)) { if (!create) { return undefined; } Object.defineProperty(target, rootKey, { value: HashMap.create() }); } return target[rootKey]; } function FillRandomBytes(buffer, size) { for (let i = 0; i < size; ++i) { buffer[i] = Math.random() * 0xff | 0; } return buffer; } function GenRandomBytes(size) { if (typeof Uint8Array === 'function') { let array = new Uint8Array(size); if (typeof crypto !== 'undefined') { crypto.getRandomValues(array); } else if (typeof msCrypto !== 'undefined') { msCrypto.getRandomValues(array); } else { FillRandomBytes(array, size); } return array; } return FillRandomBytes(new Array(size), size); } function CreateUUID() { let data = GenRandomBytes(UUID_SIZE); // mark as random - RFC 4122 § 4.4 data[6] = data[6] & 0x4f | 0x40; data[8] = data[8] & 0xbf | 0x80; let result = ''; for (let offset = 0; offset < UUID_SIZE; ++offset) { let byte = data[offset]; if (offset === 4 || offset === 6 || offset === 8) { result += '-'; } if (byte < 16) { result += '0'; } result += byte.toString(16).toLowerCase(); } return result; } } // uses a heuristic used by v8 and chakra to force an object into dictionary mode. function MakeDictionary(obj) { obj.__ = undefined; delete obj.__; return obj; } }); })(Reflect || (Reflect = {}));
09-29
/** * 深度克隆(支持复杂类型和循环引用) * @param obj 要克隆的对象 * @param visited 已访问对象记录(用于防止循环引用) * @returns 克隆后的新对象 */ public static clone(obj: any, visited = new Map()): any { // 基础类型直接返回 if (obj === null || typeof obj !== "object") { return obj; } // 防止循环引用 if (visited.has(obj)) { return visited.get(obj); } // 特殊类型处理 if (obj instanceof Date) { return new Date(obj.getTime()); } if (obj instanceof RegExp) { return new RegExp(obj); } if (obj instanceof Map) { const clonedMap = new Map(); visited.set(obj, clonedMap); for (const [key, value] of obj.entries()) { clonedMap.set(this.clone(key, visited), this.clone(value, visited)); } return clonedMap; } if (obj instanceof Set) { const clonedSet = new Set(); visited.set(obj, clonedSet); for (const item of obj) { clonedSet.add(this.clone(item, visited)); } return clonedSet; } // 数组处理 if (obj instanceof Array) { const clonedArr = []; visited.set(obj, clonedArr); for (let i = 0; i < obj.length; i++) { clonedArr[i] = this.clone(obj[i], visited); } return clonedArr; } // 构造新对象(保留构造函数,适用于简单类实例) const constructor = obj.constructor; let clonedObj: any; if (constructor && constructor !== Object) { clonedObj = new constructor(); } else { clonedObj = {}; } visited.set(obj, clonedObj); // 复制所有自有属性(包括 Symbol) const descriptors = Object.getOwnPropertyDescriptors(obj); for (const key in descriptors) { const descriptor = descriptors[key]; if (descriptor.value !== undefined) { descriptor.value = this.clone(descriptor.value, visited); } Object.defineProperty(clonedObj, key, descriptor); } // 可选:复制 Symbol 属性 const symbolKeys = Object.getOwnPropertySymbols(obj); for (const symbol of symbolKeys) { const descriptor = Object.getOwnPropertyDescriptor(obj, symbol); if (descriptor.value !== undefined) { descriptor.value = this.clone(descriptor.value, visited); } Object.defineProperty(clonedObj, symbol, descriptor); } return clonedObj; }/** * 深度克隆(支持复杂类型和循环引用) * @param obj 要克隆的对象 * @param visited 已访问对象记录(用于防止循环引用) * @returns 克隆后的新对象 */ public static clone(obj: any, visited = new Map()): any { // 基础类型直接返回 if (obj === null || typeof obj !== "object") { return obj; } // 防止循环引用 if (visited.has(obj)) { return visited.get(obj); } // 特殊类型处理 if (obj instanceof Date) { return new Date(obj.getTime()); } if (obj instanceof RegExp) { return new RegExp(obj); } if (obj instanceof Map) { const clonedMap = new Map(); visited.set(obj, clonedMap); for (const [key, value] of obj.entries()) { clonedMap.set(this.clone(key, visited), this.clone(value, visited)); } return clonedMap; } if (obj instanceof Set) { const clonedSet = new Set(); visited.set(obj, clonedSet); for (const item of obj) { clonedSet.add(this.clone(item, visited)); } return clonedSet; } // 数组处理 if (obj instanceof Array) { const clonedArr = []; visited.set(obj, clonedArr); for (let i = 0; i < obj.length; i++) { clonedArr[i] = this.clone(obj[i], visited); } return clonedArr; } // 构造新对象(保留构造函数,适用于简单类实例) const constructor = obj.constructor; let clonedObj: any; if (constructor && constructor !== Object) { clonedObj = new constructor(); } else { clonedObj = {}; } visited.set(obj, clonedObj); // 复制所有自有属性(包括 Symbol) const descriptors = Object.getOwnPropertyDescriptors(obj); for (const key in descriptors) { const descriptor = descriptors[key]; if (descriptor.value !== undefined) { descriptor.value = this.clone(descriptor.value, visited); } Object.defineProperty(clonedObj, key, descriptor); } // 可选:复制 Symbol 属性 const symbolKeys = Object.getOwnPropertySymbols(obj); for (const symbol of symbolKeys) { const descriptor = Object.getOwnPropertyDescriptor(obj, symbol); if (descriptor.value !== undefined) { descriptor.value = this.clone(descriptor.value, visited); } Object.defineProperty(clonedObj, symbol, descriptor); } return clonedObj; }这个方法有问题么
07-11
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值