対象はすべて

6723 ワード

Javascriptでは等しく演算に「=」「==」などが含まれていますが、両者の違いは多くなくてもいいです.この文章では、将来どのように二つのオブジェクトが同じかどうかを判断しますか?
二つのオブジェクトが同じ属性を持っていて、それらの属性が同じ値を持っていると考えられます.この二つのオブジェクトは同じです.それでは、次の例を通して論証します.
var obj1 = {
    name: "Benjamin",
    sex : "male"
}

var obj2 = {
    name: "Benjamin",
    sex : "male"
}

//Outputs: false
console.log(obj1 == obj2);

//Outputs: false
console.log(obj1 === obj2);
上記の例では、「==」を使っても「===」を使ってもfalseに戻ります.主な原因は基本型のstringであり、numberは値によって比較し、対象(Date、Aray)及び一般対象はポインタが指すメモリ中のアドレスによって比較している.次の例を見てください.
var obj1 = {
    name: "Benjamin",
    sex : "male"
};

var obj2 = {
    name: "Benjamin",
    sex : "male"
};

var obj3 = obj1;

//Outputs: true
console.log(obj1 == obj3);

//Outputs: true
console.log(obj1 === obj3);

//Outputs: false
console.log(obj2 == obj3);

//Outputs: false
console.log(obj2 === obj3);
上記の例がtrueに戻るのは、Obj 1とOB 3のポインタがメモリ内の同じアドレスを指しているからです.対象に向かう言語(Java/C+)の値伝達と引用伝達の概念は似ています.
二つのオブジェクトが同じかどうかを判断するには、二つのオブジェクトの属性が同じかどうかを判断しますか?それとも属性に対応する値が同じか?二つのオブジェクトの値が同じかどうかを判断すると、次のようになります.
function isObjectValueEqual(a, b) {
    // Of course, we can do it use for in 
    // Create arrays of property names
    var aProps = Object.getOwnPropertyNames(a);
    var bProps = Object.getOwnPropertyNames(b);

    // If number of properties is different,
    // objects are not equivalent
    if (aProps.length != bProps.length) {
        return false;
    }

    for (var i = 0; i < aProps.length; i++) {
        var propName = aProps[i];

        // If values of same property are not equal,
        // objects are not equivalent
        if (a[propName] !== b[propName]) {
            return false;
        }
    }

    // If we made it this far, objects
    // are considered equivalent
    return true;
}

var obj1 = {
    name: "Benjamin",
    sex : "male"
};

var obj2 = {
    name: "Benjamin",
    sex : "male"
};

//Outputs: true
console.log(isObjectValueEqual(obj1, obj2));
ご覧のように、オブジェクトの値が等しいことを確認します.私たちは基本的に遍歴するオブジェクトの属性ごとに、それらが同じかどうかを確認します.この簡単な実現は私たちの例に適用されるが、多くの場合、処理できない.たとえば:
  • この属性値の一つがオブジェクトである場合ですか?
  • 属性値のうちの一つがNaNである場合(JavaScriptでは自分の唯一の価値に等しいですか?)
  • 属性の値がundefinedである場合、他のオブジェクトにはこの属性がない(したがって、計算結果は不確定ですか?)検査対象の「値が等しい」強力な方法があります.完璧なテストライブラリに頼って、様々な境界状況をカバーすることが望ましいです.UnderscoreとLo-Dashという名前があります.isEqual()法は、より良い処理深度オブジェクトの比較に用いられる.これらはこのように使えます.
  • // Outputs: true
    console.log(_.isEqual(obj1, obj2));
    
    最後にUnderscoreのisEqualの一部のソースコードを添付します.
      // Internal recursive comparison function for `isEqual`.
      var eq = function(a, b, aStack, bStack) {
        // Identical objects are equal. `0 === -0`, but they aren't identical.
        // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
        if (a === b) return a !== 0 || 1 / a === 1 / b;
        // A strict comparison is necessary because `null == undefined`.
        if (a == null || b == null) return a === b;
        // Unwrap any wrapped objects.
        if (a instanceof _) a = a._wrapped;
        if (b instanceof _) b = b._wrapped;
        // Compare `[[Class]]` names.
        var className = toString.call(a);
        if (className !== toString.call(b)) return false;
        switch (className) {
          // Strings, numbers, regular expressions, dates, and booleans are compared by value.
          case '[object RegExp]':
          // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
          case '[object String]':
            // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
            // equivalent to `new String("5")`.
            return '' + a === '' + b;
          case '[object Number]':
            // `NaN`s are equivalent, but non-reflexive.
            // Object(NaN) is equivalent to NaN
            if (+a !== +a) return +b !== +b;
            // An `egal` comparison is performed for other numeric values.
            return +a === 0 ? 1 / +a === 1 / b : +a === +b;
          case '[object Date]':
          case '[object Boolean]':
            // Coerce dates and booleans to numeric primitive values. Dates are compared by their
            // millisecond representations. Note that invalid dates with millisecond representations
            // of `NaN` are not equivalent.
            return +a === +b;
        }
        if (typeof a != 'object' || typeof b != 'object') return false;
        // Assume equality for cyclic structures. The algorithm for detecting cyclic
        // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
        var length = aStack.length;
        while (length--) {
          // Linear search. Performance is inversely proportional to the number of
          // unique nested structures.
          if (aStack[length] === a) return bStack[length] === b;
        }
        // Objects with different constructors are not equivalent, but `Object`s
        // from different frames are.
        var aCtor = a.constructor, bCtor = b.constructor;
        if (
          aCtor !== bCtor &&
          // Handle Object.create(x) cases
          'constructor' in a && 'constructor' in b &&
          !(_.isFunction(aCtor) && aCtor instanceof aCtor &&
            _.isFunction(bCtor) && bCtor instanceof bCtor)
        ) {
          return false;
        }
        // Add the first object to the stack of traversed objects.
        aStack.push(a);
        bStack.push(b);
        var size, result;
        // Recursively compare objects and arrays.
        if (className === '[object Array]') {
          // Compare array lengths to determine if a deep comparison is necessary.
          size = a.length;
          result = size === b.length;
          if (result) {
            // Deep compare the contents, ignoring non-numeric properties.
            while (size--) {
              if (!(result = eq(a[size], b[size], aStack, bStack))) break;
            }
          }
        } else {
          // Deep compare objects.
          var keys = _.keys(a), key;
          size = keys.length;
          // Ensure that both objects contain the same number of properties before comparing deep equality.
          result = _.keys(b).length === size;
          if (result) {
            while (size--) {
              // Deep compare each member
              key = keys[size];
              if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
            }
          }
        }
        // Remove the first object from the stack of traversed objects.
        aStack.pop();
        bStack.pop();
        return result;
      };
    
      // Perform a deep comparison to check if two objects are equal.
      _.isEqual = function(a, b) {
        return eq(a, b, [], []);
      };