npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@dafengzhen/deep-diff

v0.1.1

Published

Deep object comparison and diff engine with support for cyclic references, arrays, dates, and customizable options

Readme

deep-diff

GitHub License npm version PRs Welcome

English

一个零依赖的 TypeScript 深度对象比较与差异分析库。它能生成详细的差异树,支持循环引用、数组、日期、正则表达式以及可自定义的选项。

特性

  • 零依赖 — 轻量且快速
  • 循环引用检测 — 安全比较包含循环引用的对象
  • 差异树输出 — 结构化的、可遍历的差异结果树
  • 差异统计 — 新增、删除、修改、未变更节点的计数
  • 高度可定制 — 可配置最大深度、忽略的键、键排序等
  • Date 与 RegExp 支持 — 正确处理 DateRegExp 的值比较
  • TypeScript 优先 — 完整类型定义,开箱即用

安装

npm install @dafengzhen/deep-diff
yarn add @dafengzhen/deep-diff
pnpm add @dafengzhen/deep-diff

使用

基本差异比较

import { diff, DiffType } from '@dafengzhen/deep-diff';

const oldObj = { name: 'Alice', age: 30 };
const newObj = { name: 'Alice', age: 31 };

const result = diff(oldObj, newObj);

console.log(result.changed); // true
console.log(result.children[0].diffType); // DiffType.Equal
console.log(result.children[1].diffType); // DiffType.Modified

深度相等检查

import { deepEqual } from '@dafengzhen/deep-diff';

deepEqual({ a: 1, b: { c: 2 } }, { a: 1, b: { c: 2 } }); // true
deepEqual({ a: 1 }, { a: 2 }); // false

查找所有差异

import { diff, findDifferences } from '@dafengzhen/deep-diff';

const result = diff(
  { name: 'Alice', age: 30, city: 'NYC' },
  { name: 'Alice', age: 31, city: 'LA' },
);

const changes = findDifferences(result);
// [
//   { key: 'age', diffType: 'modified', ... },
//   { key: 'city', diffType: 'modified', ... }
// ]

获取变更路径

import { diff, getChangedPaths } from '@dafengzhen/deep-diff';

const result = diff({ user: { name: 'Alice', age: 30 } }, { user: { name: 'Bob', age: 30 } });

console.log(getChangedPaths(result)); // ['user.name']

获取差异统计

import { diff, getDiffStats } from '@dafengzhen/deep-diff';

const result = diff({ a: 1, b: 2, c: 3 }, { a: 1, b: 20, d: 4 });

console.log(getDiffStats(result));
// { total: 5, added: 1, removed: 1, modified: 1, equal: 2 }

检查是否存在变更

import { diff, hasChanges } from '@dafengzhen/deep-diff';

hasChanges(diff({ a: 1 }, { a: 1 })); // false
hasChanges(diff({ a: 1 }, { a: 2 })); // true

使用选项

import { diff } from '@dafengzhen/deep-diff';

const result = diff(
  { stable: true, updatedAt: '2026-01-01' },
  { stable: true, updatedAt: '2026-01-02' },
  'root',
  [],
  {
    ignoreKeys: ['updatedAt'], // 比较时忽略的键
    maxDepth: 5, // 最大遍历深度
    sortKeys: true, // 对对象键进行排序以保持一致的输出
  },
);

循环引用

import { diff } from '@dafengzhen/deep-diff';

const left: any = { value: 1 };
const right: any = { value: 2 };
left.self = left;
right.self = right;

const result = diff(left, right);
// 安全处理循环引用,不会导致无限递归

API

diff(oldValue, newValue, key?, path?, options?, depth?)

计算两个值之间的差异,返回 DiffNode 树。

| 参数 | 类型 | 默认值 | 描述 | | ---------- | ---------------------- | -------- | ---------------------- | | oldValue | unknown | — | 原始值 | | newValue | unknown | — | 用于比较的新值 | | key | number \| string | 'root' | 该值在父级中的键或索引 | | path | (number \| string)[] | [] | 该值的完整路径 | | options | DiffOptions | {} | 差异比较的配置选项 | | depth | number | 0 | 当前嵌套深度 |

deepEqual(left, right)

对两个值进行深度相等比较。如果深度相等则返回 true

findDifferences(node)

查找差异树中所有包含变更的节点。返回 DiffNode 对象数组。

getChangedPaths(node)

获取所有变更节点的字符串路径(例如 'user.address[0].city')。

getDiffStats(node)

计算差异树中差异的统计信息。返回 { total, added, removed, modified, equal }

getNodeAtPath(node, path)

从差异树中获取指定路径的 DiffNode

hasChanges(node)

检查差异树中是否存在任何变更。

类型

DiffNode<T>

| 属性 | 类型 | 描述 | | ----------- | ------------------ | ------------------------ | | changed | boolean | 该节点是否表示存在变更 | | children | DiffNode[] | 子差异节点 | | diffType | DiffType | 差异类型 | | key | number \| string | 该节点在父级中的键或索引 | | leaf | boolean | 是否为叶子节点 | | newValue? | T | 新值(如果可用) | | oldValue? | T | 原始值(如果可用) | | path | DiffPath | 该节点的完整路径 | | valueType | ValueType | 值的类型 |

DiffType(枚举)

  • Added — 值被新增(仅存在于新值中)
  • Equal — 值无差异
  • Modified — 值被修改
  • Removed — 值被删除(仅存在于旧值中)

DiffOptions

| 属性 | 类型 | 默认值 | 描述 | | ---------------- | ---------- | ------ | ------------------------------------ | | arrayMatchKey? | string | — | 用于匹配数组元素的键 | | ignoreKeys? | string[] | — | 比较时忽略的键 | | maxDepth? | number | — | 最大遍历深度(默认无限制) | | sortKeys? | boolean | true | 是否对对象键进行排序以保持一致的输出 |

License

MIT