CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-vue--shared

Internal utility functions shared across Vue.js packages for DOM manipulation, type checking, and general utilities

Pending
Overview
Eval results
Files

equality-utilities.mddocs/

Equality and Comparison

Deep equality checking and comparison utilities with special handling for complex data types including dates, arrays, objects, and symbols.

Capabilities

Deep Equality Comparison

Functions for performing deep equality checks that handle JavaScript's complex equality semantics.

/**
 * Perform deep loose equality comparison between two values
 * Handles special cases for dates, symbols, arrays, and objects
 * @param a - First value to compare
 * @param b - Second value to compare  
 * @returns True if values are loosely equal
 */
function looseEqual(a: any, b: any): boolean;

/**
 * Find index of value in array using loose equality comparison
 * Uses looseEqual for comparison instead of strict equality
 * @param arr - Array to search in
 * @param val - Value to find
 * @returns Index of value or -1 if not found
 */
function looseIndexOf(arr: any[], val: any): number;

Usage Examples:

import { looseEqual, looseIndexOf } from "@vue/shared";

// Basic equality (same as === for primitives)
console.log(looseEqual(1, 1)); // true
console.log(looseEqual("hello", "hello")); // true
console.log(looseEqual(1, "1")); // false (different types)

// Date comparison (compares timestamps)
const date1 = new Date("2023-01-01");
const date2 = new Date("2023-01-01");
const date3 = new Date("2023-01-02");

console.log(looseEqual(date1, date2)); // true (same timestamp)
console.log(looseEqual(date1, date3)); // false (different timestamps)
console.log(date1 === date2); // false (different objects)

// Symbol comparison (always strict)
const sym1 = Symbol("test");
const sym2 = Symbol("test");
const sym3 = sym1;

console.log(looseEqual(sym1, sym2)); // false (different symbols)
console.log(looseEqual(sym1, sym3)); // true (same symbol)

// Array comparison (recursive)
const arr1 = [1, 2, { a: 3 }];
const arr2 = [1, 2, { a: 3 }];
const arr3 = [1, 2, { a: 4 }];

console.log(looseEqual(arr1, arr2)); // true (deep equal)
console.log(looseEqual(arr1, arr3)); // false (nested object differs)
console.log(arr1 === arr2); // false (different array objects)

// Object comparison (recursive)
const obj1 = { 
  name: "John", 
  age: 30, 
  hobbies: ["reading", "coding"],
  birth: new Date("1993-01-01")
};
const obj2 = { 
  name: "John", 
  age: 30, 
  hobbies: ["reading", "coding"],
  birth: new Date("1993-01-01")
};
const obj3 = { 
  name: "John", 
  age: 31, 
  hobbies: ["reading", "coding"],
  birth: new Date("1993-01-01")
};

console.log(looseEqual(obj1, obj2)); // true (deep equal)
console.log(looseEqual(obj1, obj3)); // false (age differs)

// Nested structure comparison
const complex1 = {
  users: [
    { id: 1, profile: { name: "Alice", tags: ["admin"] } },
    { id: 2, profile: { name: "Bob", tags: ["user"] } }
  ],
  settings: { theme: "dark", notifications: true }
};

const complex2 = {
  users: [
    { id: 1, profile: { name: "Alice", tags: ["admin"] } },
    { id: 2, profile: { name: "Bob", tags: ["user"] } }
  ],
  settings: { theme: "dark", notifications: true }
};

console.log(looseEqual(complex1, complex2)); // true

// Array indexOf with loose equality
const mixedArray = [
  1,
  "hello", 
  { name: "test" },
  [1, 2, 3],
  new Date("2023-01-01")
];

// Find equivalent values
console.log(looseIndexOf(mixedArray, 1)); // 0
console.log(looseIndexOf(mixedArray, { name: "test" })); // 2
console.log(looseIndexOf(mixedArray, [1, 2, 3])); // 3
console.log(looseIndexOf(mixedArray, new Date("2023-01-01"))); // 4

// Not found
console.log(looseIndexOf(mixedArray, { name: "other" })); // -1
console.log(looseIndexOf(mixedArray, [1, 2, 4])); // -1

Equality Comparison Rules

looseEqual follows these rules in order:

  1. Strict Equality: If a === b, return true
  2. Date Objects: Compare using getTime() if both are dates
  3. Symbols: Use strict equality (symbols are unique)
  4. Arrays: Compare length first, then recursively compare each element
  5. Objects: Compare key count first, then recursively compare each property
  6. Fallback: Convert both to strings and compare

Special Case Handling

Date Comparison:

const d1 = new Date("2023-01-01T00:00:00.000Z");
const d2 = new Date("2023-01-01T00:00:00.000Z");
looseEqual(d1, d2); // true - compares timestamps

Array vs Non-Array:

looseEqual([1, 2], "1,2"); // false - different types
looseEqual([], ""); // false - different types

Object Property Order:

looseEqual({ a: 1, b: 2 }, { b: 2, a: 1 }); // true - order doesn't matter

Missing vs Undefined Properties:

looseEqual({ a: 1 }, { a: 1, b: undefined }); // false - different key counts

Circular References:

const circular1: any = { name: "test" };
circular1.self = circular1;

const circular2: any = { name: "test" };
circular2.self = circular2;

// Will cause maximum call stack exceeded error
// looseEqual(circular1, circular2); // ❌ Don't do this

Performance Characteristics

  • Early Returns: Exits quickly for strict equality and type mismatches
  • Length Checks: Compares array/object sizes before deep comparison
  • Recursive: Can handle deeply nested structures (limited by call stack)
  • No Caching: Each comparison is independent (no memoization)

Common Use Cases

Form Validation:

function hasFormChanged(currentValues: any, originalValues: any) {
  return !looseEqual(currentValues, originalValues);
}

Array Operations:

function removeByValue(arr: any[], value: any) {
  const index = looseIndexOf(arr, value);
  if (index > -1) {
    arr.splice(index, 1);
  }
}

Change Detection:

function shouldUpdate(newProps: any, oldProps: any) {
  return !looseEqual(newProps, oldProps);
}

Limitations

  • Circular References: Will cause stack overflow
  • Function Comparison: Functions are compared by reference, not implementation
  • Class Instances: Compared as plain objects (only enumerable properties)
  • Prototype Chain: Only checks own properties, ignores prototype
  • Performance: Deep comparison can be expensive for large nested structures

Install with Tessl CLI

npx tessl i tessl/npm-vue--shared

docs

display-utilities.md

dom-configuration.md

environment-utilities.md

equality-utilities.md

html-security.md

index.md

normalization.md

object-utilities.md

reactive-flags.md

string-transformations.md

type-checking.md

tile.json