IT story

자바 스크립트의 고유 한 객체 식별자

hot-time 2020. 8. 6. 07:52
반응형

자바 스크립트의 고유 한 객체 식별자


실험을해야하며 자바 스크립트의 객체에 대한 고유 식별자를 알아야하므로 동일한 지 확인할 수 있습니다. 평등 연산자를 사용하고 싶지 않으므로 파이썬의 id () 함수와 같은 것이 필요합니다.

이와 같은 것이 존재합니까?


업데이트 아래에 내 원래의 대답은 시간과 나의 이해 어울리는 스타일 6 년 전에 작성되었습니다. 의견에 대한 대화에 대한 더 현대적인 접근 방식은 다음과 같습니다.

(function() {
    if ( typeof Object.id == "undefined" ) {
        var id = 0;

        Object.id = function(o) {
            if ( typeof o.__uniqueid == "undefined" ) {
                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 호환 환경에서는 사용에 의한 부작용을 피할 수 WeakMap을 .

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을 확장하는 더 확실한 방법을 제공합니다. 이 코드는 속성 열거에서 속성을 숨 깁니다 (o의 p).

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()메소드를 구현하는 브라우저의 경우 아래 코드는 소유 한 모든 오브젝트에 바인딩 할 수있는 함수를 생성하고 리턴합니다.

이 방법은 확장하지 않는 이점이 Object.prototype있습니다.

코드는 주어진 객체에 __objectID__속성 이 있는지 확인 하고 숨겨진 (열거 가능하지 않은) 읽기 전용 속성으로 정의하여이를 작동합니다.

따라서 읽기 전용 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__;

         }
    };

})();

jQuery 코드는 data()ID와 같은 자체 메소드를 사용합니다 .

var id = $.data(object);

백 스테이지 방법 data에서는 다음과 같은 고유 ID 스트림의 다음 ID를 넣어 object라는 매우 특수한 필드를 만듭니다."jQuery" + now()

id = elem[ expando ] = ++uuid;

John Resig가 JavaScript에 대한 모든 것을 알고 있고 그의 방법이 모든 지식을 기반으로한다는 것을 분명히 알고있는 것과 동일한 방법을 사용하는 것이 좋습니다.


@justin answer, ES6 호환의 Typescript 버전은 기호를 사용하여 키 충돌을 방지하고 편의를 위해 전역 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));

I've used code like this, which will cause Objects to stringify with unique strings:

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__ + ']';
};

the __proto__ bits are to keep the __id__ getter from showing up in the object. this has been only tested in firefox.


Notwithstanding the advice not to modify Object.prototype, this can still be really useful for testing, within a limited scope. The author of the accepted answer changed it, but is still setting Object.id, which doesn't make sense to me. Here's a snippet that does the job:

// 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

I faced the same problem and here's the solution I implemented with ES6

code
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
}

cat = new Animal("Catty");


console.log(cat.id) // 1 

For the purpose of comparing two objects, the simplest way to do this would be to add a unique property to one of the objects at the time you need to compare the objects, check if the property exists in the other and then remove it again. This saves overriding prototypes.

function isSameObject(objectA, objectB) {
   unique_ref = "unique_id_" + performance.now();
   objectA[unique_ref] = true;
   isSame = objectB.hasOwnProperty(unique_ref);
   delete objectA[unique_ref];
   return isSame;
}

object1 = {something:true};
object2 = {something:true};
object3 = object1;

console.log(isSameObject(object1, object2)); //false
console.log(isSameObject(object1, object3)); //true

참고URL : https://stackoverflow.com/questions/1997661/unique-object-identifier-in-javascript

반응형