前言
这篇文章简单总结常用的深度比较方法,这些方法在react中用的特别多,特别是生命周期里面prop对比。因此,react和immutable天生结合性比较好。假设你项目中没有用immutable这种第三方库,那么实现深度比较的方法,在这里总结一下!
方法一
[JavaScript]
纯文本查看
复制代码
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 | function equalsObject (obj1,obj) { var p; if (obj1 === obj) { return true; } // some checks for native types first // function and sring if (typeof(obj1) === "function" || typeof(obj1) === "string" || obj1 instanceof String) { return obj1.toString() === obj.toString(); } // number if (obj1 instanceof Number || typeof(obj1) === "number") { if (obj instanceof Number || typeof(obj) === "number") { return obj1.valueOf() === obj.valueOf(); } return false; } // equalsObject(null,null) and equalsObject(undefined,undefined) do not inherit from the // Object.prototype so we can return false when they are passed as obj if (typeof(obj1) !== typeof(obj) || obj === null || typeof(obj) === "undefined") { return false; } function sort (o) { var result = {}; if (typeof o !== "object") { return o; } Object.keys(o).sort().forEach(function (key) { result[key] = sort(o[key]); }); return result; } if (typeof(obj1) === "object") { if (Array.isArray(obj1)) { // check on arrays return JSON.stringify(obj1) === JSON.stringify(obj); } else { // anyway objects for (p in obj1) { if (typeof(obj1[p]) !== typeof(obj[p])) { return false; } if ((obj1[p] === null) !== (obj[p] === null)) { return false; } switch (typeof(obj1[p])) { case 'undefined': if (typeof(obj[p]) !== 'undefined') { return false; } break; case 'object': if (obj1[p] !== null && obj[p] !== null && (obj1[p].constructor.toString() !== obj[p].constructor.toString() || !equalsObject(obj1[p],obj[p]))) { return false; } break; case 'function': if (obj1[p].toString() !== obj[p].toString()) { return false; } break; default: if (obj1[p] !== obj[p]) { return false; } } }; } } // at least check them with JSON return JSON.stringify(sort(obj1)) === JSON.stringify(sort(obj)); } var a = {a: 'text', b:[0,1]}; var b = {a: 'text', b:[0,1]}; var c = {a: 'text', b: 0}; var d = {a: 'text', b: false}; var e = {a: 'text', b:[1,0]}; var f = {a: 'text', b:[1,0], f: function(){ this.f = this.b; }}; var g = {a: 'text', b:[1,0], f: function(){ this.f = this.b; }}; var h = {a: 'text', b:[1,0], f: function(){ this.a = this.b; }}; var i = { a: 'text', c: { b: [1, 0], f: function(){ this.a = this.b; } } }; var j = { a: 'text', c: { b: [1, 0], f: function(){ this.a = this.b; } } }; var k = {a: 'text', b: null}; var l = {a: 'text', b: undefined};equalsObject(a,b) //trueequalsObject(f,g)//trueequalsObject(f,h)//false |
方法二
[JavaScript]
纯文本查看
复制代码
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 | function deepCompare(x, y) { var i, l, leftChain, rightChain; function compare2Objects(x, y) { var p; // remember that NaN === NaN returns false // and isNaN(undefined) returns true if (isNaN(x) && isNaN(y) && typeof x === 'number' && typeof y === 'number') { return true; } // Compare primitives and functions. // Check if both arguments link to the same object. // Especially useful on the step where we compare prototypes if (x === y) { return true; } // Works in case when functions are created in constructor. // Comparing dates is a common scenario. Another built-ins? // We can even handle functions passed across iframes if ((typeof x === 'function' && typeof y === 'function') || (x instanceof Date && y instanceof Date) || (x instanceof RegExp && y instanceof RegExp) || (x instanceof String && y instanceof String) || (x instanceof Number && y instanceof Number)) { return x.toString() === y.toString(); } // At last checking prototypes as good as we can if (!(x instanceof Object && y instanceof Object)) { return false; } if (x.isPrototypeOf(y) || y.isPrototypeOf(x)) { return false; } if (x.constructor !== y.constructor) { return false; } if (x.prototype !== y.prototype) { return false; } // Check for infinitive linking loops if (leftChain.indexOf(x) > -1 || rightChain.indexOf(y) > -1) { return false; } // Quick checking of one object being a subset of another. // todo: cache the structure of arguments[0] for performance for (p in y) { if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) { return false; } else if (typeof y[p] !== typeof x[p]) { return false; } } for (p in x) { if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) { return false; } else if (typeof y[p] !== typeof x[p]) { return false; } switch (typeof(x[p])) { case 'object': case 'function': leftChain.push(x); rightChain.push(y); if (!compare2Objects(x[p], y[p])) { return false; } leftChain.pop(); rightChain.pop(); break; default: if (x[p] !== y[p]) { return false; } break; } } return true; } if (arguments.length < 1) { return true; //Die silently? Don't know how to handle such case, please help... // throw "Need two or more arguments to compare"; } for (i = 1, l = arguments.length; i < l; i++) { leftChain = []; //Todo: this can be cached rightChain = []; if (!compare2Objects(arguments[0], arguments[i])) { return false; } } return true;} |
方法三
[JavaScript]
纯文本查看
复制代码
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | function countProps(obj) { var count = 0; for (k in obj) { if (obj.hasOwnProperty(k)) { count++; } } return count;};function objectEquals(v1, v2) { if (typeof(v1) !== typeof(v2)) { return false; } if (typeof(v1) === "function") { return v1.toString() === v2.toString(); } if (v1 instanceof Object && v2 instanceof Object) { if (countProps(v1) !== countProps(v2)) { return false; } var r = true; for (k in v1) { r = objectEquals(v1[k], v2[k]); if (!r) { return false; } } return true; } else { return v1 === v2; }} |
方法四
[JavaScript]
纯文本查看
复制代码
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | const hasOwnProperty = (obj1: any, obj2: any) => { switch (typeOf(obj1)) { case "object": return Object.prototype.hasOwnProperty.call(obj1, obj2); case "array": return typeOf(obj2) === "number" && obj2 >= 0 && obj1.length > obj2 ; default: return false; } }; const typeOf = (value) => Object.prototype.toString.call(value).replace(/\[|\]/gi, "").split(" ")[1].toLowerCase(); const length = (object) => { switch (typeOf(object)) { case "array": return object.length; case "object": return Object.keys(object).length; default: return 0; } }; const every = (obj, func) => typeOf(obj) === "array" ? obj.every(func) : Object.entries(obj).every(([key, value]: [any, any]) => func(value, key)); const equal = (obj1, obj2) => { switch (true) { case typeOf(obj1) === "function" && typeOf(obj2) === "function": return true; case obj1 === obj2: return true; case typeOf(obj1) === typeOf(obj2) && ["object", "array"].includes(typeOf(obj1)) && length(obj1) === length(obj2): return every(obj1, (value, key) => hasOwnProperty(obj2, key) && equal(value, obj2[key])); default: return false; } }; |
本文转自:https://www.haorooms.com/post/js_deepcompare