2009-07-25 8 views
2

Wie bestimmen Sie unter diesen Bedingungen den Unterschied zwischen new Object und new fn?Ermitteln der Differenz zwischen neuem Objekt und neuem Fn

  • var fn = function(){};
  • fn.prototype = {};
  • Sie verlassen sich nicht auf __proto__ oder Object.getPrototypeOf bestehenden, da sie nicht in IE oder Opera sind.
  • Die Lösung darf nicht statisch verwendet werden fn, wie instanceof fn.
  • Implementieren Sie Ihre eigenen Object.getPrototypeOf ist in Ordnung.

Nicht erforderlich: Es wäre schön, wenn Ihre Lösung mit Objekten aus anderer Frames arbeitet und Funktion Serialisierung nicht verwendet.

Hier einige Beispiel Basiscode für den Anfang:

var fn = function(){}; 
fn.prototype = {}; 

var x = new fn, 
y = new Object; 

fn = null; // prohibit static reference to fn 

// define your detection function here 
function isNewObject(obj) { 

}; 

alert(isNewObject(x) !== isNewObject(y) ? "pass" : "fail"); 
+0

Sie meinen, Sie möchten wissen, ob foo eine Instanz von SomeClass oder nur ein Objekt mit den gleichen Eigenschaften ist? –

+2

Ich glaube nicht, dass das möglich ist. –

+0

@gs Es ist möglich mit __proto__ oder Object.getPrototypeOf, aber das ist natürlich nicht Cross-Browser. –

Antwort

3

Ich bin mir ziemlich sicher, dass Sie kann dies nur mit Standard-Support in ES3 nicht tun, und hier ist der Grund:

Blick auf x und y Schöpfung.

var fn = function(){}; 
fn.prototype = {}; 

var x = new fn, 
    y = new Object; 

Wenn x instanziert wird, sein interner [[Prototyp]] wird von fn.prototype auf ein Objekt referenziert gesetzt (nur ein Object Objekt, das Sie fn.prototype zugewiesen). Der Konstruktor des Objekts - fn - wird dann in einem Kontext dieses neu erstellten Objekts aufgerufen, aber da es kein ob-Objekt in irgendeiner Weise mutiert, können wir diesen Schritt als irrelevant betrachten.

Wenn y instanziiert wird, wird sein interner [[Prototyp]] auf Object.prototype gesetzt, was ebenfalls ein Object Objekt ist. Sein Konstruktor (Object) wird dann in einem Kontext dieses neu erzeugten Objekts ebenfalls aufgerufen, aber auch dort passiert nichts.

So, jetzt am Ende mit 2 Object Objekte auf, die sich nur darin unterscheiden, dass ihre internen [[Prototyp]] 's Referenz verschiedene Objekte - x ist einer Referenzen, was Sie Object.prototype zu fn.prototype und y ‚s Referenzen zugeordnet. Ihre internen Eigenschaften [[Class]] sind ebenfalls identisch (d. H.gleich "Objekt")

Sie können in ES3 keinen direkten Zugriff auf [[Prototyp]] erhalten. Sie können etwas daraus ableiten, indem Sie instanceof verwenden, aber da fn in Ihrem Beispiel 0ulled ist intanceof -basierte Inferenz ist aus dem Bild.

Jetzt können Sie Object Konstruktor in der Weise erweitern, dass es instanziiertes Objekt irgendwie mutieren würde. Sie können dann ein Objekt untersuchen und diese Vergrößerung erkennen. Zum Beispiel:

Object = function() { 
    return ({ __: void 0 }); 
} 

und dann:

function isNewObject(object) { 
    return '__' in object; 
} 

aber dies wird natürlich nur funktionieren, wenn das Objekt mit new Object erstellt wird und nicht über, sagen wir, ein Objektliteral - { }. Es ist auch eher aufdringlich :)

Vielleicht gibt es andere Möglichkeiten, aber ich kann sie jetzt nicht sehen.

HTH

+0

Ihre Lösung würde nur funktionieren, wenn jemand nicht definiert explizit '__ ', aber es scheint die einzige Möglichkeit (außer Bruteforcing durch Iterieren über Eigenschaften und Verwendung! obj.hasOwnProperty (..) und! Object.prototype.hasOwnProperty (..)) –

+0

Sie können natürlich immer "__" in ein eindeutigeres Token ändern, aber das Problem bleibt bestehen. Jedes Skript könnte das Object Objekt fälschen, indem dieses einzigartige Token hinzugefügt/gelöscht wird. – kangax

3

Soweit ich weiß, Ihr Problem nicht möglich ist, mit ES3 zu lösen: instanceof und isPrototypeOf() nicht verwendet werden kann, weil das Prototypobjekt zu lösen von fn ist nicht zugänglich, und nur ES5 ermöglicht den Zugriff auf die interne [[Prototyp]] - Eigenschaft über Object.getPrototypeOf().

Btw, ein noch größeres Problem wäre zu lösen, wenn Sie Object.prototype zu fn.prototype zuweisen, zB

var x = (function() { 
    function Foo() {} 
    Foo.prototype = Object.prototype; 
    return new Foo; 
})(); 

Da die Prototypkette von Foo und Object Fällen identisch ist, sollte es keine Möglichkeit, zu unterscheiden Sie.

Verwandte Themen