获取两个 javascript 对象的增量

2023-11-21

我有两个大型的嵌套 JavaScript 对象,我想比较它们并创建一个仅代表差异的对象。我打算用它来创建 PATCH 请求。

Given oldObj and newObj:

  • 仅在的属性newObj应该在差异中
  • 仅在的属性oldObj应该在差异中
  • 两个对象上的属性应使用来自的值newObj如果该值是数组、字符串或数字
  • 应该递归比较对象
  • 无需花哨合并数组,完全替换即可

这可能看起来像重复的,但我不认为它是重复的。此解决方案(1)仅一层深(下面的答案是非递归的,在数组上爆炸,并且不是双向的)。该解决方案(2)返回未更改的属性不是双向的。

目标输入/输出:

diff({a:1},{a:0}); // {a:0}

diff({a:1},{b:1}); // {a:1,b:1}

diff({
  a: { x: 1 },
  b: 1
},
{
  a: { x: 0 },
  b: 1
}) // {a:{x:0}}

diff({a:[1,3,5,7]},{a:[1,3,7]}); // {a:[1,3,7]} 

我正在使用以下从解决方案 1 修改而来的方法。它满足除diff({a:1},{b:1}) // {a:1,b:1}因为它只在一个方向进行比较。

jsonDiff = function(oldObject, newObject) {
  var diff, i, innerDiff;
  diff = {};
  for (i in newObject) {
    innerDiff = {};
    if (_.isArray(newObject[i])) {
      if (!_.isEqual(newObject[i], oldObject[i])) {
        diff[i] = newObject[i];
      }
    } else if (typeof newObject[i] === 'object') {
      innerDiff = jsonDiff(oldObject[i], newObject[i]);
      if (!_.isEmpty(innerDiff)) {
        diff[i] = innerDiff;
      }
    } else if (!oldObject) {
      diff[i] = newObject[i];
    } else if (!oldObject.hasOwnProperty(i)) {
      diff[i] = newObject[i];
    } else if (oldObject[i] !== newObject[i]) {
      diff[i] = newObject[i];
    }
  }
  return diff;
};

我见过jsonDiffPatch库,但我不需要它创建的所有元数据,只需要原始差异对象。有没有一个迷你图书馆可以做到这一点?似乎有必要实施PATCH很好,但我找不到。有人对此有一个小要点吗?


这是一个应该适合您的函数,注释多于代码:

// diffObjs: return differences between JavaScript values
//
// Function:
//
//    Compare two JavaScript values, and return a two-element
//    array that contains a minimal representation of the difference
//    between the two.
//
//    Values may be scalar (e.g., string, integer, boolean) or objects,
//    including arrays.  When the two values match exactly, that is,
//    if the '===' operator between the two would return 'true', we return NULL.
//    
//    When the result contains an object or array, only data, not references,
//    are copied from the arguments.  This makes for a large size result
//    but one whose manipulation will not affect the original arguments.
//
// Args:
//    v1, v2: values to compare
//
// Specific behaviors:
//
//    *Return NULL if v1 === v2*
//
//    This happens when two scalar (non-object) values match, or when the same
//    object or array is passed in both arguments.
//    e.g.,
//        
//        var my_obj = { member1: 0, member1: 'dog' };
//        var my_array = [ 1, 'cat' ];
//        var my_int = 7;
//        var no_val = null;
//
//        diffObjs(my_int, my_int)        ==> NULL
//        diffObjs(1, 1)                  ==> NULL
//        diffObjs(my_obj, my_obj)        ==> NULL
//        diffObjs({x:1,y:2}, {x:1,y:2})  ==> NULL
//        diffObjs(my_array, my_array)    ==> NULL
//        diffObjs([1,'a'], [1,'1'])      ==> NULL
//        diffObjs(null, null)            ==> NULL
//        diffObjs(no_val, null)          ==> NULL
//
//    *Return copies of v1 and v2 on type mismatch*:
//
//    When type of v1 and v2 are different or one is an array and the other
//    is an object, the result array will contain exect copies of both
//    v1 and v2.
//
//    *Return minimal representation of differences among non-array objects*:
//
//    Otherwise, when two objects are passed in, element 0
//    in the result array contains the members and their values
//    that exist in v1 but not v2, or members that exist in both
//    v1 and v2 that have different values.  Element 1 contains
//    the same but with respect to v2, that is members and their
//    values that exist in v2 but not v1, or members that exist in
//    both v1 and v2 that have different values.
//    
//    Note: The members are represented in the result objects only when
//    they are specific to the object of the corresponding value argument
//    or when the members exist in both and have different values.  The
//    caller therefore can tell whether the object mismatch exists 
//    because of specificity of a member to one object vs. a mismatch
//    in values where one is null and the other is not.
//
//    Examples:
//        diffObjs({a:10, b:"dog"}, {a:1, b:"dog"}    ==> [ {a:10}, {a:1} ]
//        diffObjs({a:10},          {a:10, b:"dog"}   ==> [ {}, {b:"dog"} ]
//        diffObjs({a:10, c:null},  {a:10, b:"dog"}   ==> [ {c:null}, {b:"dog"} ]
//        diffObjs({a:[1], b:"cat"},{a:1, b:"dog"}    ==> [ {a:[1], b:"cat"}, {a:1, b:"dog"} ]
//        diffObjs(
//            {a:{ m1:"x", m2:"y"}, b:3 },
//            {a:{ m1:"x", m2:"z", m3:1 }, b:3 } )    ==> [ {a:{m2:"y"}}, {a:{m2:"z",m3:1}} ]
//
//    *Return copies of compared arrays when differing by position or value*
//
//    If the two arguments arrays, the results in elements 0 and 1
//    will contain results in array form that do not match with respect
//    to both value and order.  If two positionally corresponding
//    elements in the array arguments have identical value (e.g., two
//    scalars with matching values or two references to the same object), 
//    the corresponding values in the array will be null.  The
//    cardinality of the arrays within the result array will therefore
//    always match that of the corresponding arguments.
//
//    Examples:
//        diffObjs([1,2],        [1,2])   ==> [ [null,null], [null,null] ]
//        diffObjs([1,2],        [2,1])   ==> [ [1,2], [2,1] ]
//        diffObjs([1,2],        [1,2,3]) ==> [ [1,2,null], [2,1,3] ]
//        diffObjs([1,1,2,3],    [1,2,3]) ==> [ [null,1,2,3], [null,2,3] ]
//

var diffObjs = function(v1, v2) {

    // return NULL when passed references to
    // the same objects or matching scalar values
    if (v1 === v2) {
        return null;
    }
    var cloneIt = function(v) {
        if (v == null || typeof v != 'object') {
            return v;
        }

        var isArray = Array.isArray(v);

        var obj = isArray ? [] : {};
        if (!isArray) {
            // handles function, etc
            Object.assign({}, v);
        }

        for (var i in v) {
            obj[i] = cloneIt(v[i]);
        }

        return obj;
    }

    // different types or array compared to non-array
    if (typeof v1 != typeof v2 || Array.isArray(v1) != Array.isArray(v2)) {
        return [cloneIt(v1), cloneIt(v2)];
    }

    // different scalars (no cloning needed)
    if (typeof v1 != 'object' && v1 !== v2) {
        return [v1, v2];
    }

    // one is null, the other isn't
    // (if they were both null, the '===' comparison
    // above would not have allowed us here)
    if (v1 == null || v2 == null) {
        return [cloneIt(v1), cloneIt(v2)]; 
    }

    // We have two objects or two arrays to compare.
    var isArray = Array.isArray(v1);

    var left = isArray ? [] : {};
    var right = isArray ? [] : {};

    for (var i in v1) {
        if (!v2.hasOwnProperty(i)) {
            left[i] = cloneIt(v1[i]);
        } else {
            var sub_diff = diffObjs(v1[i], v2[i]);
            // copy the differences between the 
            // two objects into the results.
            // - If the object is array, use 'null'
            //   to indicate the two corresponding elements
            //   match.
            //
            // - If the object is not an array, copy only
            //   the members that point to an unmatched
            //   object.
            if (isArray || sub_diff) { 
                left[i] = sub_diff ? cloneIt(sub_diff[0]) : null;
                right[i] = sub_diff ? cloneIt(sub_diff[1]) : null;
            }
        }
    }

    for (var i in v2) {
        if (!v1.hasOwnProperty(i)) {
            right[i] = cloneIt(v2[i]);
        }
    }

    return [ left, right];
};
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

获取两个 javascript 对象的增量 的相关文章

随机推荐

  • “现在无法切换到旧模式” - tls.connect 函数中的 Node.JS apn 模块错误

    我正在尝试实现 Node JS apn 模块来连接到 APNS Apple 推送通知服务 以从运行 Ubuntu 12 04 的 Amazon EC2 实例上托管的节点服务器 使用 ExpressJS 将通知推送到 iPhone 设备 我收
  • http请求会自动重试吗?

    我正在尝试使用 GoLang 将数据推送到 apache 服务器 假设我的apache服务器暂时停止了 然后我的http请求会自动重试 我正在使用这个声明 resp err http DefaultClient Do req if err
  • 如何将重力应用于弹跳球应用程序?

    我编写了一个相当简单的java应用程序 它允许您拖动鼠标 并根据您拖动鼠标的长度 它会朝那个方向射出一个球 并在球移动时从墙壁上弹起 这是一个快速截图 替代文本http img222 imageshack us img222 3179 ba
  • 不同的WAR文件,共享资源

    假设您有多个应用程序 它们共享相同的代码和大多数其他资源 但外观和感觉有所不同 一些标签发生变化等 想想品牌 如果每个 Web 应用程序都放入自己的 WAR 文件中 那么您将共享资源放在哪里 我已经使用类路径来共享类和属性文件 但是 jav
  • PostgreSQL 将尾随零添加到数字中

    最近我将一个数据库迁移到 PostgreSQL 其中一些列定义为numeric 9 3 and numeric 9 4 在测试应用程序时 我发现当数据保存到这些列时 插入的值中会添加尾随零 我正在使用 Hibernate 我的日志显示为准备
  • IE10 似乎不喜欢放置文件时的放置事件

    我有一个简单的 Web 应用程序 它使用 HTML5 中的 filereader api 来通过拖放接受文件上传 将文件拖到网页上时 将触发正确的拖动事件 但是当我放下文件时 IE 只是打开它而不是让 JS 处理它 删除代码非常基本 thi
  • 根据屏幕密度/尺寸了解(以编程方式)使用哪个资源文件夹的最简单方法

    有没有办法准确地知道 Android 在执行期间选择了哪种布局 和其他资源 runtime支持多屏幕时基于屏幕密度和尺寸 我需要知道文件夹的名称 EDIT 我需要知道文件夹的名称以编程方式 如果您这样做只是为了调试目的 我建议您这样做 对于
  • 将 install.packages 与自定义临时目录一起使用

    我想安装一个具有无权访问权限的安全配置文件的软件包 tmp 但有自己的临时目录 例如 tmp jeroen 然而即使我尝试通过TMPDIR环境变量 它仍然失败 因为它尝试使用 tmp 下面是一个使用的玩具示例拉普装甲 and Unix工具
  • Xcode 错误:无法启动 [目录] -- 无效的主机字符串:'localhost'

    我正在尝试在命令行工具中运行以下代码 import
  • 在 LINQ 查询中获取当前枚举器(迭代器?)。就像 for 循环中的当前索引一样

    是否可以在 LINQ 查询中获取当前的枚举器 和迭代器 不知道哪个术语是正确的 例如 我尝试创建所有当前加载的程序集的 XML 输出 通过 LINQ to XML Dim xmldoc As XDocument New XDocument
  • PHP - 浮点数精度[重复]

    这个问题在这里已经有答案了 a 35 b 34 99 echo a b 结果为 0 009999999999998 这是怎么回事 我想知道为什么我的程序不断报告奇怪的结果 为什么 PHP 没有返回预期的 0 01 因为浮点运算 实数运算 对
  • 带条件“显示数据库”

    我想查询 MySql 数据库 以根据提供的条件 应用于数据库名称的条件 向我显示所有现有数据库 现在由于我的条件很复杂 简单的 LIKE 条件是不够的 我需要使用常规的 WHERE 子句 任何人都可以提供如何做到这一点的示例吗 USE IN
  • PHP 中的“GLOBAL”和“STATIC”变量有什么区别?

    PHP 中的 GLOBAL 变量和 STATIC 变量到底有什么区别 当我们想在多个函数中使用一个变量时 更适合使用哪一个 Thanks 静态变量仅意味着 var 属于一个类 但可以引用而无需实例化该类 全局变量位于全局命名空间中 可以被任
  • Perl 中的字符串与“eq”与“==”进行比较[重复]

    这个问题在这里已经有答案了 我 一个完全的 Perl 新手 正在做字符串比较if陈述 如果我执行以下操作 if str1 taste str2 waste 我看到了正确的结果 即 如果条件匹配 它将评估 then 块 但我看到这些警告 参数
  • 如何在 iText XMLWorker 中摆脱 Helvetica?

    我们使用 iText 从 Java 代码生成 PDF 文件 这在大多数情况下工作得很好 几天前 我们开始生成 PDF A 而不是需要嵌入所有字体的普通 PDF 文件 iTextDocument大部分是定制的PdfPTable以及我们直接控制
  • Java:多对象变量(静态)

    我是面向对象编码的新手 并且遇到以下问题 注意this解决方案是我的问题的一部分 我需要一个许多对象可以引用的变量 但为每个对象保留一些 私有 信息 更具体地说 我创建了一个名为Worker我希望该类的每个对象都有一个唯一的类型 IDint
  • Android Studio - 设备文件资源管理器停止工作

    几天来 Android Studio 的设备文件资源管理器向我显示了以下消息 执行 shell 命令 pm list 包时出错 并且无法从数据文件夹中查看文件和应用程序 例如从我的 Flutter 应用程序获取数据库 有什么想法可以解决这个
  • Javascript Jupyter Notebook 如何获取代码单元格内容?

    有一个类似的问题here 但它是关于使用 python 代码读取 markdown 单元格 我想使用 JavaScript 例如在 Jupyter Notebook 前端扩展中 来读取代码单元中的源代码 我想对代码进行分析 然而 如果我只是
  • Android Activity 过渡动画

    我想要实现的是 使用现有活动的过渡动画启动一个新活动only 我想向上滑动当前活动 新活动将位于当前活动的后面 这是向上滑动的动画 R layout slide up
  • 获取两个 javascript 对象的增量

    我有两个大型的嵌套 JavaScript 对象 我想比较它们并创建一个仅代表差异的对象 我打算用它来创建 PATCH 请求 Given oldObj and newObj 仅在的属性newObj应该在差异中 仅在的属性oldObj应该在差异