programing

javascript의 고유

padding 2023. 10. 15. 17:04
반응형

javascript의 고유

실험을 좀 해야 하는데 자바스크립트의 객체들에 대해 어떤 고유 식별자를 사용해서 동일한 객체인지 확인해야 합니다.

나는 평등 연산자를 사용하고 싶지 않습니다.에,합니다 합니다.id()Python에서 작동합니다.

이런 게 있나요?

업데이트 아래 저의 원래 답변은 6년 전에 시대와 저의 이해에 맞는 스타일로 작성되었습니다.댓글에서 일부 대화가 이루어짐에 따라 이에 대한 보다 현대적인 접근 방식은 다음과 같습니다.

(function() {
    if ( typeof Object.id != "undefined" ) return;

    var id = 0;

    Object.id = function(o) {
        if ( typeof o.__uniqueid != "undefined" ) {
            return o.__uniqueid;
        }

        Object.defineProperty(o, "__uniqueid", {
            value: ++id,
            enumerable: false,
            // This could go either way, depending on your 
            // interpretation of what an "id" is
            writable: false
        });

        return o.__uniqueid;
    };
})();

var obj = { a: 1, b: 1 };

console.log(Object.id(obj));
console.log(Object.id([]));
console.log(Object.id({}));
console.log(Object.id(/./));
console.log(Object.id(function() {}));

for (var k in obj) {
    if (obj.hasOwnProperty(k)) {
        console.log(k);
    }
}
// Logged keys are `a` and `b`

오래된 브라우저 요구 사항이 있는 경우 여기에서 다음에 대한 브라우저 호환성을 확인하십시오.Object.defineProperty.

비교가 중요하다고 생각하기 때문에 (변경 이력에만 있지 않고) 원래의 답은 아래에 두고 있습니다.


다음과 같은 것을 회전시킬 수 있습니다.이를 통해 개체의 ID를 생성자 또는 다른 곳에 명시적으로 설정할 수도 있습니다.

(function() {
    if ( typeof Object.prototype.uniqueId == "undefined" ) {
        var id = 0;
        Object.prototype.uniqueId = function() {
            if ( typeof this.__uniqueid == "undefined" ) {
                this.__uniqueid = ++id;
            }
            return this.__uniqueid;
        };
    }
})();

var obj1 = {};
var obj2 = new Object();

console.log(obj1.uniqueId());
console.log(obj2.uniqueId());
console.log([].uniqueId());
console.log({}.uniqueId());
console.log(/./.uniqueId());
console.log((function() {}).uniqueId());

고유 ID를 내부적으로 저장하는 데 사용하는 구성원이 자동으로 작성된 다른 구성원 이름과 충돌하지 않도록 주의해야 합니다.

제가 관찰하는 한, 여기에 게시된 어떤 답변도 예상치 못한 부작용을 일으킬있습니다.

ES2015 호환 환경에서는 WickMap을 사용하여 부작용을 방지할 수 있습니다.

const id = (() => {
    let currentId = 0;
    const map = new WeakMap();

    return (object) => {
        if (!map.has(object)) {
            map.set(object, ++currentId);
        }

        return map.get(object);
    };
})();

id({}); //=> 1

최신 브라우저는 Object.prototype을 확장하기 위한 더 깨끗한 방법을 제공합니다.이 코드는 속성 열거에서 숨겨진 속성을 만듭니다(pino의 경우).

DefineProperty를 구현하는 브라우저의 경우 다음과 같이 uniqueId 속성을 구현할 수 있습니다.

(function() {
    var id_counter = 1;
    Object.defineProperty(Object.prototype, "__uniqueId", {
        writable: true
    });
    Object.defineProperty(Object.prototype, "uniqueId", {
        get: function() {
            if (this.__uniqueId == undefined)
                this.__uniqueId = id_counter++;
            return this.__uniqueId;
        }
    });
}());

자세한 내용은 https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/defineProperty 을 참조하십시오.

object프로토타입을 만들고 함수를 추가합니다.다음은 당신의 목적에 맞게 잘 작동해야 합니다.

var __next_objid=1;
function objectId(obj) {
    if (obj==null) return null;
    if (obj.__obj_id==null) obj.__obj_id=__next_objid++;
    return obj.__obj_id;
}

하는 브라우저의 Object.defineProperty()하고 있는 수 합니다.d,합니다.

은 를 .Object.prototype.

코드는 주어진 객체가 다음을 가지고 있는지 확인함으로써 작동합니다.__objectID__속성, 숨겨진(읽기 전용) 속성(비 enumable)으로 정의하는 것이 가능합니다.

합니다를 합니다.obj.__objectID__속성이 정의된 후에는 자동으로 실패하지 않고 지속적으로 좋은 오류를 발생시킵니다.

어떤 으로를 에는, __objectID__주어진 객체에서 이 값은 단순히 반환됩니다.

var getObjectID = (function () {

    var id = 0;    // Private ID counter

    return function (obj) {

         if(obj.hasOwnProperty("__objectID__")) {
             return obj.__objectID__;

         } else {

             ++id;
             Object.defineProperty(obj, "__objectID__", {

                 /*
                  * Explicitly sets these two attribute values to false,
                  * although they are false by default.
                  */
                 "configurable" : false,
                 "enumerable" :   false,

                 /* 
                  * This closure guarantees that different objects
                  * will not share the same id variable.
                  */
                 "get" : (function (__objectID__) {
                     return function () { return __objectID__; };
                  })(id),

                 "set" : function () {
                     throw new Error("Sorry, but 'obj.__objectID__' is read-only!");
                 }
             });

             return obj.__objectID__;

         }
    };

})();

@ justin answer의 스크립트 버전, ES6 호환, 기호를 사용하여 키 충돌을 방지하고 편리하게 글로벌 Object.id 에 추가합니다.아래 코드를 복사해서 붙여넣거나, 가져올 ObjecId.ts 파일에 입력하면 됩니다.

(enableObjectID)();

declare global {
    interface ObjectConstructor {
        id: (object: any) => number;
    }
}

const uniqueId: symbol = Symbol('The unique id of an object');

export function enableObjectID(): void {
    if (typeof Object['id'] !== 'undefined') {
        return;
    }

    let id: number = 0;

    Object['id'] = (object: any) => {
        const hasUniqueId: boolean = !!object[uniqueId];
        if (!hasUniqueId) {
            object[uniqueId] = ++id;
        }

        return object[uniqueId];
    };
}

사용 예:

console.log(Object.id(myObject));

[편집] 도우미 기능만 원하실 경우, 위 내용을 아래와 같이 단축하실 수 있습니다.

let counter = 0;
const weakMap = new WeakMap();
const getObjectId = (obj) => (weakMap.get(obj) ?? (weakMap.set(obj, ++counter) && counter));

운동장이

jQuery 합니다를 합니다.data()d(ID)입니다.

var id = $.data(object);

에서.data다에 합니다.object을 받은"jQuery" + now()한 음 ID다와 같은 고유 합니다.

id = elem[ expando ] = ++uuid;

John Resig도 자바스크립트에 대한 모든 것을 알고 있고 그의 방법도 그 모든 지식에 기초하고 있으므로 동일한 방법을 사용할 것을 제안합니다.

동일한 문제에 직면했고 ES6에서 구현한 솔루션은 다음과 같습니다.

let id = 0; // This is a kind of global variable accessible for every instance 

class Animal {
    constructor(name) {
        this.name = name;
        this.id = id++; 
    }

    foo() {} // Executes some cool stuff
}

const cat = new Animal("Catty");
console.log(cat.id) // 1

저는 다음과 같은 코드를 사용했습니다. 그러면 Objects가 고유한 문자열로 문자열화됩니다.

Object.prototype.__defineGetter__('__id__', function () {
    var gid = 0;
    return function(){
        var id = gid++;
        this.__proto__ = {
             __proto__: this.__proto__,
             get __id__(){ return id }
        };
        return id;
    }
}.call() );

Object.prototype.toString = function () {
    return '[Object ' + this.__id__ + ']';
};

__proto__입니다.__id__그 물체에 나타나는 것으로부터 얻을 수 있습니다. 은 파이어폭스에서만입니다.이것은 파이어폭스에서만 테스트 된 것입니다.

Object.prototype을 수정하지 말라는 권고에도 불구하고 제한된 범위 내에서 테스트할 때 여전히 유용할 수 있습니다. 있습니다.Object.id안 되네요,입니다 그 을 할 수 과 같습니다작업을 수행하는 토막글은 다음과 같습니다.

// Generates a unique, read-only id for an object.
// The _uid is generated for the object the first time it's accessed.

(function() {
  var id = 0;
  Object.defineProperty(Object.prototype, '_uid', {
    // The prototype getter sets up a property on the instance. Because
    // the new instance-prop masks this one, we know this will only ever
    // be called at most once for any given object.
    get: function () {
      Object.defineProperty(this, '_uid', {
        value: id++,
        writable: false,
        enumerable: false,
      });
      return this._uid;
    },
    enumerable: false,
  });
})();

function assert(p) { if (!p) throw Error('Not!'); }
var obj = {};
assert(obj._uid == 0);
assert({}._uid == 1);
assert([]._uid == 2);
assert(obj._uid == 0);  // still

저와 같은 클래스 인스턴스를 처리하기 위해 여기에 온 경우 정적 vars/method를 사용하여 사용자 지정 고유 ID로 인스턴스를 참조할 수 있습니다.

class Person { 
    constructor( name ) {
        this.name = name;
        this.id = Person.ix++;
        Person.stack[ this.id ] = this;
    }
}
Person.ix = 0;
Person.stack = {};
Person.byId = id => Person.stack[ id ];

let store = {};
store[ new Person( "joe" ).id ] = true;
store[ new Person( "tim" ).id ] = true;

for( let id in store ) {
    console.log( Person.byId( id ).name );
}

은 각 개체에 할 것입니다.string,number그리고 a을 있는 것입니다.getHashCode기능. 합니다.나머지에 대해서는 새 참조 번호를 할당합니다.

(function() {
  var __gRefID = 0;
  window.getHashCode = function(ref)
  {
      if (ref == null) { throw Error("Unable to calculate HashCode on a null reference"); }

      // already cached reference id
      if (ref.hasOwnProperty("__refID")) { return ref["__refID"]; }

      // numbers are already hashcodes
      if (typeof ref === "number") { return ref; }

      // strings are immutable, so we need to calculate this every time
      if (typeof ref === "string")
      {
          var hash = 0, i, chr;
          for (i = 0; i < ref.length; i++) {
            chr = ref.charCodeAt(i);
            hash = ((hash << 5) - hash) + chr;
            hash |= 0;
          }
          return hash;
      }

      // virtual call
      if (typeof ref.getHashCode === "function") { return ref.getHashCode(); }

      // generate and return a new reference id
      return (ref["__refID"] = "ref" + __gRefID++);
  }
})();

ID를 원하는 수십억 개의 개체를 생성할 때 확장성의 이점을 제공하는 Justin Johnson의 답변 변형입니다.

하는 것이 인 한계를 수 ) 1-up ()Number, ID를 재사용할 위험이 없이는 순환할 수 없습니다), 우리는 객체와 새로 생성된 ID를 에 등록합니다. 따라서 객체가 쓰레기를 수집한 후 어느 시점에 ID를 프리리스트에게 반환하여 새로 생성된 객체(Python's)가 다시 사용하도록 합니다.id함수는 또한 두 개체의 존재가 시간적으로 겹치지 않는 한 여러 개체에 대해 동일한 ID를 반환할 수 있습니다.

제한 사항:

  1. JS 프리미티브가 아닌 객체에서만 작동합니다. (이것은 다소 합리적입니다. 모든 것이 객체인 Python과 달리 JS 프리미티브는 일반적으로 그렇지 않습니다.id함수는 논리적으로 개체에만 작동합니다. 프리미티브는 합리적으로 식별 가능한 방식으로 "존재"할 필요가 없기 때문입니다.
  2. 의 개체를 의 ID를 요청한 한 에 모두 하고()에서 , 의 ID 를는 IDfreelist일종의 기억 유출을 구성합니다.JS 옵티마이저가 효율적으로 저장할 수 있기를 바랍니다. 따라서 비용은 객체 자체 비용의 일부로 남아 있지만 여전히 비용이 듭니다.ID를 가진 객체가 정기적으로 생성되고 파괴되는 경우, 낭비되는 메모리는 특정 시점에서 존재하는 ID를 가진 객체의 최대 개수에 대략적으로 연결됩니다.

하지만 그 한계가 문제가 되지 않는다면, 이것은 꽤 효과적입니다.나는 10M 개의 가비지 오브젝트를 ID로 생성하는 동안 때때로 제어를 이벤트 루프(그리고 가비지 컬렉터)로 되돌리기 위해 테스트 코드를 약간 수정했습니다. 그리고 브라우저에서 거의 절반에 가까운 오브젝트 ID가 재사용을 위해 회수됩니다. 마지막 루프에서 5개의 오브젝트를 만들고 ID를 생성하면 1M 바로 이상의 ID가 생성됩니다.2M 이상의 개체가 특정 시점에 ID를 생성했을 때.l을 async최종화 레지스트리에서 정리를 수행할 수 있는 기회가 많아지기 때문에 사용법이 개선될 것으로 기대합니다.

async function sleep(ms) {
    await _sleep(ms);
}

function _sleep(ms) {
    return new Promise((resolve) => setTimeout(resolve, ms));
}


    (function() {
        if ( typeof Object.id != "undefined" ) return;

        var freelist = [];  // Stores previously used IDs for reuse when an object with
                            // an ID is garbage collected, so creating and dropping billions
                            // of objects doesn't consume all available IDs
        const registry = new FinalizationRegistry((freeid) => {
            freelist.push(freeid);
        });

        var id = 0;

        Object.id = function(o) {
            if ( typeof o.__uniqueid != "undefined" ) {
                return o.__uniqueid;
            }

            Object.defineProperty(o, "__uniqueid", {
                value: freelist.length ? freelist.pop() : ++id,
                enumerable: false,
                // This could go either way, depending on your 
                // interpretation of what an "id" is
                writable: false
            });
            registry.register(o, o.__uniqueid);  // Sometime after o is collected, its ID
                                                 // will be reclaimed for use by a new object

            return o.__uniqueid;
        };
    })();
    
    var obj = { a: 1, b: 1 };
    
    console.log(Object.id(obj));
    console.log(Object.id([]));
    console.log(Object.id({}));
    console.log(Object.id(/./));

    var idsum = 0; // So we do something real to prevent optimizing out code
    // Make a ton of temporary objects with IDs, handing control back to the event loop
    // every once in a while to (hopefully) see some IDs returned to the pool
    for (var i = 0; i < 1000000; ++i) {
         idsum += Object.id({c: i});
    }
    sleep(10).then(() => {
        console.log(Object.id(function() { console.log("Hey"); }));
        for (var i = 1000000; i < 2000000; ++i) {
             idsum += Object.id({c: i});
        }
        console.log(Object.id(function() { console.log("There"); }));
        sleep(10).then(() => {
            for (var i = 0; i < 5; ++i) {
                console.log(Object.id([i]));
            }
            console.log(idsum);
        });
    });

    for (var k in obj) {
        if (obj.hasOwnProperty(k)) {
            console.log(k);
        }
    }
    // Logged keys are `a` and `b`

언급URL : https://stackoverflow.com/questions/1997661/unique-object-identifier-in-javascript

반응형