【问题标题】:Compare javascript objects with `undefined` attributes?将javascript对象与“未定义”属性进行比较?
【发布时间】:2016-10-25 04:43:08
【问题描述】:

lodash/下划线.isEqual(o1,o2)assert.deepEqual(o1,o2) 应该如何处理具有undefined 值的对象?我想要一个在这种情况下返回 true 的 deepEquals:

 var left = {a: true, b: undefined};
 var right = {a: true};
 assert(_.isEqual(left, right))   // returns false

或者,有没有办法测试属性 b 是否定义为 undefined 而不是简单地未定义?

 typeof left.b //  "undefined"
 typeof right.b // "undefined

 left.b === undefined  // true
 right.b === undefined // true

现在我使用它是为了方便,但怀疑它会产生假阴性:

var isEqual = function(o1, o2) { return JSON.stringify(o1) === JSON.stringify(o2)}

How to check for "undefined" in JavaScript?

【问题讨论】:

    标签: javascript node.js mocha.js


    【解决方案1】:

    或者,有没有办法测试属性 b 是定义为未定义还是未定义?

    是的,有很多方法可以区分这些情况。

    "b" in left; // true
    "b" in right; // false
    
    left.hasOwnProperty("b"); // true
    right.hasOwnProperty("b"); // false
    
    left.propertyIsEnumerable('b'); // true
    right.propertyIsEnumerable('b'); // false
    
    Object.keys(left).includes("b"); // true
    Object.keys(right).includes("b"); // false
    
    Object.getOwnPropertyNames(left).includes("b"); // true
    Object.getOwnPropertyNames(right).includes("b"); // false
    
    Reflect.ownKeys(left).includes("b"); // true
    Reflect.ownKeys(right).includes("b"); // false
    
    !!Object.getOwnPropertyDescriptor(left, 'b'); // true
    !!Object.getOwnPropertyDescriptor(right, 'b'); // false
    
    !!Reflect.getOwnPropertyDescriptor(left, 'b'); // true
    !!Reflect.getOwnPropertyDescriptor(right, 'b'); // false
    
    !!(o => {for(var p in o) if(p==='b') return 1; return 0;})(left); // true
    !!(o => {for(var p in o) if(p==='b') return 1; return 0;})(right); // false
    

    看了带注释的源码,我觉得这样就够了:

    _.myEqual = function(a,b) {
      var keys = _.keys;
      _.keys = function(obj) { /* Hijack _.keys to filter out undefined properties */
        return _.filter(keys(obj), function(key){ return obj[key] !== void 0; });
      };
      var ret = _.isEqual(a,b); /* Call usual comparator, will use modified _.keys */
      _.keys = keys; /* Restore usual _.keys */
      return ret;
    }
    

    _.myEqual = function(a,b) {
      var keys = _.keys;
      _.keys = function(obj) {
        return _.filter(keys(obj), key => obj[key] !== void 0);
      };
      var ret = _.isEqual(a,b);
      _.keys = keys;
      return ret;
    }
    console.log(_.myEqual({a: true, b: undefined}, {a: true})); // true
    console.log(_.myEqual({a: true, b: true}, {a: true})); // false
    <script src="https://raw.githubusercontent.com/jashkenas/underscore/master/underscore.js"></script>

    【讨论】:

    • 为了完整起见,您可以添加propertyIsEnumerable
    【解决方案2】:

    这将去除 undefined 并保留 assert.deepEqual_.isEqual 的其他理想属性,例如对属性顺序不敏感:

    assert.jsonEqual = function(a, b) { return deepEqual(JSON.parse(JSON.stringify(a)), JSON.parse(JSON.stringify(b))) }

    【讨论】:

      【解决方案3】:

      left 不等于 right 的原因是因为 b 是左侧的属性,即使它未定义。

      要检查属性是否存在于对象上,即使它是未定义的(如左示例中),请使用 in 运算符:

      "b" in left; // true
      "b" in right; // false
      

      Javascript in 运算符:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/in


      检查属性是否存在且未定义的快速函数:

      function propertyExistsAndIsUndefined(object, property) {
          return property in object && typeof object[property] === "undefined";
      }
      

      【讨论】:

      • 为什么不只是property in object && object[property] === undefined
      • undefined 可能被其他人覆盖。因为undefined 只是一个值未定义的全局对象的属性,你可以写undefined = true 现在object[property] === undefined 将返回false。 (现代浏览器不允许undefined 不可写,但仍然。)undefined 也不是保留字,所以我想你也可以创建一个名为undefined 的局部变量。 typeof 的结果永远不会改变,使它更可靠。如果是这样,那么你手上可能会有更大的问题。
      • object[property] === void 0 也可以工作,因为void 运算符的计算结果总是未定义。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-23
      • 1970-01-01
      • 2022-07-12
      • 2021-10-13
      • 2013-06-08
      相关资源
      最近更新 更多