JavaScript에는 해시 코드 함수가 있습니까?


150

기본적으로 고유 한 객체, 세트의 객체를 만들려고합니다. 속성 이름에 대한 객체와 함께 JavaScript 객체를 사용한다는 훌륭한 아이디어가있었습니다. 같은

set[obj] = true;

이것은 한 지점까지 작동합니다. 문자열과 숫자로 잘 작동하지만 다른 객체에서는 모두 같은 값으로 "해시"되어 같은 속성에 액세스하는 것 같습니다. 객체에 대해 고유 한 해시 값을 생성 할 수있는 방법이 있습니까? 문자열과 숫자는 어떻게합니까, 같은 동작을 무시할 수 있습니까?


32
객체가 모두 동일한 값으로 '해시'하는 이유는 toString 메소드를 대체하지 않았기 때문입니다. 키는 문자열이어야하므로 toString 메소드는 유효한 키를 얻기 위해 자동으로 호출되므로 모든 객체가 동일한 기본 문자열 "[object Object]"로 변환됩니다.
alanning February

4
JSON.stringify(obj)또는 obj.toSource()문제 및 대상 플랫폼에 따라 효과가있을 수 있습니다.
AnnanFay

4
@Annan JSON.stringify (obj)는 문자 그대로 (전체) 객체를 문자열로 변환합니다. 따라서 기본적으로 객체를 자체에 복사하는 것입니다. 이것은 의미가없고 공간 낭비이며 최적이 아닙니다.
Metalstorm

1
@Metalstorm True, 문제의 원인에 따라 다릅니다. Google을 통해이 질문을 찾았을 때 최종 솔루션은 객체에서 toSource ()를 호출하는 것입니다. 또 다른 방법은 소스에서 기존 해시를 사용하는 것입니다.
AnnanFay

@Annan, toSourceChrome에서 작동하지 않음 btw
Pacerier

답변:


35

JavaScript 객체는 문자열을 키로 만 사용할 수 있습니다 (다른 것은 문자열로 변환 됨).

또는 해당 객체를 인덱싱하는 배열을 유지 관리하고 해당 인덱스 문자열을 객체에 대한 참조로 사용할 수 있습니다. 이 같은:

var ObjectReference = [];
ObjectReference.push(obj);

set['ObjectReference.' + ObjectReference.indexOf(obj)] = true;

분명히 조금 장황하지만, 그것을 처리하고 모든 Willy nilly를 가져오고 설정할 수있는 몇 가지 메소드를 작성할 수 있습니다.

편집하다:

당신의 추측은 사실입니다-이것은 JavaScript에서 동작으로 정의됩니다-특히 toString 변환이 발생하여 속성 이름으로 사용될 객체에서 자신의 toString 함수를 정의 할 수 있습니다. -올리에

이것은 또 다른 흥미로운 점을 제시합니다. 해시하려는 객체에 toString 메서드를 정의하면 해시 식별자를 구성 할 수 있습니다.


또 다른 옵션은 해시이므로 각 객체에 임의의 값을 부여하는 것입니다. 임의의 숫자 + 총 틱은 배열에서 객체를 추가 / 제거하는 함수 세트를 갖습니다.
Sugendran

4
동일한 객체를 두 번 추가하면 실패합니다. 그것이 다르다고 생각할 것입니다.
Daniel X Moore

"같은 객체를 두 번 추가하면 실패합니다. 다른 것으로 생각합니다." 좋은 지적. 해결 방법은 중복 검사를 push ()에 연결하여 ObjectReference의 Array를 서브 클래 싱하는 것입니다. 지금이 솔루션을 편집 할 시간이 없지만 나중에 기억할 수 있기를 바랍니다.
eyelidlessness

8
객체에 추가 속성이 필요하지 않기 때문에이 솔루션이 마음에 듭니다. 그러나 깨끗한 가비지 수집기를 사용하려고하면 문제가 발생합니다. 귀하의 접근 방식에서는 다른 참조가 이미 삭제되었지만 객체를 저장합니다. 더 큰 응용 프로그램에서 문제가 발생할 수 있습니다.
Johnny

35
객체를 참조 할 때마다 어레이의 선형 스캔이 필요한 경우 객체를 해시하는 요점은 무엇입니까?
Bordaigorl

57

JavaScript에서 Java와 같은 hashCode () 함수를 원한다면 다음과 같습니다.

String.prototype.hashCode = function(){
    var hash = 0;
    for (var i = 0; i < this.length; i++) {
        var character = this.charCodeAt(i);
        hash = ((hash<<5)-hash)+character;
        hash = hash & hash; // Convert to 32bit integer
    }
    return hash;
}

이것이 Java (비트 연산자)의 구현 방식입니다.

hashCode는 양수 및 음수 일 수 있으며, 정상 입니다. 음수 값을 제공하는 HashCode를 참조하십시오 . 따라서이 Math.abs()기능과 함께 사용하는 것을 고려할 수 있습니다 .


5
이것은 완벽하지 않은 -hash를 생성합니다
qodeninja

2
@KimKha char는 JS에서 예약어 이므로 일부 문제가 발생할 수 있습니다. 다른 이름이 더 좋을 것입니다.
szeryf

16
@qodeninja 누가 말합니다? 그런 주장을 듣는 것은 처음입니다. 어떤 출처에 연결할 수 있습니까? 해시는 일반적으로 고정 크기 정수 산술 및 비트 연산을 사용하여 계산되므로 양수 또는 음수 결과를 얻는 것이 예상됩니다.
szeryf

7
까다 롭지 만 ... "if (this.length == 0) return hash;" 중복 :) 그리고 개인적으로 "문자"를 "코드"로 변경합니다.
메탈 스톰

10
@qodeninja 및 @szeryf : 사용 방법에주의해야합니다. 예를 들어 20 개의 요소가 pickOne["helloo".hashCode() % 20]있는 배열 pickOne을 시도했습니다 . 내가 가지고 undefined해시 코드가 음수 때문에 누군가가 (나를) 암시 적으로 긍정적 인 해시 코드를 가정하는 예입니다 그래서.
Jim Pivarski 2014

31

가장 쉬운 방법은 각 객체에 고유 한 toString방법을 제공하는 것입니다.

(function() {
    var id = 0;

    /*global MyObject */
    MyObject = function() {
        this.objectId = '<#MyObject:' + (id++) + '>';
        this.toString= function() {
            return this.objectId;
        };
    };
})();

나는 같은 문제가 있었고 이것은 최소한의 소란으로 나를 위해 완벽하게 해결했으며 지방 자바 스타일을 다시 구현하고 객체 클래스에 Hashtable추가 equals()하고 hashCode()객체 클래스에 추가 하는 것이 훨씬 쉽습니다 . 문자열 '<#MyObject : 12>도 해시에 넣지 않아야합니다. 그렇지 않으면 해당 ID를 가진 기존 객체의 항목이 지워집니다.

이제 내 해시는 모두 차갑습니다. 나는 또한 이 정확한 주제 에 대해 며칠 전에 블로그 항목을 게시했습니다 .


28
그러나 이것은 요점을 그리워합니다. 자바가 equals()하고 hashCode()그래서 동일한 두 개체가 동일한 해시 값을 가지고있다. 위의 방법을 사용한다는 것은 모든 인스턴스에 MyObject고유 한 문자열이 있다는 것을 의미합니다. 즉,지도에서 올바른 값을 검색하려면 해당 객체에 대한 참조를 유지해야합니다. 키를 갖는 것은 객체의 고유성과 아무 관련이 없기 때문에 의미가 없습니다. toString()키로 사용하는 특정 유형의 객체에 유용한 기능을 구현해야합니다.
sethro

@sethro toString는 동등성을 관계로 직접 맵핑하여 두 오브젝트가 "동일한"것으로 간주되는 경우 동일한 문자열을 작성하도록 오브젝트에 대해 for 를 구현할 수 있습니다 .
Daniel X Moore

3
맞습니다 . 이것이 a를 a 로 사용할 수 있도록 하는 유일한 올바른 방법 입니다. 나는 귀하의 답변을 대등 하거나 사례별로 작성하지 않도록 일반적인 솔루션을 제공하려고 노력한다고 오해 한 것 같습니다 . toString()ObjectSettoString()equals()hashCode()
sethro

3
Dowvoted. 이것은 해시 코드가 아닙니다. stackoverflow.com/a/14953738/524126에 대한 내 대답을 참조하십시오. 해시 코드 의 실제 구현 : stackoverflow.com/a/15868654/524126
Metalstorm

5
@Metalstorm이 질문은 "진정한"해시 코드에 대한 질문이 아니라 JavaScript에서 객체를 세트로 성공적으로 사용하는 방법입니다.
Daniel X Moore

20

설명한 내용은 ECMAScript 6 사양 (다음 JavaScript 버전)의 일부인 Harmony WeakMaps 에서 다룹니다 . 즉, 키는 정의되지 않은 것을 포함하여 무엇이든 될 수 있고 열거 할 수없는 세트입니다.

즉, 키에 연결된 키 (객체!)에 대한 직접적인 참조가 없으면 값에 대한 참조를 얻을 수 없습니다. 효율성 및 가비지 수집과 관련된 여러 가지 엔진 구현 이유에서 중요하지만 데이터 전송자를 노출시키지 않고 회전 가능한 액세스 권한 및 데이터 전달과 같은 새로운 의미를 허용한다는 점에서도 매우 훌륭합니다.

에서 MDN :

var wm1 = new WeakMap(),
    wm2 = new WeakMap();
var o1 = {},
    o2 = function(){},
    o3 = window;

wm1.set(o1, 37);
wm1.set(o2, "azerty");
wm2.set(o1, o2); // A value can be anything, including an object or a function.
wm2.set(o3, undefined);
wm2.set(wm1, wm2); // Keys and values can be any objects. Even WeakMaps!

wm1.get(o2); // "azerty"
wm2.get(o2); // Undefined, because there is no value for o2 on wm2.
wm2.get(o3); // Undefined, because that is the set value.

wm1.has(o2); // True
wm2.has(o2); // False
wm2.has(o3); // True (even if the value itself is 'undefined').

wm1.has(o1);   // True
wm1.delete(o1);
wm1.has(o1);   // False

WeakMaps는 현재 Firefox, Chrome 및 Edge에서 사용할 수 있습니다. 또한 노드 v7 및 v6에서 --harmony-weak-maps플래그가 지원됩니다.


1
이것과의 차이점은 무엇입니까 Map?
smac89

@ smac89 WeakMap에는 다음과 같은 제한이 있습니다. 1) 객체 만 키로 사용합니다. 2) 크기 속성 없음 3) 반복자 또는 forEach 방법 없음 4) 명확한 방법 없음. 키는 객체입니다. 따라서 객체가 메모리에서 삭제 될 때이 객체와 연결된 WeakMap의 데이터도 삭제됩니다. 정보를 유지하려고 할 때 매우 유용합니다. 정보는 개체가 존재하는 동안에 만 존재해야합니다. 따라서 WeakMap에는 메소드 만 있습니다 : 설정, 쓰기 및 삭제, 읽기
Ekaterina Tokareva

이것은 정확하게 작동하지 않습니다 ... var m = new Map();m.set({},"abc"); console.log(m.get({}) //=>undefinedset 명령에서 처음 참조했던 것과 동일한 변수가있는 경우에만 작동합니다. EGvar m = new Map();a={};m.set(a,"abc"); console.log(m.get(a) //=>undefined
Sancarn

1
@Sancarn 같은 변수 일 필요는 없지만 같은 객체를 가리켜 야합니다. 첫 번째 예에서는 두 개의 서로 다른 객체가 있지만 모양은 동일하지만 주소가 다릅니다.
Svish

1
@Svish 좋은 자리! 내가 지금 알고 있지만, 나는 :) 다시 짓을하지 않을 수 있습니다
Sancarn

19

내가 선택한 솔루션은 Daniel과 유사하지만 객체 팩토리를 사용하고 toString을 재정의하는 대신 getHashCode 함수를 통해 처음 요청 될 때 객체에 해시를 명시 적으로 추가합니다. 조금 지저분하지만 내 요구에 더 좋습니다 :)

Function.prototype.getHashCode = (function(id) {
    return function() {
        if (!this.hashCode) {
            this.hashCode = '<hash|#' + (id++) + '>';
        }
        return this.hashCode;
    }
}(0));

7
이 길을 가고 싶어 경우를 통해 해시 코드를 설정하는 것이 훨씬 낫다 Object.definePropertyenumerable로 설정 false그래서 당신은 어떤 충돌하지 않습니다 for .. in루프.
Sebastian Nowak

14

특정 상황에서는 키와 프리미티브 값이 진행되는 한 객체의 평등에만 관심이 있습니다. 나를 위해 일한 솔루션은 객체를 JSON 표현으로 변환하고 해시로 사용하는 것이 었습니다. 잠재적으로 일치하지 않는 키 정의 순서와 같은 제한 사항이 있습니다. 그러나 내가 말했듯 이이 객체는 모두 한곳에서 생성 되었기 때문에 저에게 효과적이었습니다.

var hashtable = {};

var myObject = {a:0,b:1,c:2};

var hash = JSON.stringify(myObject);
// '{"a":0,"b":1,"c":2}'

hashtable[hash] = myObject;
// {
//   '{"a":0,"b":1,"c":2}': myObject
// }

10

문자열, 객체, 배열 등에 대한 해시 코드를 생성하기 위해 작은 JavaScript 모듈 을 얼마 전에 함께 사용 했습니다 (방금 GitHub에 커밋했습니다. )

용법:

Hashcode.value("stackoverflow")
// -2559914341
Hashcode.value({ 'site' : "stackoverflow" })
// -3579752159

javascript의 GC가 순환 참조에서도 초크하지 않습니까?
Clayton Rabenda

@Ryan Long 나는 당신이 순환 참조를 가지고 있다면 당신의 코드를 리팩터링 할 필요가 있다고 말할 수있다.)
Metalstorm

11
@Metalstorm "그런 다음 코드를 리팩터링해야합니다"농담합니까? 모든 DOM 요소 부모와 자식 쌍은 순환 참조를 구성합니다.
Chris Middleton

8
그것은 숫자 속성을 가진 열악한 작업 해싱 객체를 수행하는데, 많은 경우에 같은 값을 반환합니다. 즉 var hash1 = Hashcode.value({ a: 1, b: 2 }); var hash2 = Hashcode.value({ a: 2, b: 1 }); console.log(hash1, hash2);기록 할 것입니다2867874173 2867874173
Julien Bérubé

9

JavaScript 사양은 인덱스 이름에 대한 toString 변환을 수행하는 것으로 인덱스 속성 액세스를 정의합니다. 예를 들어

myObject[myProperty] = ...;

와 같다

myObject[myProperty.toString()] = ...;

이것은 JavaScript에서와 같이 필요합니다

myObject["someProperty"]

와 같다

myObject.someProperty

그리고 예, 그것은 나를 슬프게합니다 :-(



5

참조 : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol

Es6 기호를 사용하여 고유 키 및 액세스 개체를 만들 수 있습니다. Symbol ()에서 반환 된 모든 심볼 값은 고유합니다. 심볼 값은 객체 속성의 식별자로 사용될 수 있습니다. 이것이 데이터 유형의 유일한 목적입니다.

var obj = {};

obj[Symbol('a')] = 'a';
obj[Symbol.for('b')] = 'b';
obj['c'] = 'c';
obj.d = 'd';

2
실제로 Symbol을 재생성 할 수있는 방법이 없다는 것을 제외하고 let x = Symbol ( 'a'); let y = Symbol ( 'a'); console.log (x === y); // false를 반환하므로 Symbol은 해시처럼 작동하지 않습니다.
Richard Collette

3

다음은 고유 정수를 반환하는 간단한 솔루션입니다.

function hashcode(obj) {
    var hc = 0;
    var chars = JSON.stringify(obj).replace(/\{|\"|\}|\:|,/g, '');
    var len = chars.length;
    for (var i = 0; i < len; i++) {
        // Bump 7 to larger prime number to increase uniqueness
        hc += (chars.charCodeAt(i) * 7);
    }
    return hc;
}

2
이러한 복잡성은 해시 코드 () 뒤에있는 모든 생각 훼손
tuxSlayer

나는 이것이 불필요하게 복잡하지 않다. 그래도 궁금했습니다. 왜 교체 단계입니까? 예외는 charCodeAt에서 다르게 반환되었을 것입니다. 그렇지 않습니까?
그렉 Pettit

hashcode({a:1, b:2}) === hashcode({a:2, b:1})다른 많은 갈등 때문에 너무 나쁩니다 .
maaartinus

3

제목을 기반으로 js로 강력한 해시를 생성 할 수 있으며 객체, 매개 변수 배열, 문자열 등에서 고유 해시를 생성하는 데 사용할 수 있습니다.

나중에 색인을 생성하면 가능한 일치 오류를 피하면서 매개 변수에서 색인을 검색 할 수 있습니다 (객체 검색 / 반복 등을 피하십시오).

async function H(m) {
  const msgUint8 = new TextEncoder().encode(m)                       
  const hashBuffer = await crypto.subtle.digest('SHA-256', msgUint8)          
  const hashArray = Array.from(new Uint8Array(hashBuffer))                    
  const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('')
  console.log(hashHex)
}

/* Examples ----------------------- */
H("An obscure ....")
H(JSON.stringify( {"hello" : "world"} ))
H(JSON.stringify( [54,51,54,47] ))

내 브라우저에서 위의 출력은 당신에게도 동일해야합니다 ( 정말입니까? ).

bf1cf3fe6975fe382ab392ec1dd42009380614be03d489f23601c11413cfca2b
93a23971a914e5eacbf0a8d25154cda309c3c1c72fbb9914d47c60f3cb681588
d2f209e194045604a3b15bdfd7502898a0e848e4603c5a818bd01da69c00ad19

https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#Converting_a_digest_to_a_hex_string


1

내 솔루션은 전역 Object객체에 대한 정적 기능을 소개 합니다.

(function() {
    var lastStorageId = 0;

    this.Object.hash = function(object) {
        var hash = object.__id;

        if (!hash)
             hash = object.__id = lastStorageId++;

        return '#' + hash;
    };
}());

JavaScript에서 다른 객체 조작 함수를 사용하면 더 편리하다고 생각합니다.


1
내부 값이 동일한 객체는 다른 해시로 해시되지만 해시 (코드)가하는 것은 아닙니다.
Metalstorm

JavaScript에서 (그리고 거의 모든 다른 언어로도 생각합니다) 동일한 내부 값으로 작성된 두 개의 객체는 여전히 다른 객체입니다. 밑줄 데이터 유형은 각각 새로운 객체 인스턴스로 표시되기 때문입니다. jsfiddle.net/h4G9f
Johnny

4
예. 그러나 이것은 해시 코드가 아닙니다. 해시 코드는 객체 상태의 동등성을 확인하는 데 사용됩니다. 해시와 마찬가지로 동일한 입력이 들어가고 (변수 값) 동일한 해시가 나옵니다. 당신이 찾고있는 것은 UUID입니다 (이것은 함수가 제공하는 것입니다).
Metalstorm

1
네가 옳아. 나는 그 질문을 이해하지 못한다. 실제로 받아 들여진 대답은 좋은 해결책을 제공하지 않습니다.
Johnny

:뿐만 아니라 당신의 기능을 가지고 가서, 나는 그것을 더이 같은 경향 것 jsfiddle.net/xVSsd 같은 결과 짧은 LOC (+ 문자)를, 그리고 아마도 작은 조금의 빠른 :)
Metalstorm

1

다른 답변보다 조금 더 깊이 들어 가려고 노력할 것입니다.

JS가 더 나은 해싱 지원을 제공하더라도 모든 것을 완벽하게 해시하지는 않을 것입니다. 많은 경우 자신의 해시 함수를 정의해야합니다. 예를 들어 Java는 해싱을 잘 지원하지만 여전히 일부 작업을 생각하고 수행해야합니다.

한 가지 문제는 해시 / 해시 코드라는 용어입니다. 암호화 해싱과 비 암호 해싱이 있습니다. 다른 문제는 해싱이 유용한 이유와 작동 방식을 이해해야한다는 것입니다.

JavaScript 또는 Java에서의 해싱에 대해 대부분 이야기 할 때 비 암호화 해싱, 일반적으로 해시 맵 / 해시 테이블의 해싱에 대해 이야기합니다 (NodeJS를 사용하여 서버 측에서 수행 할 수있는 인증 또는 암호에 대한 작업을 수행하지 않는 한). ..).

보유하고있는 데이터와 달성하고자하는 데이터에 따라 다릅니다.

데이터에는 자연스러운 "간단한"고유성이 있습니다.

  • 정수의 해시는 ... 독특하기 때문에 정수입니다. 행운입니다!
  • 문자열의 해시 ... 문자열에 따라 다릅니다. 문자열이 고유 식별자를 나타내는 경우 해시로 간주 할 수 있으므로 해싱이 필요하지 않습니다.
  • 간접적으로 거의 고유 한 정수인 것이 가장 간단한 경우입니다.
  • 객체가 동일하면 해시 코드가 동일합니다.

데이터에는 자연스러운 "복합"고유성이 있습니다.

  • 예를 들어 person 객체를 사용하면 firstname, lastname, birthdate를 사용하여 해시를 계산할 수 있습니다. ... Java가 어떻게 수행하는지 확인 : Good Hash Function for Strings , 또는 유스 케이스에 충분히 저렴하고 고유 한 다른 ID 정보를 사용하십시오.

데이터가 무엇인지 모릅니다.

  • 행운을 빕니다 ... 문자열로 직렬화하고 Java 스타일을 해시 할 수는 있지만 문자열이 크면 충돌이 발생하지 않고 정수 (자체)의 해시를 피하지 않으면 비용이 많이들 수 있습니다.

알 수없는 데이터에는 마술처럼 효율적인 해싱 기술이 없으며, 경우에 따라 두 번 생각해야 할 수도 있습니다. 따라서 JavaScript / ECMAScript가 더 많은 지원을 추가하더라도이 문제에 대한 마법의 언어 솔루션은 없습니다.

실제로 두 가지가 필요합니다 : 충분한 고유성, 충분한 속도

그 외에도 "개체가 같은 경우 해시 코드가 동일합니다"


0

실제로 행동 설정을 원한다면 (자바 지식으로 갈 것입니다) JavaScript에서 솔루션을 찾기가 어려울 것입니다. 대부분의 개발자는 각 객체를 나타내는 고유 키를 권장하지만, 고유 키를 사용하여 각각 동일한 두 개의 객체를 얻을 수 있다는 점에서 다릅니다. Java API는 키가 아닌 해시 코드 값을 비교하여 중복 값을 검사하는 작업을 수행하며 JavaScript에 객체의 해시 코드 값 표현이 없으므로 거의 불가능합니다. 프로토 타입 JS 라이브러리조차도 다음과 같은 단점을 인정합니다.

"해시는 고유 키를 값에 바인딩하는 연관 배열로 생각할 수 있습니다 (고유 할 필요는 없음) ..."

http://www.prototypejs.org/api/hash


0

눈꺼풀이없는 대답 외에도 다음은 모든 객체의 재현 가능한 고유 ID를 반환하는 함수입니다.

var uniqueIdList = [];
function getConstantUniqueIdFor(element) {
    // HACK, using a list results in O(n), but how do we hash e.g. a DOM node?
    if (uniqueIdList.indexOf(element) < 0) {
        uniqueIdList.push(element);
    }
    return uniqueIdList.indexOf(element);
}

보시다시피 조회 목록이 매우 비효율적이지만 지금은 내가 찾을 수있는 최선입니다.


0

객체를 키로 사용하려면 이미 언급 한 것처럼 toString 메서드를 덮어 써야합니다. 사용 된 해시 함수는 모두 훌륭하지만 동일한 객체가 아닌 동일한 객체에 대해서만 작동합니다.

객체에서 해시를 만드는 작은 라이브러리를 작성했습니다.이 라이브러리는이 목적으로 쉽게 사용할 수 있습니다. 객체는 다른 순서를 가질 수도 있으며 해시는 동일합니다. 내부적으로 해시에 대해 다른 유형 (djb2, md5, sha1, sha256, sha512, ripemd160)을 사용할 수 있습니다.

다음은 설명서의 작은 예입니다.

var hash = require('es-hash');

// Save data in an object with an object as a key
Object.prototype.toString = function () {
    return '[object Object #'+hash(this)+']';
}

var foo = {};

foo[{bar: 'foo'}] = 'foo';

/*
 * Output:
 *  foo
 *  undefined
 */
console.log(foo[{bar: 'foo'}]);
console.log(foo[{}]);

패키지는 브라우저 및 Node-J에서 사용할 수 있습니다.

리포지토리 : https://bitbucket.org/tehrengruber/es-js-hash


0

조회 객체에 고유 한 값을 원하면 다음과 같이 할 수 있습니다.

조회 객체 만들기

var lookup = {};

해시 코드 기능 설정

function getHashCode(obj) {
    var hashCode = '';
    if (typeof obj !== 'object')
        return hashCode + obj;
    for (var prop in obj) // No hasOwnProperty needed
        hashCode += prop + getHashCode(obj[prop]); // Add key + value to the result string
    return hashCode;
}

목적

var key = getHashCode({ 1: 3, 3: 7 });
// key = '1337'
lookup[key] = true;

정렬

var key = getHashCode([1, 3, 3, 7]);
// key = '01132337'
lookup[key] = true;

다른 유형

var key = getHashCode('StackOverflow');
// key = 'StackOverflow'
lookup[key] = true;

최종 결과

{ 1337: true, 01132337: true, StackOverflow: true }

참고 수행 getHashCode객체 또는 배열이 비어있을 때 어떤 값을 반환하지 않습니다

getHashCode([{},{},{}]);
// '012'
getHashCode([[],[],[]]);
// '012'

이것은 @ijmacd 솔루션과 유사하지만 종속성 getHashCode이 없습니다 JSON.


당신은 그것으로 순환 참조에 문제가
생겼다

@tuxSlayer 알려 주셔서 감사합니다. 필요에
따라이

이렇게하면 메모리와 성능이 매우 어려워 질 수있는 큰 객체를위한 매우 긴 키가 생성됩니다.
Gershom

0

나는 눈꺼풀과 김카의 대답을 결합했습니다.

다음은 angularjs 서비스이며 숫자, 문자열 및 객체를 지원합니다.

exports.Hash = () => {
  let hashFunc;
  function stringHash(string, noType) {
    let hashString = string;
    if (!noType) {
      hashString = `string${string}`;
    }
    var hash = 0;
    for (var i = 0; i < hashString.length; i++) {
        var character = hashString.charCodeAt(i);
        hash = ((hash<<5)-hash)+character;
        hash = hash & hash; // Convert to 32bit integer
    }
    return hash;
  }

  function objectHash(obj, exclude) {
    if (exclude.indexOf(obj) > -1) {
      return undefined;
    }
    let hash = '';
    const keys = Object.keys(obj).sort();
    for (let index = 0; index < keys.length; index += 1) {
      const key = keys[index];
      const keyHash = hashFunc(key);
      const attrHash = hashFunc(obj[key], exclude);
      exclude.push(obj[key]);
      hash += stringHash(`object${keyHash}${attrHash}`, true);
    }
    return stringHash(hash, true);
  }

  function Hash(unkType, exclude) {
    let ex = exclude;
    if (ex === undefined) {
      ex = [];
    }
    if (!isNaN(unkType) && typeof unkType !== 'string') {
      return unkType;
    }
    switch (typeof unkType) {
      case 'object':
        return objectHash(unkType, ex);
      default:
        return stringHash(String(unkType));
    }
  }

  hashFunc = Hash;

  return Hash;
};

사용법 예 :

Hash('hello world'), Hash('hello world') == Hash('hello world')
Hash({hello: 'hello world'}), Hash({hello: 'hello world'}) == Hash({hello: 'hello world'})
Hash({hello: 'hello world', goodbye: 'adios amigos'}), Hash({hello: 'hello world', goodbye: 'adios amigos'}) == Hash({goodbye: 'adios amigos', hello: 'hello world'})
Hash(['hello world']), Hash(['hello world']) == Hash(['hello world'])
Hash(1), Hash(1) == Hash(1)
Hash('1'), Hash('1') == Hash('1')

산출

432700947 true
-411117486 true
1725787021 true
-1585332251 true
1 true
-1881759168 true

설명

보시다시피 서비스의 핵심은 KimKha가 만든 해시 함수입니다. 문자열에 유형을 추가하여 객체의 구조가 최종 해시 값에도 영향을 미칩니다. 키가 해시되어 객체 충돌을 방지합니다.

눈꺼풀이없는 물체 비교는 자기 참조 물체에 의한 무한 재귀를 방지하는 데 사용됩니다.

용법

객체로 액세스하는 오류 서비스를 가질 수 있도록이 서비스를 만들었습니다. 따라서 한 서비스가 지정된 객체에 오류를 등록하고 다른 서비스가 오류가 있는지 확인할 수 있습니다.

JsonValidation.js

ErrorSvc({id: 1, json: '{attr: "not-valid"}'}, 'Invalid Json Syntax - key not double quoted');

UserOfData.js

ErrorSvc({id: 1, json: '{attr: "not-valid"}'});

이것은 다음을 반환합니다.

['Invalid Json Syntax - key not double quoted']

동안

ErrorSvc({id: 1, json: '{"attr": "not-valid"}'});

이것은 돌아올 것이다

[]

0

숨겨진 비밀 속성을 defineProperty enumerable: false

매우 빠르게 작동합니다 .

  • 처음 읽은 uniqueId : 1,257,500 ops / s
  • 기타 : 309,226,485 ops / s
var nextObjectId = 1
function getNextObjectId() {
    return nextObjectId++
}

var UNIQUE_ID_PROPERTY_NAME = '458d576952bc489ab45e98ac7f296fd9'
function getObjectUniqueId(object) {
    if (object == null) {
        return null
    }

    var id = object[UNIQUE_ID_PROPERTY_NAME]

    if (id != null) {
        return id
    }

    if (Object.isFrozen(object)) {
        return null
    }

    var uniqueId = getNextObjectId()
    Object.defineProperty(object, UNIQUE_ID_PROPERTY_NAME, {
        enumerable: false,
        configurable: false,
        writable: false,
        value: uniqueId,
    })

    return uniqueId
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.