isEqual() | Underscore JS 日本語リファレンス

第1引数と第2引数を見比べ型や値が同じなら「true」を返す関数。

■使用例

var obj = {
	music :  "弦楽四重奏によるドラゴンクエスト",
	author : "すぎやまこういち",
	game : {}
}
var obj2 = {
	music :  "弦楽四重奏によるドラゴンクエスト",
	author : "すぎやまこういち",
	game : {}
}
// re = true; 
var re = _.isEqual( obj, obj2 );

■内部構造

_.isEqual = function(a, b) {
// 引数を内部関数eq()に代入し結果を返す。
    return eq(a, b);
  };
  var eq = function(a, b, aStack, bStack) {
    if (a === b) return a !== 0 || 1 / a === 1 / b;

// 「null = undefined」用
    if (a == null || b == null) return a === b;
    
// a,b が _の instance だった時。
    if (a instanceof _) a = a._wrapped;
    if (b instanceof _) b = b._wrapped;
    
// 第1引数の型が文字列になる。
// Array だったら [object Array]、Object だったら [object Object]、arguments は [object Arguments]、function は [object Function]、
// 文字列だったら [object String]、数字は [object Number]。
    var className = toString.call(a);
    
// 第1引数と第2引数の型が違ったら、false を返す。 
    if (className !== toString.call(b)) return false;

// 型の種類によって対応を分ける。 
    switch (className) {
      
// 型が 正規表現 だったら。
      case "[object RegExp]":
      // RegExps are coerced to strings for comparison (Note: "" + /a/i === "/a/i")
      
// 型が 文字列 だったら。
      case "[object String]":
        return "" + a === "" + b;

// 型が 数字 だったら。
      case "[object Number]":
        if (+a !== +a) return +b !== +b;
        return +a === 0 ? 1 / +a === 1 / b : +a === +b;

// 型が Date Object だったら。      
      case "[object Date]":

// 型が 真偽値 だったら。
      case "[object Boolean]":
        return +a === +b;
    }
    var areArrays = className === "[object Array]";

// 型が 配列 じゃなかったら。
    if (!areArrays) {

// 第1引数もしくは第2引数の型が object でない場合。
      if (typeof a != "object" || typeof b != "object") return false;
      var aCtor = a.constructor, bCtor = b.constructor;

// 第1引数と第2引数の Constructor が違うなど下記条件が全部 true なら return false を返す。      
      if (aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor &&
                               _.isFunction(bCtor) && bCtor instanceof bCtor)
                          && ("constructor" in a && "constructor" in b)) {
        return false;
      }
    }
// //型が 配列 じゃなかったら。

// 再帰処理された時は、各値の出所の配列(Object)などが入っている。
    aStack = aStack || [];
    bStack = bStack || [];
    var length = aStack.length;

// 配列、Object の値がまた 配列 か Object の時、while 文が実行される。
    while (length--) {
      if (aStack[length] === a) return bStack[length] === b;
    }

// 配列などの各値を調べる時に元の配列などを入れておく。
    aStack.push(a);
    bStack.push(b);

// 型が 配列 だったら。
    if (areArrays) {
    	
// 第1引数と第2引数のそれぞれの配列の長さが違ったら false を返す。  
      length = a.length;
      if (length !== b.length) return false;

// 配列の各値を再度 eq() に代入。false が返された時、false を返す。 
      while (length--) {
        if (!eq(a[length], b[length], aStack, bStack)) return false;
      }
      
// 型が Object だったら。
    } else {

// 第1引数「Object」のkey値の配列を作成。
      var keys = _.keys(a), key;
      length = keys.length;
      
// 第1引数と第2引数のkey値の配列の長さが違ったら false を返す。
      if (_.keys(b).length !== length) return false;

// 第1引数「Object」の各key値とその値を比べる while ループ。
      while (length--) {
        key = keys[length];

// 第1引数の key値を第2引数が持っていて、 eq(a[key], b[key], aStack, bStack) の結果が true ならこの if は実行されない。        
        if (!(_.has(b, key) && eq(a[key], b[key], aStack, bStack))) return false;
      }
    }
    // Remove the first object from the stack of traversed objects.
    aStack.pop();
    bStack.pop();
    
// 途中で return false; されなかったら true を返す。
    return true;
  };

このページのトップへ戻る