имеет ли javascript что-то, эквивалентное функции `id` Python? [Дубликат]

Если вы действительно должны сделать это с помощью отражения, вы можете сделать это так:

var employees = new Employees();
var type = employees.GetType();

for (int i = 1; i <= 4; ++i)
    type.GetProperty("field"+i).SetValue(employees, "abcde");

Console.WriteLine(employees.field1); // Prints "abcde"

Как указывают другие люди, использование отражения таким образом кажется немного подозрительным. Похоже, вы должны делать это по-другому, например, используя Dictionary<string,string>.

88
задан Stefano Borini 4 January 2010 в 06:34
поделиться

11 ответов

Обновление Мой первоначальный ответ ниже был написан 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());

Позаботьтесь о том, чтобы любой член, который вы используете для внутреннего хранения уникального идентификатора, не сталкивался с другим автоматически созданный имя участника.

51
ответ дан TWiStErRob 19 August 2018 в 06:09
поделиться
  • 1
    Вы действительно не должны добавлять к Object.prototype ... – James 4 January 2010 в 11:52
  • 2
    @Justin Добавление свойств Object.prototype проблематично в ECMAScript 3, потому что эти причисления перечислимы для всех объектов. Поэтому, если вы определяете Object.prototype.a , тогда "a" будет видна, когда вы сделаете для (prop in {}) alert (prop); Итак, вы должны сделать компромисс между добавлением Object.prototype и возможностью итерации через записывать подобные объекты, используя цикл for..in. Это серьезная проблема для библиотек – Alexandre Jasmin 4 January 2010 в 23:06
  • 3
    Нет компромисса. Долгое время считалось лучшей практикой всегда использовать object.hasOwnProperty(member) при использовании цикла for..in. Это хорошо зарекомендовавшая себя практика, и это обеспечивается jslint – Justin Johnson 5 January 2010 в 00:01
  • 4
    ни один из них не рекомендовал бы это делать, по крайней мере, не для каждого объекта, вы можете сделать то же самое с объектами, которые вы обрабатываете. к сожалению, большую часть времени мы используем внешние библиотеки javascript, и, к сожалению, не каждый из них хорошо программируется, поэтому избегайте этого, если у вас нет полного контроля над всеми библиотеками, включенными в вашу веб-страницу, или, по крайней мере, вы знаете, что они хорошо справляются , – useless 15 March 2011 в 00:32
  • 5
    @JustinJohnson: В ES5 есть компромисс: defineProperty(…, {enumerable:false}). И сам метод uid должен быть в пространстве имен Object – Bergi 19 December 2012 в 00:16

Последние браузеры предоставляют более чистый метод расширения Object.prototype. Этот код сделает свойство скрытым от перечисления свойств (для p in o)

. Для браузеров , реализующих 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

33
ответ дан bignose 19 August 2018 в 06:09
поделиться
  • 1
    & quot; Последние браузеры & quot; по-видимому, не включает Firefox 3.6. (Да, я отказываюсь от гонки обновлений в более новых версиях Firefox, и я уверен, что я не единственный. Кроме того, FF3.6 всего 1 год.) – bart 28 September 2011 в 09:06
  • 2
    1 год не является «только». в этом виде спорта. Интернет развивается динамично - это хорошо. У современных браузеров есть автоматические обновления, чтобы это разрешить. – Kos 24 November 2012 в 11:02
  • 3
    Несколько лет спустя это, кажется, работает лучше для меня, чем принятый ответ. – Fitter Man 15 February 2015 в 00:02

Я использовал такой код, который заставит объекты строчить с помощью уникальных строк:

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__ не отображался в объекте , это было проверено только в firefox.

1
ответ дан Eric Strom 19 August 2018 в 06:09
поделиться
  • 1
    Просто имейте в виду, что __defineGetter__ является нестандартным. – Tomáš Zato 29 September 2015 в 21:36

Типовая версия ответа @justin, совместимая с ES6, с использованием символов для предотвращения любого столкновения ключей и добавления в глобальный Object.id для удобства. Просто скопируйте вставить код ниже или поместите его в файл ObjecId.ts, который вы импортируете.

(enableObjectID)();

const uniqueId: symbol = Symbol('The unique id of an object');
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];
    };
}

Использование в вашем ts-коде:

(<any>Object).id(yourObject);
2
ответ дан Flavien Volken 19 August 2018 в 06:09
поделиться

Насколько мне известно, любой ответ, который может быть опубликован здесь, может иметь неожиданные побочные эффекты.

В среде, совместимой с 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
19
ответ дан hakatashi 19 August 2018 в 06:09
поделиться
  • 1
    Я читаю это в 2018 году, и это, безусловно, самый чистый путь. – Romain 11 February 2018 в 12:52

Я столкнулся с той же проблемой, и вот решение, которое я использовал с 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
ответ дан Jaime Rios 19 August 2018 в 06:09
поделиться

На самом деле вам не нужно изменять прототип 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;
}
10
ответ дан KalEl 19 August 2018 в 06:09
поделиться

Несмотря на рекомендации не изменять 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
1
ответ дан Klortho 19 August 2018 в 06:09
поделиться

Для браузеров, реализующих метод 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__;

         }
    };

})();
6
ответ дан Luc125 19 August 2018 в 06:09
поделиться

Код jQuery использует свой собственный метод data() как такой идентификатор.

var id = $.data(object);

В за кулисном методе data создает очень специальное поле в object, называемом "jQuery" + now(), помещает туда следующий id потока уникальных идентификаторов, таких как

id = elem[ expando ] = ++uuid;

Я бы предложил использовать тот же метод, что и Джон Ресиг, очевидно, знает все, что есть о JavaScript, и его метод основан на всех этих знаниях.

3
ответ дан vava 19 August 2018 в 06:09
поделиться
  • 1
    Метод jQuery data имеет недостатки. См. Например, stackoverflow.com/questions/1915341/… . Кроме того, Джон Ресиг отнюдь не знает все, что нужно знать о JavaScript, и полагая, что он это не поможет вам в качестве разработчика JavaScript. – Tim Down 4 January 2010 в 10:51
  • 2
    @Tim, у него столько же недостатков с точки зрения получения уникального идентификатора, как и любой другой метод, представленный здесь, так как он примерно одинаково под капотом. И да, я считаю, что Джон Ресиг знает намного больше меня, и я должен учиться на его решениях, даже если он не Дуглас Крокфорд. – vava 4 January 2010 в 11:01
  • 3
    AFAIK $. Data не работает с объектами JavaScript, а только с элементами DOM. – mb21 12 June 2014 в 12:07
1
ответ дан adevart 30 October 2018 в 18:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: