Is there anyway to detect if a JavaScript object is a regex?
For example, I would like to do something like this:
var t = /^foo(bar)?$/i;
alert(typeof t); //I want this to return "regexp"
Is this possible?
Thanks!
EDIT: Thanks for all the answers. It seems I have two very good choices:
obj.constructor.name === "RegExp"
or
obj instanceof RegExp
Any major pros/cons to either method?
Thanks again!
You can use instanceof operator:
var t = /^foo(bar)?$/i;
alert(t instanceof RegExp);//returns true
In fact, that is almost the same as:
var t = /^foo(bar)?$/i;
alert(t.constructor == RegExp);//returns true
Keep in mind that as RegExp is not a primitive data type, it is not possible to use typeof operator which could be the best option for this question.
But you can use this trick above or others like duck type checking, for example, checking if such object has any vital methods or properties, or by its internal class value (by using {}.toString.call(instaceOfMyObject)).
alert( Object.prototype.toString.call( t ) ); // [object RegExp]
This is the way mentioned in the specification for getting the class of object.
From ECMAScript 5, Section 8.6.2 Object Internal Properties and Methods:
The value of the [[Class]] internal property is defined by this specification for every kind of built-in object. The value of the [[Class]] internal property of a host object may be any String value except one of "Arguments", "Array", "Boolean", "Date", "Error", "Function", "JSON", "Math", "Number", "Object", "RegExp", and "String". The value of a [[Class]] internal property is used internally to distinguish different kinds of objects. Note that this specification does not provide any means for a program to access that value except through Object.prototype.toString (see 15.2.4.2).
A RegExp is a class of object defined in the spec at Section 15.10 RegExp(RegularExpression)Objects:
A RegExp object contains a regular expression and the associated flags.
Give the .constructor property a whirl:
> /^foo(bar)?$/i.constructor
function RegExp() { [native code] }
> /^foo(bar)?$/i.constructor.name
"RegExp"
> /^foo(bar)?$/i.constructor == RegExp
true
From underscore.js
// Is the given value a regular expression?
_.isRegExp = function(obj) {
return !!(obj && obj.test && obj.exec && (obj.ignoreCase || obj.ignoreCase === false));
};
Works in google chrome:
x = /^foo(bar)?$/i;
x == RegExp(x); // true
y = "hello";
y == RegExp(y); // false
"Regexp" is not a native Javascript type. Most of the above answers tell you how to accomplish your task, but not why. Here's why.
There is no absolute way of checking this, so far the best answer is
var t = /^foo(bar)?$/i;
alert(t instanceof RegExp);//returns true
but there is one down side to this approach and that's it will return false if the regular expression object is commeing from an other window.
Here are two ways:
/^\/.*\/$/.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 */
If a string literal is delimited by the regexp backslash delimiter, the regexp self test will fail.
If Object.seal or Object.freeze are run on a user-defined object, and that object also has all of the aforementioned properties, the delete statement will return a false positive.
References
ECMAScript 5, Section 15.10.4.1 new RegExp(pattern, flags)
What are some use-cases of when delete has been very useful in JavaScript?
Why is this configurable property not deletable?
Webkit JavaScriptCore source: ObjectConstructor.cpp
Object Properties in JavaScript
I was looking for typeof regex because I tried use it in type definition for TypeScript props on a function.
Then I do the next:
const RegexType = /$/;
type paramProps = {
regexParam: typeof RegexType;
}
You can test here:
const RegexType = /$/;
const t = /^foo(bar)?$/i;
console.log(typeof t == typeof RegexType) //true
Related
Hi I have this simple code:
let obj = {
games: [
{id: 'test'}
]
}
console.log(obj.games[0].id) // returns: test
console.log('games[0].id' in obj) // returns: false
console.log(obj.hasOwnProperty('games[0].id')) // returns: false
I don't understand the return value when I try to check for its property name instead of returning its property value.
You have three objects and the methods you are using to test are meant for a single object.
obj - object containing a games property
obj.games - array with one element
obj.games[0] - object with id property
Consider these which all are true:
let obj = {
games: [
{id: 'test'}
]
}
console.log(`obj.hasOwnProperty('games')`, obj.hasOwnProperty('games'))
console.log(`'games' in obj`, 'games' in obj)
console.log(`obj.games.hasOwnProperty('0')`, obj.games.hasOwnProperty('0'))
console.log(`'0' in obj.games`, '0' in obj.games)
console.log(`obj.games[0].hasOwnProperty('id')`, obj.games[0].hasOwnProperty('id'))
console.log(`'id' in obj.games[0]`, 'id' in obj.games[0])
if (obj && obj.games && obj.games.length > 0 && obj.games[0].id) {
console.log('obj.games has at least one element, '
+ 'and the first element has an id')
}
let id = obj && obj.games && obj.games.length > 0 && obj.games[0].id;
console.log('id:', id);
in and hasOwnProperty() just take a single property name, they don't accept an expression with nested properties.
So you have to test each level separately.
console.log('games' in obj && 0 in obj.games && "id" in obj.games[0])
You can also use optional chaining to combine all but the last check.
console.log(obj?.games.?[0] && "id" in obj.games[0])
The in operator can only test a single attribute. It's not intelligent enough to follow a path.
You could just
const value = obj?.games?.[0]?.id;
const exists = value !== undefined;
console.log(exists)
More importantly, in this case you really shouldn't use the in operator at all. The disadvantage of the in operator, is that it requires the tested field to be coded as a string.
In general putting the names of fields in strings is something to avoid, because it makes it harder to find usages and to refacture code later on.
The use of the in operator can only be justified if the name of the tested field is not a constant, not known in advance.
Having said that, the hasOwnProperty function does something slightly different. It is actually more strict than the solution presented above, and also more strict than the in operator. It strictly checks for fields on the object itself, not the ones of super/base types.
The hasOwnProperty() method returns true if the specified property is
a direct property of the object — even if the value is null or
undefined. The method returns false if the property is inherited, or
has not been declared at all. Unlike the in operator, this method does
not check for the specified property in the object's prototype chain. (source: MDN)
in operator seems to be available since forever ago.
var obj = {foo: 'bar'};
if ('foo' in obj) {
console.log(obj.foo);
}
if (undefined !== obj.foo) {
console.log(obj.foo);
}
The two if blocks in the code above do the same thing. This example itself may be too simple, but by reading MDN, to me, I wouldn't use it. Besides typing less characters and readability, are there any benefits / advantages that I don't see? Can you give me a good example of in operator usage?
From MDN:
If you set a property to undefined but do not delete it, the in operator returns true for that property.
So, the in operator can be used to find if a property exists in an object, even if it is undefined. The second way you show, undefined !== obj.foo, will return false if the property doesn't exist, OR is undefined.
Example:
var obj = { myProp: undefined };
'myProp' in obj; // = true
obj.myProp !== undefined; // false
I can see this being useful if you want to confirm that a property exists on an object before assigning a value to it, since the assignment will work even if the property didn't previously exist.
Here's some example that shows a use case for this:
var obj = { foo: undefined }
obj.foo !== undefined; // false
'foo' in obj; // true
When using the in operator, you test if the property is specified in the given object and not its value.
Using the in operator in javascript we not also can check for a particular property but can iterate over the list.
The ES 5 specification details two distinct syntaxes for the for-in statement:
1.for (var variable in objectExpression) {statement}
2.for (LeftHandSideExpression in objectExpression) {statement}
For Ex.
If i have an Array object like
var objarray=new Array('rakesh','naresh','dinesh','nilesh');
then i can directly loop over the Array Object.
for(var a in objarray)
{
console.log(objarray[a])
};
The output we get is:
rakesh
naresh
dinesh
nilesh
So the 'in' operator has other benefits other than only checking value.
I was looking up how to check if a variable in JavaScript is an array, but then as the SO page was loading, I thought of a solution to the problem. Looking through the answers, I found that none of them had thought of this simple answer: Just check for the methods we need to use on the array, so that it still works for any user defined types that implement the same methods. Being the helpful person I am, I thought I'd submit my answer for future people trying to solve the same problem..But after testing it, I found it does not work.
function print(object) {
if ('map' in object) { // If the object implements map, treat it like an array
object.map(function(current) {
console.log(current);
});
} else { // Otherwise, treat it as a string
console.log(object);
}
}
Now, this works fine when I call it with an array, but if I use a string it fails. Since strings are objects in javascript, why shouldn't the 'in' keyword work for them? Is there any way to implement this that is as simple as what it currently is?
You can access the property and test its type:
if (object != null && typeof object.map === 'function')
object.map(...);
// ...
Since strings are objects in javascript, why shouldn't the 'in' keyword work for them?
Not quite. There is a difference between a primitive string value and a String instance object.
typeof "foo"; // "string"
typeof new String(); // "object"
Primitive values don't have properties themselves, which is why the in operator throws an Error when used on them. They will, however, be temporarily boxed into Objects by property accessors:
var a = "foo";
a.bar = 'bar'; // no error, but...
console.log(a.bar); // undefined
String.prototype.baz = function () {
return this + this;
};
console.log(a.baz()); // "foofoo"
I suppose you could do something like this:
var y = function (o) {
if (typeof o != "string" && "map" in o)
console.log("not a string"); //your code here
else
console.log("It's a string!"); //your code here
}
I tested this with var x = "hello" and it worked. Because && short circuits in JavaScript, it will stop at typeof o != "string", which is good, since "map" in o fails for strings. Note the intentional use of lowercase, which is for primitives; Strings are objects. I'm not exactly sure if this is what you were aiming for.
This question is a spin-off of [] is an instance of Array but "" isn't of String
Given that
"" instanceof String; /* false */
String() instanceof String; /* false */
new String() instanceof String; /* true */
and
typeof "" === "string"; /* true */
typeof String() === "string"; /* true */
typeof new String() === "string"; /* false */
Then, if I have a variable abc and I want to know if it's a string, I can do
if(typeof abc === "string" || abc instanceof String){
// do something
}
Is there a simpler, shorter and native way of doing this, or must I create my own function?
function isStr(s){
return typeof s === "string" || s instanceof String;
}
if(isStr(abc)){
// do something
}
I think Object.prototype.toString.call(a) === "[object String]" is the shortest/nativest way of doing this
you are correct:
typeof myVar == 'string' || myVar instanceof String;
is one of the best ways to check if a variable is a string.
You may be confused because [] is an array initialiser (often called an array literal) that is defined as creating an Array object, whereas '' is a string literal that is defined as creating a string primitive.
A primitive isn't an instance of any kind of object, though it may be coerced to a related object for convenience.
A more important question is why an isString function should return true for both string primitives and string objects? The use of string objects is (extremely?) rare, I would have thought that their use would infer special treatment and that you would want to differentiate between the two and not treat them the same.
It's far more common to ignore the Type of a variable and, where it's Type might vary, unconditionally convert it to the required Type, e.g. if you want a string primitive:
function foo(s) {
s = String(s); // s is guaranteed to be a string primitive
...
}
The exception is where functions are overloaded and have different behaviour depending on whether a particular argument is a Function, Object or whatever. Such overloading is generally not considered a good idea, but many javascript libraries are dependent on it. In those cases, passing a String object rather than a string primitive may have unexpected consequences.
Trying to get my JavaSscript fundamentals strong. So the question is about string literals. Aren't they Objects? If your answer is 'yes' then my question is why is instanceof returning false?
> var s = new String
> s.constructor.toString()
function String() { [native code] }
> typeof s
object
> s instanceof String
true
> s instanceof Object
true
> s instanceof Number
false
So far so good.
> typeof 'c'
string
> 'c' instanceof Object
false
> 'c' instanceof String
false
> 'c'.length
1
> 'c'.charAt(0)
c
> 'c'.constructor.toString()
function String() { [native code] }
String literals are primitives (String values), String objects can be created with the String constructor in a new expression:
"foo" instanceof String // false
new String("foo") instanceof String // true
Edit: Something that seems to be confusing (by looking at the accepted answer here), is that you can still access properties defined on the prototype objects of primitive values, for example:
"foo".indexOf == String.prototype.indexOf // true
"foo".match == String.prototype.match // true
String.prototype.test = true;
"foo".test // true
true.toString == Boolean.prototype.toString
(3).toFixed == Number.prototype.toFixed // true
// etc...
The reason of that relies on the Property Accessors, the dot notation . and the bracket notation [].
Let's give a look to the algorithm in the ECMA-262 specification:
The production MemberExpression : MemberExpression [ Expression ] (or MemberExpression . Identifier) is evaluated as follows:
Evaluate MemberExpression.
Call GetValue(Result(1)).
Evaluate Expression.
Call GetValue(Result(3)).
Call ToObject(Result(2)).
Call ToString(Result(4)).
Return a value of type Reference whose base object is Result(5) and whose property name is Result(6).
In the Step 5, the ToObject internal operator type-converts the MemberExpression to object, depending on it's type.
The primitives are converted to Objects without noticing, and that's why you can access the properties defined on the prototype.
Great explanation of this here. Copied for reference below.
That's because those things are primitives, and unless they need to be used as objects (when you are calling methods on them, for example) they remain so. The only time they "become" objects is when they need to be wrapped. If you are familiar with the concept of "boxing" in .NET, then think of it in that way.
Here is an example - take a look at this code:
Number.prototype.times = function(func) {
for(var index = 1; index <= this; index++) {
func(index);
}
};
So, the following code will fail:
3.times(print); // assume 'print' writes to standard out
3, by itself is a primitive. That said, the following will work:
(3).times(print); // assume 'print' writes to standard out
That would display the numbers 1, 2, and 3. Because of the parenthesis, the JavaScript interpreter will temporarily wrap the primitive 3 in a Number object, call the method, and then garbage collect the object since it isn't needed any longer.
Anyway, a full discussion of this can be found in "JavaScript: The Definitive Guide."