JSON 개체가 변경되지 않았음을 확인하는 방법은 무엇입니까?
JSON.stringify의 MDN 매뉴얼에 따르면:
어레이가 아닌 개체의 속성은 특정 순서로 문자열화되지 않습니다.문자열화 내에서 동일한 개체 내의 속성 순서에 의존하지 마십시오.
오브젝트의 문자열화 버전을 캐싱하고 후속 문자열화 버전과 비교하여 오브젝트가 변경되었는지 여부를 판단하고 싶었습니다.그것은 대상을 반복적으로 반복하고 비교하는 것보다 훨씬 간단해 보였다.문제는 JSON.stringify 함수는 결정론적 함수가 아니기 때문에 같은 오브젝트를 문자열화할 때 기술적으로 다른 문자열을 얻을 수 있다는 것입니다.
그 밖에 어떤 옵션이 있습니까?아니면 객체의 동일성을 판단하기 위해 엉터리 비교 함수를 작성해야 합니까?
이것은 다양한 JavaScript 엔진이 오브젝트 속성을 내부적으로 추적하는 방식 때문이라고 확신합니다.예를 들어 다음과 같습니다.
var obj = {
"1" : "test",
"0" : "test 2"
};
for(var key in obj) {
console.log(key);
}
로그 1, 0 이 기록됩니다.파이어폭스는 0, V8에서는 1(Chrome 및 NodeJS).따라서 결정론적이어야 할 경우 어레이에 저장된 각 키를 반복하고 어레이를 정렬한 다음 해당 어레이를 루프하여 각 속성을 별도로 문자열화해야 합니다.
제가 쓴 작은 도우미 JSON.sortify를 시도해 보세요.
지금까지의 답변과는 대조적으로
- 임의의 레벨의 네스팅으로 동작합니다.
- 숫자 키를 처리할 수 있습니다.
- 키의 특수 문자를 이스케이프하다
- 파라미터뿐만 아니라 거의 사용되지 않는 파라미터도 받아들입니다.
- (필요에 따라) 순환 참조에 TypeError를 발생시킵니다.
- '필터'
undefined및 toJSON()
다음은 제가 작성한 결정론적 JSON.stringify()의 구현입니다(Underscore.js 사용).(배열되지 않은) 오브젝트를 (배열로) 정렬된 키와 값의 쌍으로 재귀적으로 변환한 후 문자열화합니다.여기 코더월 게시물 원본입니다.
문자열화:
function stringify(obj) {
function flatten(obj) {
if (_.isObject(obj)) {
return _.sortBy(_.map(
_.pairs(obj),
function(p) { return [p[0], flatten(p[1])]; }
),
function(p) { return p[0]; }
);
}
return obj;
}
return JSON.stringify(flatten(obj));
}
해석:
function parse(str) {
function inflate(obj, pairs) {
_.each(pairs, function(p) {
obj[p[0]] = _.isArray(p[1]) ?
inflate({}, p[1]) :
p[1];
});
return obj;
}
return inflate({}, JSON.parse(str));
}
최근에는 오브젝트를 문자열화하는 결정론적 방법을 사용하고 있습니다.또한 JSON에 오브젝트 문자열라이즈 순서를 적어두었습니다.이것에 의해, 상기의 딜레마가 해결됩니다.http://stamat.wordpress.com/javascript-object-ordered-property-stringify/
또, 커스텀 해시 테이블 실장도 하고 있었습니다.이것 역시 http://stamat.wordpress.com/javascript-quickly-find-very-large-objects-in-a-large-array/의 토픽과 관련되어 있습니다.
//SORT WITH STRINGIFICATION
var orderedStringify = function(o, fn) {
var props = [];
var res = '{';
for(var i in o) {
props.push(i);
}
props = props.sort(fn);
for(var i = 0; i < props.length; i++) {
var val = o[props[i]];
var type = types[whatis(val)];
if(type === 3) {
val = orderedStringify(val, fn);
} else if(type === 2) {
val = arrayStringify(val, fn);
} else if(type === 1) {
val = '"'+val+'"';
}
if(type !== 4)
res += '"'+props[i]+'":'+ val+',';
}
return res.substring(res, res.lastIndexOf(','))+'}';
};
//orderedStringify for array containing objects
var arrayStringify = function(a, fn) {
var res = '[';
for(var i = 0; i < a.length; i++) {
var val = a[i];
var type = types[whatis(val)];
if(type === 3) {
val = orderedStringify(val, fn);
} else if(type === 2) {
val = arrayStringify(val);
} else if(type === 1) {
val = '"'+val+'"';
}
if(type !== 4)
res += ''+ val+',';
}
return res.substring(res, res.lastIndexOf(','))+']';
}
밑줄 또는 Lodash 사용:
var sortByKeys = function(obj) {
if (!_.isObject(obj)) {
return obj;
}
var sorted = {};
_.each(_.keys(obj).sort(), function(key) {
sorted[key] = sortByKeys(obj[key]);
});
return sorted;
};
var sortedStringify = function() {
arguments[0] = sortByKeys(arguments[0]);
return JSON.stringify.apply(this, arguments);
};
최신 Chrome 및 Firefox에서 작동합니다.
JSFiddle 여기: http://jsfiddle.net/stchangg/ruC22/2/
최근에 비슷한 사용 사례가 있습니다.다음 코드는 종속성이 없으며 모든 브라우저에서 작동합니다.
function stringify(obj) {
var type = Object.prototype.toString.call(obj);
// IE8 <= 8 does not have array map
var map = Array.prototype.map || function map(callback) {
var ret = [];
for (var i = 0; i < this.length; i++) {
ret.push(callback(this[i]));
}
return ret;
};
if (type === '[object Object]') {
var pairs = [];
for (var k in obj) {
if (!obj.hasOwnProperty(k)) continue;
pairs.push([k, stringify(obj[k])]);
}
pairs.sort(function(a, b) { return a[0] < b[0] ? -1 : 1 });
pairs = map.call(pairs, function(v) { return '"' + v[0] + '":' + v[1] });
return '{' + pairs + '}';
}
if (type === '[object Array]') {
return '[' + map.call(obj, function(v) { return stringify(v) }) + ']';
}
return JSON.stringify(obj);
};
stringify([{b: {z: 5, c: 2, a: {z: 1, b: 2}}, a: 1}, [1, 2, 3]])
'[{"a":1,"b":{"a":{"b":2,"z":1},"c":2,"z":5}},[1,2,3]]'
stringify([{a: 1, b:{z: 5, c: 2, a: {b: 2, z: 1}}}, [1, 2, 3]])
'[{"a":1,"b":{"a":{"b":2,"z":1},"c":2,"z":5}},[1,2,3]]'
JavaScript 키는 본질적으로 순서가 없습니다.이걸 만들려면 직접 Stringifier를 써야 해, 그래서 내가 썼지
사용방법:
JSONc14n.stringify(obj)
출처:
var JSONc14n = {
stringify: function(obj){
var json_string,
keys,
key,
i;
switch(this.get_type(obj)){
case "[object Array]":
json_string = "[";
for(i = 0; i < obj.length; i++){
json_string += this.stringify(obj[i]);
if(i < obj.length - 1) json_string += ",";
}
json_string += "]";
break;
case "[object Object]":
json_string = "{";
keys = Object.keys(obj);
keys.sort();
for(i = 0; i < keys.length; i++){
json_string += '"' + keys[i] + '":' + this.stringify(obj[keys[i]]);
if(i < keys.length - 1) json_string += ",";
}
json_string += "}";
break;
case "[object Number]":
json_string = obj.toString();
break;
default:
json_string = '"' + obj.toString().replace(/["\\]/g,
function(_this){
return function(character){
return _this.escape_character.apply(_this, [character]);
};
}(this)
) + '"';
}
return json_string;
},
get_type: function(thing){
if(thing===null) return "[object Null]";
return Object.prototype.toString.call(thing);
},
escape_character: function(character){
return this.escape_characters[character];
},
escape_characters: {
'"': '\\"',
'\\': '\\\\'
}
};
고려해야 할 몇 가지 사항입니다.사물이 다르다는 것은 무엇을 의미할까요?해당 개체의 속성이 변경되었는지 확인하시겠습니까?누가 이러한 변화에 대해 '알고' 싶은가?개체 속성이 변경되었는지 즉시 확인하시겠습니까?
해당 객체의 속성을 '관찰 가능한' 속성으로 만들 수 있으며 속성이 변경되면 이벤트를 발생시킬 수 있으며 관심 있는 사람은 누구나 이러한 속성 변경에 가입할 수 있습니다.이렇게 하면 무엇이 바뀌었는지 즉시 알 수 있고 그 정보로 원하는 것을 할 수 있습니다.Kno.js는 이 방법을 사용합니다.이렇게 하면 '나쁜' 객체 비교에 의존할 필요가 없습니다.
인정된 답변은 더 이상 올바르지 않습니다.
모든 브라우저가 동일한 순서로 키를 정렬합니다.
JSON.stringify({"b": "b", "01": "01", 01: 1, "0": 0, "a": "a"})
// {"0":0,"1":1,"b":"b","01":"01","a":"a"}"
Object.getOwnPropertyNames({"b": "b", "01": "01", 01: 1, "0": 0, "a": "a"})
// [ "0", "1", "b", "01", "a" ]
- 숫자 필드가 정렬됨
- 문자열 필드가 정렬되지 않음
- 숫자 필드는 항상 문자열 필드 앞에 있습니다.
- 할 때 하면 .
{ 1: "anything" } - 숫자 필드를 지정할 때 한 가지 예외가 있습니다.
{ 01: "anything" }에는 숫자 필드가 됩니다.1{ "01": "anything" }필드가 ."01"
하다를 할 적용됩니다.JSON.stringify ★★★★★★★★★★★★★★★★★」Object.getOwnPropertyNames ★★★★★★★★★★★★★★★★★」for (var key in obj).
Safari, Chrome, Firefox, Edge, IE11에서 확인.
이 모든 것을 통해JSON.stringify이치노
한 . 1번 사용입니다.delete문자열 필드가 다시 추가되면 필드 목록의 끝에 추가되기 때문에 문자열 필드를 삭제하는 작업을 수행합니다.
이 경우에도 하실 수 있습니다.JSON.stringify두 개의 다른 개체를 비교할 수 있습니다. 단, 필드가 동일한 순서로 작성되었음을 알고 있으면 됩니다.
덧붙여, 현재 모든 JS엔진이 오브젝트를 동일하게 취급하고 있어도, 장래의 경우는 보증할 수 없기 때문에, 비교를 위해서 특별한 툴을 사용하는 것이 좋습니다.
Deep Equal 모듈을 사용하는 것이 좋습니다.strict: true선택.
언급URL : https://stackoverflow.com/questions/8931967/how-to-deterministically-verify-that-a-json-object-hasnt-been-modified
'source' 카테고리의 다른 글
| 커스텀 정보 및 가격을 사용하여 장바구니에 제품 추가 (0) | 2023.03.11 |
|---|---|
| WordPress + CloudFront Flexible SSL이 리다이렉트 루프(https)로 끝남 (0) | 2023.03.11 |
| 올바른 Java를 설치한 후 MacOS에서 Oracle SQLDeveloper가 열리지 않음 (0) | 2023.03.11 |
| Detect Enter 키를 jQuery로 누릅니다. (0) | 2023.03.11 |
| 요소를 새로 고치지 않은 상태로 유지하는 방법 (0) | 2023.03.11 |