Bearbeiten: Ich interpretiere "Objektliteral" als alles, was mit einem Objektliteral erstellt wurde oder mit dem Object
-Konstruktor. Das hat John Resig höchstwahrscheinlich gemeint.
Ich habe eine Funktion, die auch funktioniert, wenn .constructor
verunreinigt wurde oder das Objekt in einem anderen Fenster erstellt wurde. Beachten Sie, dass Object.prototype.toString.call(obj) === "[object Object]"
(wie einige vielleicht glauben) dieses Problem nicht lösen wird.
function isObjectLiteral(obj) {
if (typeof obj !== "object" || obj === null)
return false;
var hasOwnProp = Object.prototype.hasOwnProperty,
ObjProto = obj;
// Objektkonstruktor-Prototyp von obj erhalten
while (Object.getPrototypeOf(ObjProto = Object.getPrototypeOf(ObjProto)) !== null);
if (!Object.getPrototypeOf.isNative) // Workaround bei nicht-nativem Object.getPrototypeOf
for (var prop in obj)
if (!hasOwnProp.call(obj, prop) && !hasOwnProp.call(ObjProto, prop)) // woanders geerbt
return false;
return Object.getPrototypeOf(obj) === ObjProto;
};
if (!Object.getPrototypeOf) {
if (typeof ({}).__proto__ === "object") {
Object.getPrototypeOf = function (obj) {
return obj.__proto__;
};
Object.getPrototypeOf.isNative = true;
} else {
Object.getPrototypeOf = function (obj) {
var constructor = obj.constructor,
oldConstructor;
if (Object.prototype.hasOwnProperty.call(obj, "constructor")) {
oldConstructor = constructor;
if (!(delete obj.constructor)) // Konstruktor zurücksetzen
return null; // kann Konstruktor nicht löschen, null zurückgeben
constructor = obj.constructor; // echten Konstruktor erhalten
obj.constructor = oldConstructor; // Konstruktor wiederherstellen
}
return constructor ? constructor.prototype : null; // benötigt für IE
};
Object.getPrototypeOf.isNative = false;
}
} else Object.getPrototypeOf.isNative = true;
Hier ist der HTML-Code für den Testfall:
isObjectLiteral
li { background: green; } li.FAIL { background: red; }
iframe { display: none; }
function isObjectLiteral(obj) {
// Funktion ohne Objektliteral-Instanz
if (typeof obj !== "object" || obj === null)
return false;
var hasOwnProp = Object.prototype.hasOwnProperty,
ObjProto = obj;
// Objektkonstruktor-Prototyp von obj erhalten
while (Object.getPrototypeOf(ObjProto = Object.getPrototypeOf(ObjProto)) !== null);
if (!Object.getPrototypeOf.isNative) // Workaround bei nicht-nativem Object.getPrototypeOf
for (var prop in obj)
if (!hasOwnProp.call(obj, prop) && !hasOwnProp.call(ObjProto, prop)) // woanders geerbt
return false;
return Object.getPrototypeOf(obj) === ObjProto;
};
// Wenn Object.getPrototypeOf nicht existiert
if (!Object.getPrototypeOf) {
if (typeof ({}).__proto__ === "object") {
// Objektliteral-Prototyp erhalten
Object.getPrototypeOf = function (obj) {
return obj.__proto__;
};
Object.getPrototypeOf.isNative = true;
} else {
// Objektliteral-Prototyp erhalten
Object.getPrototypeOf = function (obj) {
var constructor = obj.constructor,
oldConstructor;
if (Object.prototype.hasOwnProperty.call(obj, "constructor")) {
oldConstructor = constructor;
if (!(delete obj.constructor)) // Konstruktor zurücksetzen
return null; // kann Konstruktor nicht löschen, null zurückgeben
constructor = obj.constructor; // echten Konstruktor erhalten
obj.constructor = oldConstructor; // Konstruktor wiederherstellen
}
return constructor ? constructor.prototype : null; // benötigt für IE
};
Object.getPrototypeOf.isNative = false;
}
} else Object.getPrototypeOf.isNative = true;
// Funktionsserialisierung ist nicht erlaubt
// Funktioniert nicht in allen Browsern
Function.prototype.toString = function(){};
// Der Anwendungsfall, den wir überprüfen wollen
log("{}", {}, true);
// Instantiierte Objekte sollten nicht übereinstimmen
log("new Date", new Date, false);
var fn = function(){};
// Macht die Funktion etwas realistischer
// (und übrigens auch schwerer zu erkennen)
fn.prototype = {someMethod: function(){}};
// Funktionen sollten nicht übereinstimmen
log("fn", fn, false);
// Wieder sollten instantiierte Objekte nicht übereinstimmen
log("new fn", new fn, false);
var fn2 = function(){};
log("new fn2", new fn2, false);
var fn3 = function(){};
fn3.prototype = {}; // ohne nativen Object.getPrototypeOf unmöglich zu erkennen (?)
log("new fn3 (funktioniert nur mit nativem Object.getPrototypeOf)", new fn3, false);
log("null", null, false);
log("undefined", undefined, false);
/* Hinweis:
* Die Einschränkung gegen instantiierte Funktionen erfolgt
* aufgrund der Tatsache, dass diese Methode für
* das tiefe Klonen eines Objekts verwendet wird. Instantiierte Objekte
* bekommen einfach ihre Referenz kopiert, während
* einfache Objekte komplett geklont werden müssen.
*/
var iframe = document.createElement("iframe");
document.body.appendChild(iframe);
var doc = iframe.contentDocument || iframe.contentWindow.document;
doc.open();
doc.write("<body onload='window.top.iframeDone(Object);'>");
doc.close();
function iframeDone(otherObject){
// Objekte aus anderen Fenstern sollten übereinstimmen
log("new otherObject", new otherObject, true);
}
function log(msg, a, b) {
var pass = isObjectLiteral(a) === b ? "PASS" : "FAIL";
document.getElementById("results").innerHTML +=
"<li class='" + pass + "'>" + msg + "</li>";
}
0 Stimmen
Jeresig hat mich gebeten, eine Funktion zu implementieren, die genau das für ihn tun würde.
0 Stimmen
Ein Objekt ist niemals ein Objektliteral, also kannst du die Frage umformulieren?
0 Stimmen
Und übrigens, was war dein liebstes Commodore 64 Magazin?
0 Stimmen
@Nosredna Ich glaube, ich war damals zu jung dafür, ich habe meinen ersten C64 mit 3 Jahren bekommen. Alles, was ich wusste, war das ganze: load "*", 8, 1 Ding, damit ich meine Spiele laden konnte zu diesem Zeitpunkt.