27 Stimmen

Wie kann man feststellen, ob ein Objekt ein Objektliteral in Javascript ist?

Gibt es einen Weg, um in Javascript zu bestimmen, ob ein Objekt mit der Objektliteral Notation oder mit einem Konstruktor erstellt wurde?

Es scheint mir, dass man einfach auf das Elternobjekt zugreift. Aber wenn das Objekt, das Sie übergeben, keine Referenz auf sein Elternobjekt hat, glaube ich nicht, dass Sie das erkennen können. Oder doch?

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?

23voto

Jesse Punkte 5980

Was du willst ist:

Object.getPrototypeOf(obj) === Object.prototype

Dies überprüft, ob das Objekt ein einfaches Objekt ist, das mit new Object() oder {...} erstellt wurde und nicht eine Unterklasse von Object ist.

13voto

Rick Punkte 1376

Ich bin gerade auf diese Frage und Diskussion während eines süßen Hackfests gestoßen, das eine Gralssuche zur Bewertung, ob ein Objekt mit {} oder new Object() erstellt wurde, beinhaltete (ich habe das immer noch nicht herausgefunden.)

Wie dem auch sei, ich war überrascht, die Ähnlichkeit zwischen der hier geposteten isObjectLiteral() Funktion und meiner eigenen isObjLiteral() Funktion zu finden, die ich für das Pollen.JS Projekt geschrieben habe. Ich glaube, diese Lösung wurde vor meinem Pollen.JS Commit gepostet, also - Hut ab vor dir! Der Vorteil bei meiner ist die Länge... weniger als die Hälfte (wenn man dein Einrichtungs-Routine einschließt), aber beide produzieren die gleichen Ergebnisse.

Werfen Sie einen Blick darauf:

function isObjLiteral(\_obj) {
  var \_test  = \_obj;
  return (  typeof \_obj !== 'object' || \_obj === null ?
              false :  
              (
                (function () {
                  while (!false) {
                    if (  Object.getPrototypeOf( \_test = Object.getPrototypeOf(\_test)  ) === null) {
                      break;
                    }      
                  }
                  return Object.getPrototypeOf(\_obj) === \_test;
                })()
              )
          );
}

Zusätzlich einige Testdaten:

var \_cases= {
    \_objLit : {}, 
    \_objNew : new Object(),
    \_function : new Function(),
    \_array : new Array(), 
    \_string : new String(),
    \_image : new Image(),
    \_bool: true
};

console.dir(\_cases);

for ( var \_test in \_cases ) {
  console.group(\_test);
  console.dir( {
    type:    typeof \_cases\[\_test\], 
    string:  \_cases\[\_test\].toString(), 
    result:  isObjLiteral(\_cases\[\_test\])  
  });    
  console.groupEnd();
}

Oder auf jsbin.com...

http://jsbin.com/iwuwa

Stellen Sie sicher, dass Sie Firebug öffnen, wenn Sie dort sind - Debuggen des Dokuments ist für IE-Liebhaber.

0 Stimmen

@Rick, diese Lösung scheint eleganter zu sein.

0 Stimmen

@leeand00: Es ist ungefähr genauso lang wie meins. Ich habe auch eine Implementierung von Object.getPrototypeOf in meinem hinzugefügt, die in diesem nicht enthalten ist.

0 Stimmen

Auch, wenn Sie den Object.getPrototypeOf.isNative Teil entfernen, sind es nur 6 SLOC.

11voto

Eli Grey Punkte 34008

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>";
}

1 Stimmen

Tolle Antwort, und es ist schön, dich auf Stackoverflow zu haben. Abseits des Themas, aber danke auch für die e4x-Array-Methoden.

0 Stimmen

Jetzt, da ich deine Antwort gelesen habe, denke ich, dass ich die Frage verstehe.

1 Stimmen

Whoa! Was bedeutet das 3x-Gleichheitszeichen (===)?

8voto

Prestaul Punkte 79893

Es scheint, als ob du nach dem suchst:

function Foo() {}

var a = {};
var b = new Foo();

console.log(a.constructor == Object); // true
console.log(b.constructor == Object); // false

Das constructor-Attribut bei einem Objekt ist ein Zeiger auf die Funktion, die verwendet wurde, um es zu konstruieren. Im obigen Beispiel b.constructor == Foo. Wenn das Objekt mit geschweiften Klammern (der Array-Literal-Notation) oder mit new Object() erstellt wurde, dann wird sein constructor-Attribut == Object sein.

Aktualisierung: crescentfresh wies darauf hin, dass $(document).constructor == Object ist, anstatt gleich dem jQuery-Konstruktor zu sein, also habe ich ein wenig weiter gegraben. Es scheint, dass man durch Verwendung eines Objektliterals als Prototyp eines Objekts das constructor-Attribut fast nutzlos macht:

function Foo() {}
var obj = new Foo();
obj.constructor == Object; // false

aber:

function Foo() {}
Foo.prototype = { objectLiteral: true };
var obj = new Foo();
obj.constructor == Object; // true

Es gibt eine sehr gute Erklärung dazu in einer anderen Antwort hier, und eine ausführlichere Erklärung hier.

Ich glaube, die anderen Antworten haben recht und es gibt nicht wirklich eine Möglichkeit, dies zu erkennen.

1 Stimmen

constructor === Object ist für viele Objekte wahr. Versuche zum Beispiel javascript:alert($(document).constructor === Object) auf dieser Seite, obwohl jQuery !== Object ist.

0 Stimmen

Diese Methode wird einen Fehler werfen, wenn der Test "Objekt" null ist.

4voto

Steve Mc Punkte 3273

Ein Objektliteral ist die Notation, die Sie verwenden, um ein Objekt zu definieren - das in JavaScript immer in Form eines Schlüssel-Wert-Paares umgeben von geschweiften Klammern steht. Sobald dies ausgeführt wurde, gibt es keinen Weg zu sagen, ob das Objekt durch diese Notation erstellt wurde oder nicht (eigentlich denke ich, dass das eine Vereinfachung sein könnte, aber im Grunde korrekt). Sie haben einfach ein Objekt. Das ist einer der großartigen Dinge an js, dass es viele Abkürzungen gibt, um Dinge zu erledigen, die viel länger dauern könnten zu schreiben. Kurz gesagt, die literale Notation ersetzt das Schreiben von:

var myobject = new Object();

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X