जावास्क्रिप्ट में अद्वितीय वस्तु पहचानकर्ता


120

मुझे कुछ प्रयोग करने की आवश्यकता है और मुझे जावास्क्रिप्ट में वस्तुओं के लिए किसी प्रकार के विशिष्ट पहचानकर्ता को जानने की आवश्यकता है, इसलिए मैं देख सकता हूं कि क्या वे समान हैं। मैं समानता ऑपरेटरों का उपयोग नहीं करना चाहता, मुझे अजगर में आईडी () फ़ंक्शन की तरह कुछ चाहिए।

क्या ऐसा कुछ मौजूद है?


2
मैं थोड़ा उत्सुक हूं, आप समानता ऑपरेटरों से क्यों बचना चाहते हैं?
सीएमएस

22
क्योंकि मैं कुछ सरल चाहता हूं, और मैं एक संख्या, कुछ स्पष्ट देखना चाहता हूं। यह भाषा बिल्ली का बच्चा रोती है, मैं पहले से ही इसे पर्याप्त रूप से लड़ रहा हूं।
स्टेफानो बोरीनी

4
सख्त समानता ऑपरेटर (===) वही करेगा जो आप वस्तुओं पर मांगते हैं (यदि आप संख्या / तार / आदि की तुलना कर रहे हैं तो यह एक ही बात नहीं है), और प्रत्येक वस्तु में एक गुप्त अद्वितीय आईडी बनाने की तुलना में सरल है।
बेन ज़ोटो

4
@CMS @ अद्वितीय आईडी होने पर डिबगिंग या आइडेंटिटीसेट जैसी चीजों को लागू करने के लिए उपयोगी हो सकता है।
एलेक्स जैस्मिन

9
मैं संवाद करना चाहता हूं कि मैंने जावास्क्रिप्ट की समझ में सफलता हासिल की। बंद एक सिंक का प्रकार। अब सब कुछ स्पष्ट है। मैंने चीजें देखी हैं। मैंने जावास्क्रिप्ट प्रोग्रामर में एक स्तर प्राप्त किया।
स्टेफानो बोरीनी

जवाबों:


68

अपडेट मेरा मूल उत्तर नीचे 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

मूल उत्तर नीचे रखा गया है (केवल बदले इतिहास में) क्योंकि मुझे लगता है कि तुलना मूल्यवान है।


आप निम्नलिखित एक स्पिन दे सकते हैं। यह आपको अपने कंस्ट्रक्टर या अन्य जगहों पर किसी ऑब्जेक्ट की आईडी को स्पष्ट रूप से सेट करने का विकल्प देता है।

(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());

यह सुनिश्चित करने के लिए ध्यान रखें कि आप जो भी सदस्य यूनिक आईडी को स्टोर करने के लिए उपयोग करते हैं वह दूसरे स्वचालित रूप से बनाए गए सदस्य नाम से नहीं टकराता है।


1
@Justin Object.prototype के गुणों को जोड़ना ECMAScript 3 में समस्याग्रस्त है क्योंकि ये प्रोफ़ेटरीज सभी ऑब्जेक्ट्स पर मौजूद हैं। इसलिए यदि आप Object.prototyp.a को परिभाषित करते हैं तो "a" तब दिखाई देगा जब आप ({{) चेतावनी (प्रोप) में प्रोप करते हैं; इसलिए आपको Object.prototype को बढ़ाने और for.gov लूप का उपयोग करने वाली वस्तुओं जैसे रिकॉर्ड के माध्यम से पुनरावृति करने में सक्षम होने के बीच एक समझौता करना होगा । यह पुस्तकालयों के लिए एक गंभीर समस्या है
एलेक्स जैस्मिन

29
कोई समझौता नहीं है। लूप object.hasOwnProperty(member)का उपयोग करते समय इसे हमेशा उपयोग करने के लिए सबसे अच्छा अभ्यास माना जाता है for..in। यह एक अच्छी तरह से प्रलेखित अभ्यास है और एक जिसे jslint द्वारा लागू किया गया है
जस्टिन जॉनसन

3
न तो मैं ऐसा करने के लिए पुनर्संयोजन करेगा, कम से कम हर वस्तु के लिए नहीं, आप केवल उन वस्तुओं के साथ कर सकते हैं जिन्हें आप संभालते हैं। दुर्भाग्य से ज्यादातर समय हमें बाहरी जावास्क्रिप्ट पुस्तकालयों का उपयोग करना पड़ता है, और दुर्भाग्य से उनमें से हर एक को अच्छी तरह से प्रोग्राम नहीं किया जाता है, इसलिए इससे बचें जब तक कि आपके वेब पेज में शामिल सभी पुस्तकालयों का कुल नियंत्रण नहीं होता है, या कम से कम आप जानते हैं कि आपने अच्छी तरह से संभाला है। ।
बेकार

1
@JustinJohnson: ES5 में एक समझौता है defineProperty(…, {enumerable:false}):। और uidविधि वैसे भी नामस्थान मेंObject
बर्गी

@JustinJohnson अगर यह कहने दें कि ऑब्जेक्ट आईडी 4कैसे थी तो आप आईडी 4 के साथ एक वेरिएबल के साथ ओजे को असाइन करेंगे ताकि आप इसके साथ सामान कर सकें ... जैसे कि इसके गुण?
सर

50

अब तक जहां तक ​​मेरा अवलोकन है, यहां पोस्ट किए गए किसी भी उत्तर में अप्रत्याशित दुष्प्रभाव हो सकते हैं।

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

1
क्यों नहीं return currentId?
Gust van de Wal

क्यों WeakMapविरोध किया Map? यदि आप इसे स्ट्रिंग या संख्या प्रदान करते हैं तो यह फ़ंक्शन क्रैश हो जाएगा।
नैट सीमर

35

नवीनतम ब्राउज़र Object.prototype को विस्तारित करने के लिए एक क्लीनर विधि प्रदान करते हैं। यह कोड प्रॉपर्टी एन्यूमरेशन (पी में ओ के लिए) से संपत्ति को छिपा देगा।

डिफ़रेंप्रोपर्टी को लागू करने वाले ब्राउज़रों के लिए , आप इस तरह से यूनिक आई प्रॉपर्टी को लागू कर सकते हैं:

(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 देखें


2
"नवीनतम ब्राउज़रों" में स्पष्ट रूप से फ़ायरफ़ॉक्स 3.6 शामिल नहीं है। (हाँ, मैं फ़ायरफ़ॉक्स के नए संस्करणों में अपग्रेड दौड़ से बाहर हो रहा हूं, और मुझे यकीन है कि मैं केवल एक ही नहीं हूं। इसके अलावा, FF3.6 केवल 1 वर्ष का है।)
bart

7
1 साल का इस खेल में "केवल" नहीं है। वेब गतिशील रूप से विकसित होता है - यह एक अच्छी बात है। आधुनिक ब्राउज़रों के पास अनुमति देने के उद्देश्य से स्वचालित अपडेटर हैं।
कोस

1
कुछ वर्षों बाद, यह मेरे लिए स्वीकृत उत्तर की तुलना में बेहतर काम कर रहा है।
फिटर मैन

11

दरअसल, आपको 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;
}

4
nocase, snake_case और camelCase तीनों ने 6-लाइन कोड स्निपेट में अपना रास्ता बना लिया है। आप उस रोज़ नहीं देखते
Gust van de Wal

यह objectहैक की तुलना में बहुत अधिक समझाने वाला तंत्र लगता है। आपको केवल इसे चलाने की आवश्यकता है जब आप ओपी के ऑब्जेक्ट से मेल खाना चाहते हैं और यह बाकी समय से बाहर रहता है।
JL Peyret

6

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__;

         }
    };

})();

4

jQuery कोड data()इस तरह की आईडी के रूप में खुद की विधि का उपयोग करता है ।

var id = $.data(object);

बैकस्टेज मेथड में dataएक बहुत ही खास फील्ड तैयार किया objectजाता है , जिसे "jQuery" + now()यूनीक आइडल की स्ट्रीम के अगले आईडी में रखा जाता है

id = elem[ expando ] = ++uuid;

मेरा सुझाव है कि आप उसी विधि का उपयोग करें क्योंकि जॉन रेजिग स्पष्ट रूप से जानता है कि सभी जावास्क्रिप्ट के बारे में है और उसकी विधि उस सभी ज्ञान पर आधारित है।


5
jQuery की dataविधि में दोष हैं। उदाहरण के लिए देखें stackoverflow.com/questions/1915341/… । इसके अलावा, जॉन रेसिग किसी भी तरह से नहीं जानता है कि जावास्क्रिप्ट के बारे में सभी को पता है, और यह मानते हुए कि वह आपको जावास्क्रिप्ट डेवलपर के रूप में मदद नहीं करेगा।
टिम डाउन

1
@ यह अद्वितीय आईडी प्राप्त करने के संदर्भ में उतनी ही खामियां हैं, जितनी कि यहां प्रस्तुत की गई कोई अन्य विधि क्योंकि यह हुड के नीचे लगभग समान है। और हां, मेरा मानना ​​है कि जॉन रेजिग मुझसे ज्यादा जानते हैं और मुझे उनके फैसलों से सीखना चाहिए, भले ही वह डगलस क्रॉकफोर्ड ही क्यों न हों।
वावा

AFAIK $ .Data जावास्क्रिप्ट वस्तुओं पर काम नहीं करता है, लेकिन केवल DOM तत्व हैं।
mb21

4

@Justin उत्तर, 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));

1

मैंने इस तरह कोड का उपयोग किया है, जो वस्तुओं को अद्वितीय तारों के साथ सख्त करने का कारण होगा:

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__वस्तु में प्रदर्शित होने से गेटर। यह केवल फ़ायरफ़ॉक्स में परीक्षण किया गया है।


बस यह ध्यान रखें कि __defineGetter__गैर-मानक है।
टॉम ज़ातो -

1

ऑब्जेक्ट.प्रोटोटाइप को संशोधित न करने की सलाह के बावजूद, यह अभी भी सीमित दायरे में परीक्षण के लिए वास्तव में उपयोगी हो सकता है। स्वीकृत उत्तर के लेखक ने इसे बदल दिया, लेकिन अभी भी सेटिंग कर रहा है 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

1

मुझे उसी समस्या का सामना करना पड़ा और यहाँ मैंने 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 

1

दो वस्तुओं की तुलना करने के उद्देश्य से, ऐसा करने का सबसे सरल तरीका यह होगा कि आप जिस समय वस्तुओं की तुलना करना चाहते हैं, उसमें से किसी एक वस्तु में एक अनोखी संपत्ति जोड़ दें, जांचें कि क्या संपत्ति दूसरे में मौजूद है और फिर उसे हटा दें। यह ओवरराइडिंग प्रोटोटाइप को बचाता है।

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
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.