If you want to include all objects, including those defined using a special literal syntax (such as {}, [], /regex/, functions, ...), then no.
That is . . . unless you are willing to manually generate an id for every object you create and for every built-in/imported object:
var genId, getId, genIdRecursive;
(function () {
var hiddenProps = [
"prototype"
, "toString"
, "length"
, ">>> REPLACE ME WITH ALL OTHER PROPS FOR-IN DOESN'T LOOP OVER! <<<"
];
function isObj (x) {
var type = typeof x
return x !== null && (type === "object" || type === "function");
}
var idProp = "%*genId.idProp*%";
var currId = 1 << 31;
var maxId = -((1 << 31) + 1);
genId = function () {
for (var i = 0; i < arguments.length; ++i) {
if (currId >= maxId) {
return Math.random ();
}
var arg = arguments [i];
if (isObj (arg)) {
arg [idProp] = currId++;
}
}
}
getId = function (obj) {
var id = obj [idProp];
return id === undefined ? null : id;
}
genIdRecursive = function () {
for (var i = 0; i < arguments.length; ++i) {
var arg = arguments [i];
if (!isObj (arg)) {
continue;
}
try {
if (getId (arg) !== null) {
continue;
}
genId (arg);
}
catch (e) {
continue;
}
var props = [];
for (var prop in arg) {
props.push (prop);
}
var nPs = props.length;
var nHs = hiddenProps.length;
var n = nHs + nPs;
for (var i = 0; i < n; ++i) {
var prop = i < nHs
? hiddenProps [i]
: props [i - nHs]
;
var val;
try {
val = arg [prop];
}
catch (e) {
continue;
}
genIdRecursive (val);
}
}
};
genId (genId, getId, genIdRecursive);
}) ();
Examples:
function func1 () {}
genId (func1);
var func2 = genId (function () {});
var xs = genId (["array literal"]);
var regex = genId (/regex/);
var foo = genId ({ foo: "foo" });
var bar = genId (new Bar ());