2010-12-02 12 views
96

Gibt es trotzdem zu erkennen, ob ein JavaScript-Objekt eine Regex ist?typeof für RegExp

Zum Beispiel würde Ich mag so etwas tun:

var t = /^foo(bar)?$/i; 
alert(typeof t); //I want this to return "regexp" 

Ist das möglich?

Danke!

EDIT: Danke für alle Antworten. Es scheint, ich habe zwei sehr gute Wahl:

obj.constructor.name === "RegExp" 

oder

obj instanceof RegExp 

jeder größeren Vor/Nachteile entweder Methode?

Danke nochmal!

+1

See [diese Antwort] (http://stackoverflow.com/questions/3215046/differentiating-between-arrays-and-hashes-in-javascript/3215440#3215440) auf eine andere Frage für Bedenken hinsichtlich der Verwendung von "instanceof" und "constructor". – user113716

Antwort

130

Sie können Instanceof Operator:

var t = /^foo(bar)?$/i; 
alert(t instanceof RegExp);//returns true 

In der Tat, das ist fast das gleiche wie:

var t = /^foo(bar)?$/i; 
alert(t.constructor == RegExp);//returns true 

Beachten Sie, dass als Regex ist kein primitive data type Es ist nicht möglich, typeof Operator zu verwenden, der be the best option für diese Frage könnte.

Aber man kann diesen Trick oben oder andere verwenden wie duck type, zum Beispiel die Überprüfung, Überprüfung, ob eine solche Aufgabe alle lebenswichtigen Methoden oder Eigenschaften hat, oder durch seine internen Klassenwert (von {}.toString.call(instaceOfMyObject) verwenden).

+1

genial. Weißt du, was schneller/kompatibler ist: mit der Methode instanceof oder der Methode constructor.name? Vielen Dank! – tau

+1

instanceof, natürlich, können Sie es selbst überprüfen mit Firebug Timing (console.time) – Cleiton

+0

k vielen Dank! – tau

3

Works in Google Chrome:

x = /^foo(bar)?$/i; 
x == RegExp(x); // true 
y = "hello"; 
y == RegExp(y); // false 
10

Geben Sie die .constructor Eigenschaft einen Wirbel:

> /^foo(bar)?$/i.constructor 
function RegExp() { [native code] } 
> /^foo(bar)?$/i.constructor.name 
"RegExp" 
> /^foo(bar)?$/i.constructor == RegExp 
true 
+2

+1 Sie lernen jeden Tag neue Wege, Dinge zu tun! Vielen Dank! –

+4

Die Eigenschaft 'constructor' kann geändert werden. 'instanceof' hat dieses Problem nicht und ist eine bessere Lösung. –

+0

@TimDown, true, aber 'instanceof' funktioniert nicht in Ausführungskontexten. – elektronik

10

Von underscore.js

// Is the given value a regular expression? 
    _.isRegExp = function(obj) { 
    return !!(obj && obj.test && obj.exec && (obj.ignoreCase || obj.ignoreCase === false)); 
    }; 
+1

Sie tippen hier Ente, weil "typeof" für Regexes unzuverlässig ist und "instanceof" leidet unter dem Cross-Window-Problem. Ich frage mich, warum sie nicht die Antwort von @patrick dw benutzen ... –

+3

Jetzt weiß ich: Es funktioniert nicht im IE, wenn Objekte aus anderen Fenstern untersucht werden. –

+0

@Tim - genial ... Ich frage mich das gleiche, hatte aber noch keine Zeit, das zu überprüfen. Danke, dass du die Antwort hier geschrieben hast! –

0

"Regexp" ist kein nativer Typ Javascript. Die meisten der oben genannten Antworten sagen Ihnen, wie Sie Ihre Aufgabe erfüllen, aber nicht warum. Hier ist why.

+0

danke für den Leckerbissen. – tau

+3

Das ist eine irreführende Antwort. Ein regulärer Ausdruck ist definitiv ein natives ECMAScript- und JavaScript-Objekt. Ich denke, was Sie erreichen, ist, dass die möglichen Werte von typeof keinen dedizierten Wert für regulären Ausdruck enthalten. –

+0

'sed -i s/nativ/primitiv /'. Wenn Sie 'object' als primitiv zählen, gibt' typeof t' nur den Namen des primitiven Typs aus (na ja, meistens. Siehe https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Operators/typeof). – Tino

20
alert(Object.prototype.toString.call(t)); // [object RegExp] 

Dies ist die in der Spezifikation erwähnte Art und Weise, um die Klasse des Objekts zu erhalten.

Von ECMAScript 5, Abschnitt 8.6.2 Objekt Interne Eigenschaften und Methoden:

Der Wert des [[Klasse]] interne Eigenschaft durch diese Spezifikation für jede Art von Einbau-Objekt definiert ist .Der Wert der internen Eigenschaft [[Class]] eines Hostobjekts kann ein beliebiger String-Wert sein, mit Ausnahme von "Arguments", "Array", "Boolean", "Date", "Error", "Function", "JSON "," Math "," Nummer "," Objekt "," RegExp "und" String ". Der Wert einer internen Eigenschaft [[Klasse]] wird intern verwendet, um verschiedene Arten von Objekten zu unterscheiden. Beachten Sie, dass diese Spezifikation keinem Programm Zugriff auf diesen Wert bietet, außer durch Object.prototype.toString (siehe 15.2.4.2).

A RegExp ist eine Klasse von Objekt in der spec definiert, bei Abschnitt 15.10 RegExp (RegulaererAusdruck) Objekte:

A RegExp Objekt einen regulären Ausdruck und die damit verbundenen Flags enthält.

+1

Funktioniert das in allen Browsern? Wenn ja, ist dies die Antwort. –

+4

@Tim - Ich bin mir ziemlich sicher. Nicht dass es irgendeine Garantie ist, aber es ist die [Methode, die jQuery verwendet] (https://github.com/jquery/jquery/blob/master/src/core.js#L504-508), einschließlich für [RegExp] (https : //github.com/jquery/jquery/blob/master/src/core.js#L821-823). Ich habe gerade einen IE6-Test mit einer RegExp gemacht, und es funktioniert (wenn das ein Indikator ist). : o) Erscheint, als ob diese Methode es in der 3. Auflage in die Spezifikation geschafft hat. – user113716

+1

Leider funktioniert dies nicht im IE mit RegExp-Objekten aus anderen Fenstern, aus dem gleichen Grund, dass die '[Objekt-Array]' - Prüfung für Arrays nicht funktioniert. Eine Demo und https://groups.google.com/group/comp.lang.javascript/browse_frm/thread/368a55fec19af7b2/efea4aa2d12a3aa4?hl=de&lnk=gst&q=+ finden Sie unter http://www.jsfiddle.net/F6d8u/ Ein + isArray + test +% 28und + IE + bugs% 29 + # efea4aa2d12a3aa4 für eine Diskussion darüber. –

0

Es gibt keinen absoluten Weg, dies zu überprüfen, so weit die beste Antwort ist

var t = /^foo(bar)?$/i; 
alert(t instanceof RegExp);//returns true 

aber es gibt einen Nachteil bei diesem Ansatz und das ist wird es falsch zurück, wenn das reguläre Ausdruck Objekt commeing aus einem anderen Fenster.

0

Hier sind zwei Möglichkeiten:

/^\/.*\/$/.test(/hi/) /* test regexp literal via regexp literal */ 
/^\/.*\/$/.test(RegExp("hi")) /* test RegExp constructor via regexp literal */ 
RegExp("^/" + ".*" + "/$").test(/hi/) /* test regexp literal via RegExp constructor */ 
RegExp("^/" + ".*" + "/$").test(RegExp("hi")) /* test RegExp constructor via RegExp constructor */ 

delete RegExp("hi").source /* test via deletion of the source property */ 
delete /hi/.global /* test via deletion of the global property */ 
delete /hi/.ignoreCase /* test via deletion of the ignoreCase property */ 
delete RegExp("hi").multiline /* test via deletion of the multiline property */ 
delete RegExp("hi").lastIndex /* test via deletion of the lastIndex property */ 

Wenn ein Stringliteral begrenzt wird durch die regexp Backslash Begrenzer wird die regexp Selbsttest fehlschlagen.

Wenn Object.seal oder Object.freeze für ein benutzerdefiniertes Objekt ausgeführt werden und dieses Objekt auch alle oben genannten Eigenschaften aufweist, gibt die delete-Anweisung einen false-positiven Wert zurück.

Referenzen

+0

Ich verstehe deine Antwort nicht. – Tino

+0

@Tino RegExp-Typen haben zwei einzigartige Eigenschaften. Die Literalwerte beginnen und enden mit dem Zeichen '/'. Die Konstruktorinstanzen haben die Eigenschaften 'source',' global', 'ignoreCase',' multiline' und 'lastIndex'. –

+0

Danke, aber unglücklicherweise beweist 'frog', dass diese Eigenschaften ** für' RegExp' nicht eindeutig sind: '$$ = function() {}; $$. Prototype.toString = function() {return"/Ich bin keine Ente^WRegExp/"}; $$. Prototype.source = $$. Prototype.global = $$. Prototype.ignoreCase = $$. Prototype.multiline = $$. Prototype.lastIndex =" quack "; frog = new $$() ' – Tino