Blame view

天文台pc/tianwentai-ui/node_modules/fast-equals/README.md 22.9 KB
bc518174   王天杨   提交两个项目文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
  # fast-equals
  
  <img src="https://img.shields.io/badge/build-passing-brightgreen.svg"/>
  <img src="https://img.shields.io/badge/coverage-100%25-brightgreen.svg"/>
  <img src="https://img.shields.io/badge/license-MIT-blue.svg"/>
  
  Perform [blazing fast](#benchmarks) equality comparisons (either deep or shallow) on two objects passed, while also
  maintaining a high degree of flexibility for various implementation use-cases. It has no dependencies, and is ~2kB when
  minified and gzipped.
  
  The following types are handled out-of-the-box:
  
  - Plain objects (including `react` elements and `Arguments`)
  - Arrays
  - `ArrayBuffer` / `TypedArray` / `DataView` instances
  - `Date` objects
  - `RegExp` objects
  - `Map` / `Set` iterables
  - `Promise` objects
  - Primitive wrappers (`new Boolean()` / `new Number()` / `new String()`)
  - Custom class instances, including subclasses of native classes
  
  Methods are available for deep, shallow, or referential equality comparison. In addition, you can opt into support for
  circular objects, or performing a "strict" comparison with unconventional property definition, or both. You can also
  customize any specific type comparison based on your application's use-cases.
  
  ## Table of contents
  
  - [fast-equals](#fast-equals)
    - [Table of contents](#table-of-contents)
    - [Usage](#usage)
      - [Specific builds](#specific-builds)
    - [Available methods](#available-methods)
      - [deepEqual](#deepequal)
        - [Comparing `Map`s](#comparing-maps)
      - [shallowEqual](#shallowequal)
      - [sameValueZeroEqual](#samevaluezeroequal)
      - [circularDeepEqual](#circulardeepequal)
      - [circularShallowEqual](#circularshallowequal)
      - [strictDeepEqual](#strictdeepequal)
      - [strictShallowEqual](#strictshallowequal)
      - [strictCircularDeepEqual](#strictcirculardeepequal)
      - [strictCircularShallowEqual](#strictcircularshallowequal)
      - [createCustomEqual](#createcustomequal)
        - [unknownTagComparators](#unknowntagcomparators)
        - [Recipes](#recipes)
    - [Benchmarks](#benchmarks)
    - [Development](#development)
  
  ## Usage
  
  ```ts
  import { deepEqual } from 'fast-equals';
  
  console.log(deepEqual({ foo: 'bar' }, { foo: 'bar' })); // true
  ```
  
  ### Specific builds
  
  By default, npm should resolve the correct build of the package based on your consumption (ESM vs CommonJS). However, if
  you want to force use of a specific build, they can be located here:
  
  - ESM => `fast-equals/dist/esm/index.mjs`
  - CommonJS => `fast-equals/dist/cjs/index.cjs`
  - UMD => `fast-equals/dist/umd/index.js`
  - Minified UMD => `fast-equals/dist/min/index.js`
  
  If you are having issues loading a specific build type,
  [please file an issue](https://github.com/planttheidea/fast-equals/issues).
  
  ## Available methods
  
  ### deepEqual
  
  Performs a deep equality comparison on the two objects passed and returns a boolean representing the value equivalency
  of the objects.
  
  ```ts
  import { deepEqual } from 'fast-equals';
  
  const objectA = { foo: { bar: 'baz' } };
  const objectB = { foo: { bar: 'baz' } };
  
  console.log(objectA === objectB); // false
  console.log(deepEqual(objectA, objectB)); // true
  ```
  
  #### Comparing `Map`s
  
  `Map` objects support complex keys (objects, Arrays, etc.), however
  [the spec for key lookups in `Map` are based on `SameZeroValue`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map#key_equality).
  If the spec were followed for comparison, the following would always be `false`:
  
  ```ts
  const mapA = new Map([[{ foo: 'bar' }, { baz: 'quz' }]]);
  const mapB = new Map([[{ foo: 'bar' }, { baz: 'quz' }]]);
  
  deepEqual(mapA, mapB);
  ```
  
  To support true deep equality of all contents, `fast-equals` will perform a deep equality comparison for key and value
  parirs. Therefore, the above would be `true`.
  
  ### shallowEqual
  
  Performs a shallow equality comparison on the two objects passed and returns a boolean representing the value
  equivalency of the objects.
  
  ```ts
  import { shallowEqual } from 'fast-equals';
  
  const nestedObject = { bar: 'baz' };
  
  const objectA = { foo: nestedObject };
  const objectB = { foo: nestedObject };
  const objectC = { foo: { bar: 'baz' } };
  
  console.log(objectA === objectB); // false
  console.log(shallowEqual(objectA, objectB)); // true
  console.log(shallowEqual(objectA, objectC)); // false
  ```
  
  ### sameValueZeroEqual
  
  Performs a [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) comparison on the two
  objects passed and returns a boolean representing the value equivalency of the objects. In simple terms, this means
  either strictly equal or both `NaN`.
  
  ```ts
  import { sameValueZeroEqual } from 'fast-equals';
  
  const mainObject = { foo: NaN, bar: 'baz' };
  
  const objectA = 'baz';
  const objectB = NaN;
  const objectC = { foo: NaN, bar: 'baz' };
  
  console.log(sameValueZeroEqual(mainObject.bar, objectA)); // true
  console.log(sameValueZeroEqual(mainObject.foo, objectB)); // true
  console.log(sameValueZeroEqual(mainObject, objectC)); // false
  ```
  
  ### circularDeepEqual
  
  Performs the same comparison as `deepEqual` but supports circular objects. It is slower than `deepEqual`, so only use if
  you know circular objects are present.
  
  ```ts
  function Circular(value) {
    this.me = {
      deeply: {
        nested: {
          reference: this,
        },
      },
      value,
    };
  }
  
  console.log(circularDeepEqual(new Circular('foo'), new Circular('foo'))); // true
  console.log(circularDeepEqual(new Circular('foo'), new Circular('bar'))); // false
  ```
  
  Just as with `deepEqual`, [both keys and values are compared for deep equality](#comparing-maps).
  
  ### circularShallowEqual
  
  Performs the same comparison as `shallowequal` but supports circular objects. It is slower than `shallowEqual`, so only
  use if you know circular objects are present.
  
  ```ts
  const array = ['foo'];
  
  array.push(array);
  
  console.log(circularShallowEqual(array, ['foo', array])); // true
  console.log(circularShallowEqual(array, [array])); // false
  ```
  
  ### strictDeepEqual
  
  Performs the same comparison as `deepEqual` but performs a strict comparison of the objects. In this includes:
  
  - Checking symbol properties
  - Checking non-enumerable properties in object comparisons
  - Checking full descriptor of properties on the object to match
  - Checking non-index properties on arrays
  - Checking non-key properties on `Map` / `Set` objects
  
  ```ts
  const array = [{ foo: 'bar' }];
  const otherArray = [{ foo: 'bar' }];
  
  array.bar = 'baz';
  otherArray.bar = 'baz';
  
  console.log(strictDeepEqual(array, otherArray)); // true;
  console.log(strictDeepEqual(array, [{ foo: 'bar' }])); // false;
  ```
  
  ### strictShallowEqual
  
  Performs the same comparison as `shallowEqual` but performs a strict comparison of the objects. In this includes:
  
  - Checking non-enumerable properties in object comparisons
  - Checking full descriptor of properties on the object to match
  - Checking non-index properties on arrays
  - Checking non-key properties on `Map` / `Set` objects
  
  ```ts
  const array = ['foo'];
  const otherArray = ['foo'];
  
  array.bar = 'baz';
  otherArray.bar = 'baz';
  
  console.log(strictDeepEqual(array, otherArray)); // true;
  console.log(strictDeepEqual(array, ['foo'])); // false;
  ```
  
  ### strictCircularDeepEqual
  
  Performs the same comparison as `circularDeepEqual` but performs a strict comparison of the objects. In this includes:
  
  - Checking `Symbol` properties on the object
  - Checking non-enumerable properties in object comparisons
  - Checking full descriptor of properties on the object to match
  - Checking non-index properties on arrays
  - Checking non-key properties on `Map` / `Set` objects
  
  ```ts
  function Circular(value) {
    this.me = {
      deeply: {
        nested: {
          reference: this,
        },
      },
      value,
    };
  }
  
  const first = new Circular('foo');
  
  Object.defineProperty(first, 'bar', {
    enumerable: false,
    value: 'baz',
  });
  
  const second = new Circular('foo');
  
  Object.defineProperty(second, 'bar', {
    enumerable: false,
    value: 'baz',
  });
  
  console.log(circularDeepEqual(first, second)); // true
  console.log(circularDeepEqual(first, new Circular('foo'))); // false
  ```
  
  ### strictCircularShallowEqual
  
  Performs the same comparison as `circularShallowEqual` but performs a strict comparison of the objects. In this
  includes:
  
  - Checking non-enumerable properties in object comparisons
  - Checking full descriptor of properties on the object to match
  - Checking non-index properties on arrays
  - Checking non-key properties on `Map` / `Set` objects
  
  ```ts
  const array = ['foo'];
  const otherArray = ['foo'];
  
  array.push(array);
  otherArray.push(otherArray);
  
  array.bar = 'baz';
  otherArray.bar = 'baz';
  
  console.log(circularShallowEqual(array, otherArray)); // true
  console.log(circularShallowEqual(array, ['foo', array])); // false
  ```
  
  ### createCustomEqual
  
  Creates a custom equality comparator that will be used on nested values in the object. Unlike `deepEqual` and
  `shallowEqual`, this is a factory method that receives the default options used internally, and allows you to override
  the defaults as needed. This is generally for extreme edge-cases, or supporting legacy environments.
  
  The signature is as follows:
  
  ```ts
  interface Cache<Key extends object, Value> {
    delete(key: Key): boolean;
    get(key: Key): Value | undefined;
    set(key: Key, value: any): any;
  }
  
  interface ComparatorConfig<Meta> {
    areArraysEqual: TypeEqualityComparator<any[], Meta>;
    areDatesEqual: TypeEqualityComparator<Date, Meta>;
    areErrorsEqual: TypeEqualityComparator<Error, Meta>;
    areFunctionsEqual: TypeEqualityComparator<(...args: any[]) => any, Meta>;
    areMapsEqual: TypeEqualityComparator<Map<any, any>, Meta>;
    areObjectsEqual: TypeEqualityComparator<Record<string, any>, Meta>;
    arePrimitiveWrappersEqual: TypeEqualityComparator<boolean | string | number, Meta>;
    areRegExpsEqual: TypeEqualityComparator<RegExp, Meta>;
    areSetsEqual: TypeEqualityComparator<Set<any>, Meta>;
    areTypedArraysEqual: TypeEqualityComparator<TypedArray, Meta>;
    areUrlsEqual: TypeEqualityComparator<URL, Meta>;
    unknownTagComparators: Record<string, TypeEqualityComparator<string, any>>;
  }
  
  function createCustomEqual<Meta>(options: {
    circular?: boolean;
    createCustomConfig?: (defaultConfig: ComparatorConfig<Meta>) => Partial<ComparatorConfig<Meta>>;
    createInternalComparator?: (
      compare: <A, B>(a: A, b: B, state: State<Meta>) => boolean,
    ) => (a: any, b: any, indexOrKeyA: any, indexOrKeyB: any, parentA: any, parentB: any, state: State<Meta>) => boolean;
    createState?: () => { cache?: Cache; meta?: Meta };
    strict?: boolean;
  }): <A, B>(a: A, b: B) => boolean;
  ```
  
  Create a custom equality comparator. This allows complete control over building a bespoke equality method, in case your
  use-case requires a higher degree of performance, legacy environment support, or any other non-standard usage. The
  [recipes](#recipes) provide examples of use in different use-cases, but if you have a specific goal in mind and would
  like assistance feel free to [file an issue](https://github.com/planttheidea/fast-equals/issues).
  
  _**NOTE**: `Map` implementations compare equality for both keys and value. When using a custom comparator and comparing
  equality of the keys, the iteration index is provided as both `indexOrKeyA` and `indexOrKeyB` to help use-cases where
  ordering of keys matters to equality._
  
  #### unknownTagComparators
  
  If you want to compare objects that have a custom `@@toStringTag`, you can provide a map of the custom tags you want to
  support via the `unknownTagComparators` option. See [this recipe]('./recipes/special-objects.md) for an example.
  
  #### Recipes
  
  Some recipes have been created to provide examples of use-cases for `createCustomEqual`. Even if not directly applicable
  to the problem you are solving, they can offer guidance of how to structure your solution.
  
  - [Legacy environment support for `RegExp` comparators](./recipes/legacy-regexp-support.md)
  - [Explicit property check](./recipes/explicit-property-check.md)
  - [Using `meta` in comparison](./recipes//using-meta-in-comparison.md)
  - [Comparing non-standard properties](./recipes/non-standard-properties.md)
  - [Strict property descriptor comparison](./recipes/strict-property-descriptor-check.md)
  - [Legacy environment support for circualr equal comparators](./recipes/legacy-circular-equal-support.md)
  - [Custom `@@toStringTag` support](./recipes/special-objects.md)
  
  ## Benchmarks
  
  All benchmarks were performed on an i9-11900H Ubuntu Linux 24.04 laptop with 64GB of memory using NodeJS version
  `20.17.0`, and are based on averages of running comparisons based deep equality on the following object types:
  
  - Primitives (`String`, `Number`, `null`, `undefined`)
  - `Function`
  - `Object`
  - `Array`
  - `Date`
  - `RegExp`
  - `react` elements
  - A mixed object with a combination of all the above types
  
  ```bash
  Testing mixed objects equal...
  ┌────────────────────────────────────────┬────────────────┐
  │ Name                                   │ Ops / sec      │
  ├────────────────────────────────────────┼────────────────┤
  │ fast-equals (passed)                   │ 1416193.769468 │
  ├────────────────────────────────────────┼────────────────┤
  │ fast-deep-equal (passed)               │ 1284824.583215 │
  ├────────────────────────────────────────┼────────────────┤
  │ react-fast-compare (passed)            │ 1246947.505444 │
  ├────────────────────────────────────────┼────────────────┤
  │ shallow-equal-fuzzy (passed)           │ 1238082.379207 │
  ├────────────────────────────────────────┼────────────────┤
  │ nano-equal (failed)                    │ 946782.33704   │
  ├────────────────────────────────────────┼────────────────┤
  │ dequal/lite (passed)                   │ 758213.632866  │
  ├────────────────────────────────────────┼────────────────┤
  │ dequal (passed)                        │ 756789.655029  │
  ├────────────────────────────────────────┼────────────────┤
  │ fast-equals (circular) (passed)        │ 726093.253185  │
  ├────────────────────────────────────────┼────────────────┤
  │ underscore.isEqual (passed)            │ 489748.701783  │
  ├────────────────────────────────────────┼────────────────┤
  │ assert.deepStrictEqual (passed)        │ 453761.890107  │
  ├────────────────────────────────────────┼────────────────┤
  │ lodash.isEqual (passed)                │ 288264.867811  │
  ├────────────────────────────────────────┼────────────────┤
  │ fast-equals (strict) (passed)          │ 217221.619705  │
  ├────────────────────────────────────────┼────────────────┤
  │ fast-equals (strict circular) (passed) │ 186916.942934  │
  ├────────────────────────────────────────┼────────────────┤
  │ deep-eql (passed)                      │ 162487.877883  │
  ├────────────────────────────────────────┼────────────────┤
  │ deep-equal (passed)                    │ 916.680714     │
  └────────────────────────────────────────┴────────────────┘
  
  Testing mixed objects not equal...
  ┌────────────────────────────────────────┬────────────────┐
  │ Name                                   │ Ops / sec      │
  ├────────────────────────────────────────┼────────────────┤
  │ fast-equals (passed)                   │ 4687012.640614 │
  ├────────────────────────────────────────┼────────────────┤
  │ fast-deep-equal (passed)               │ 3418170.156109 │
  ├────────────────────────────────────────┼────────────────┤
  │ react-fast-compare (passed)            │ 3283516.669966 │
  ├────────────────────────────────────────┼────────────────┤
  │ fast-equals (circular) (passed)        │ 3268062.099602 │
  ├────────────────────────────────────────┼────────────────┤
  │ fast-equals (strict) (passed)          │ 1747578.66456  │
  ├────────────────────────────────────────┼────────────────┤
  │ fast-equals (strict circular) (passed) │ 1477873.624956 │
  ├────────────────────────────────────────┼────────────────┤
  │ dequal/lite (passed)                   │ 1335397.839502 │
  ├────────────────────────────────────────┼────────────────┤
  │ dequal (passed)                        │ 1319426.71146  │
  ├────────────────────────────────────────┼────────────────┤
  │ shallow-equal-fuzzy (failed)           │ 1237432.986615 │
  ├────────────────────────────────────────┼────────────────┤
  │ nano-equal (passed)                    │ 1064383.319776 │
  ├────────────────────────────────────────┼────────────────┤
  │ underscore.isEqual (passed)            │ 920462.516736  │
  ├────────────────────────────────────────┼────────────────┤
  │ lodash.isEqual (passed)                │ 379370.998021  │
  ├────────────────────────────────────────┼────────────────┤
  │ deep-eql (passed)                      │ 184111.383127  │
  ├────────────────────────────────────────┼────────────────┤
  │ assert.deepStrictEqual (passed)        │ 20775.59065    │
  ├────────────────────────────────────────┼────────────────┤
  │ deep-equal (passed)                    │ 3678.51009     │
  └────────────────────────────────────────┴────────────────┘
  ```
  
  Caveats that impact the benchmark (and accuracy of comparison):
  
  - `Map`s, `Promise`s, and `Set`s were excluded from the benchmark entirely because no library other than `deep-eql`
    fully supported their comparison
  - `fast-deep-equal`, `react-fast-compare` and `nano-equal` throw on objects with `null` as prototype
    (`Object.create(null)`)
  - `assert.deepStrictEqual` does not support `NaN` or `SameValueZero` equality for dates
  - `deep-eql` does not support `SameValueZero` equality for zero equality (positive and negative zero are not equal)
  - `deep-equal` does not support `NaN` and does not strictly compare object type, or date / regexp values, nor uses
    `SameValueZero` equality for dates
  - `fast-deep-equal` does not support `NaN` or `SameValueZero` equality for dates
  - `nano-equal` does not strictly compare object property structure, array length, or object type, nor `SameValueZero`
    equality for dates
  - `react-fast-compare` does not support `NaN` or `SameValueZero` equality for dates, and does not compare `function`
    equality
  - `shallow-equal-fuzzy` does not strictly compare object type or regexp values, nor `SameValueZero` equality for dates
  - `underscore.isEqual` does not support `SameValueZero` equality for primitives or dates
  
  All of these have the potential of inflating the respective library's numbers in comparison to `fast-equals`, but it was
  the closest apples-to-apples comparison I could create of a reasonable sample size. It should be noted that `react`
  elements can be circular objects, however simple elements are not; I kept the `react` comparison very basic to allow it
  to be included.
  
  ## Development
  
  Standard practice, clone the repo and `npm i` to get the dependencies. The following npm scripts are available:
  
  - benchmark => run benchmark tests against other equality libraries
  - build => build `main`, `module`, and `browser` distributables with `rollup`
  - clean => run `rimraf` on the `dist` folder
  - dev => start `vite` playground App
  - dist => run `build`
  - lint => run ESLint on all files in `src` folder (also runs on `dev` script)
  - lint:fix => run `lint` script, but with auto-fixer
  - prepublish:compile => run `lint`, `test:coverage`, `transpile:lib`, `transpile:es`, and `dist` scripts
  - start => run `dev`
  - test => run AVA with NODE_ENV=test on all files in `test` folder
  - test:coverage => run same script as `test` with code coverage calculation via `nyc`
  - test:watch => run same script as `test` but keep persistent watcher