0

I grew a little frustrated with the built-in typeof method, as it doesn't handle it's job very well. Is adding a type property to the object prototypes a bad idea, and (if so) why is that?

Array.prototype.type = "Array";
Object.prototype.type = "Object";
Function.prototype.type = "Function";
String.prototype.type = "String";
Number.prototype.type = "Number";


function typeOf(obj) {
    if (!obj) return obj; // Returns undefined and null values.

    return obj.type;
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
Amsvartner
  • 733
  • 7
  • 19
  • 2
    Did you try `Object.prototype.toString.call(obj)`? – thefourtheye May 12 '14 at 13:37
  • 1
    @thefourtheye Doesn't work with instances created by custom constructors however. – plalx May 12 '14 at 13:49
  • 1
    [very bad idea](http://stackoverflow.com/q/13296340/1048572). Why don't you use `instanceof`? – Bergi May 12 '14 at 13:49
  • @plalx But he is worried about the built-in types only, I guess – thefourtheye May 12 '14 at 13:50
  • @thefourtheye: I didn't know about that, it seems to work well although the syntax is poking holes in my eyes :) I'm just thinking of the built-in types, as you guessed. – Amsvartner May 12 '14 at 14:07
  • 1
    @Amsvartner: Ok, the idea is not *that* bad - many languages use something like that (even in JavaScript you can just check `.constructor`) - but your implementation is deadly, as it does add an enumerable property to all objects. – Bergi May 12 '14 at 14:13
  • 1
    Conflicts might arise with third-party libraries when you extend native prototypes, but it also impairs your ability to **safely** reuse **your own code** in multiple projects. – plalx May 12 '14 at 14:13
  • 1
    @Amsvartner: Well, even your `typeOf` function needs to check for `null` and `undefined` separately; I don't see a reason why it shouldn't use `instanceOf` or compare the `.constructor` instead of accessing that extra `.type`. – Bergi May 12 '14 at 14:19
  • 1
    In the browser why,not , in nodejs it might not help that much as you'd have to require a module within all the modules where you want to check the type. A better idea would be to use something like underscore or lodash that have isArray is... functions. – mpm May 12 '14 at 14:19
  • @Bergi - Yeah, I figured out what you meant by revisiting the post a second time, but you were too quick to reply for me to update my comment. Thanks a lot for the information, I will incorporate the "enumerable:false" idea into the code whilst keeping in mind that it's not compatible with older browsers. Cheers! **Edit:** As a reply to your latest question; I know that I make the same number of checks inside the typeOf method, but I get a much cleaner syntax in the code wherever I use it which makes the code easier to read. The trade-off is not worth it if it breaks other stuff though. – Amsvartner May 12 '14 at 14:27

2 Answers2

1

You can do something like this

function typeOf(inputArg) {
    if (!arguments.length) {
        throw new SyntaxError();
    }

    if (typeof inputArg === 'undefined') {
        return 'undefined';
    }

    if (inputArg === null) {
        return 'null';
    }

    return ({}.toString.call(inputArg).match(/\[object (Number|Boolean|String|Array|Object|Function)\]/) || ['Object']).pop().toLowerCase();
}

console.log(typeOf(undefined));
console.log(typeOf(null));
console.log(typeOf(1));
console.log(typeOf(true));
console.log(typeOf(''));
console.log(typeOf([]));
console.log(typeOf({}));
console.log(typeOf(function () {}));
console.log(typeOf(/a/));
console.log(typeOf());

Output

undefined
null
number
boolean
string
array
object
function
object
Uncaught SyntaxError 

On jsFiddle

However, there are some other bugs in older browsers which can still cause different results. And this does not take into account E4X XML stuff, or any new types that may get defined in ECMA next (though probably nothing new). You also need to be aware that this will identify primitive objects, i.e. new String('hello') as a string rather than an object, which may not be what you desire. So you need to think carefully as to your needs or what you are trying to achieve (which I'm not totally clear about).

Xotic750
  • 22,914
  • 8
  • 57
  • 79
1

If you're just looking for a way to test for types 'lodash' (and probably 'underscore') brings functions that might test in a way more to your liking:

http://lodash.com/docs#isArray (and all other _.is* functions)

Risadinha
  • 16,058
  • 2
  • 88
  • 91