いくつかの実験を行う必要があり、JavaScriptでオブジェクトのある種の一意の識別子を知る必要があるため、それらが同じであるかどうかを確認できます。等価演算子を使いたくありません。Pythonのid()関数のようなものが必要です。
このようなものは存在しますか?
いくつかの実験を行う必要があり、JavaScriptでオブジェクトのある種の一意の識別子を知る必要があるため、それらが同じであるかどうかを確認できます。等価演算子を使いたくありません。Pythonの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を内部的に格納するために使用するメンバーが、自動的に作成される別のメンバー名と競合しないように注意してください。
object.hasOwnProperty(member)場合は常に使用することがベストプラクティスであると長い間考えられてきましたfor..in。これは十分に文書化された慣行であり、jslintによって実施されている
defineProperty(…, {enumerable:false})。とにかく、uidメソッド自体はObject名前空間にある必要があります
4、id 4のobjを変数にどのように割り当てれば、プロパティにアクセスできるように変数を使用できるようになりますか?
私の見解では、ここに投稿された回答は予期しない副作用をもたらす可能性があります。
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
return currentId?
WeakMapはなくてMap?文字列または数値を指定すると、その関数はクラッシュします。
最新のブラウザーは、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ハックよりもはるかに説得力のあるメカニズムのようです。OPのオブジェクトマッチングが必要な場合にのみ実行する必要があり、残りの時間は邪魔になりません。
を実装しているブラウザの場合 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);
backstageメソッドでdataは、次のような一意のIDのストリームの次のIDをput put でobject呼び出すという非常に特殊なフィールドを作成します"jQuery" + now()
id = elem[ expando ] = ++uuid;
John ResigがJavaScriptに関するすべてを明らかに知っており、彼の方法はそのすべての知識に基づいているのと同じ方法を使用することをお勧めします。
dataメソッドには欠陥があります。たとえば、stackoverflow.com / questions / 1915341 /…を参照してください。また、John ResigはJavaScriptについて知っておくべきことをすべて知っているわけではなく、JavaScript開発者としての役には立たないと信じています。
ES6互換の@justin回答のTypescriptバージョン。Symbolを使用してキーの衝突を防止し、便宜上グローバル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));
私は次のようなコードを使用しました。これにより、オブジェクトは一意の文字列で文字列化されます。
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でのみテストされています。
__defineGetter__は非標準であることを覚えておいてください。
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
2つのオブジェクトを比較する目的でこれを行う最も簡単な方法は、オブジェクトを比較する必要があるときに、オブジェクトの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