Overusing Object.prototype.toString.call? - javascript

I just saw a blog post with the code
if(Object.prototype.toString.call(callback) !== '[object Function]'){
return new TypeError(callback + ' is not a function');
};
In this specific situation it looks like over-engineering it since we could use typeof callback. I see no situation, for the purpose of this code, where typeof callback would not give the correct answer. Even more, the prototype could be overridden and start giving wrong answers while typeof can't.
Example would be:
Object.prototype.toString = function(){return '[Object String]';};
Object.prototype.toString.call([])
// logs "[Object String]"
Question: is there any situation (given the purpose of this line, which is to check if a variable is a function) where typeof would fail?
I think its more correct, semantic and not over-engineering to use:
if(typeof callback !== 'function'){
return new TypeError(callback + ' is not a function');
};

The Object.prototype.toString check is from the ES5 and earlier era, when the results of that method could not be forged through a custom Symbol.toStringTag implementation. However even then, if one wanted to be very strict about these tests, they would usually have had to grab a reference to the toString function at initial evaluation time, since Object.prototype.toString can itself be overwritten — as could Function.prototype.call.
Today it would never make sense to perform a type check this way, and you’re correct that even at the time, it wasn’t typically necessary. However in the past there were a number of platform objects in browsers that returned unique strings from typeof, and that was likely one of the motivations for performing a test this way. Today there is only one such weird case remaining: typeof document.all returns undefined, but it is actually a function.
Your instinct to prefer typeof is still correct, though. The case of document.all is probably not worth worrying about in almost any code, and even if it is, the toString check will not be reliable. An example of a real reliable (paranoid) check would be:
var _Object = Object;
function isObject(value) {
return _Object(value) === value;
}
function isFunction(value) {
return typeof value === 'function' || (isObject(value) && typeof value === 'undefined');
}
console.log(isFunction(function() {})); // true
console.log(isFunction(document.all)); // true
So the answer to the part you marked ‘question’ is yes, there is one situation where typeof n === 'function' returns a misleading string, and historically there were additional situations.
More meta, regarding the ‘overengineering’ question: Perhaps the author learned it as a ‘best practice’ at some time in the past and hasn’t reviewed it in a while because, hey, it’s what’s familiar to them and it works, etc. Although there are better options, I wouldn’t call an awkward if condition overengineering. To me at least, overengineering refers to stuff at a higher level than this — architectural choices, etc. Things that are hard to refactor.
Personally, I would suggest that if you’re writing code that performs early input validation a lot, eschewing direct use of typeof might still be a good idea. Testing ‘types’ in JS is often not so straightforward, so a collection of isSomething functions like those in the example above can help abstract away the quirkier implementation details and bring some consistency and readability back. As functions, they’re also more flexible (e.g. arr.filter(isFunction)). There are popular libs that provide such utils and if using them you typically won’t need to worry about how it’s being achieved.

Related

Non-nullish logic check for objects

What is the correct/best way to refactor this logic, using nullish operator? -
if (value !== undefined && value !== null && typeof value !== 'object') {
// error, when not null/undefined, it must be an object
}
UPDATE
So far I've tried this one, which seems to be working, though looks a little odd:
if (typeof (value ?? null) !== 'object') {
// error...
}
Would that be a proper equivalent?
P.S. I'm writing this is TypeScript, so browsers compatibility doesn't concern me.
Although your existing implementation example will work, JavaScript's typeof function has a longstanding history of causing confusion in the case of typeof(null) returning 'object'. One of your most important considerations in refactoring code will always be the maintainability of your code, and any likely source of confusion is likely to reduce maintainability.
If someone were to look at this code right now, particularly any developer who is inexperienced with JavaScript or has never run into the typeof(null) quirk, they would assume that your code is looking for all non-object types, including the values of null and undefined rather than excluding them.
Additionally, although current JavaScript standards are unlikely to change the behavior of typeof(null) to avoid breaking existing code, there's no absolute guarantee that this behavior will never change. There's especially no guarantee that TypeScript itself won't change this behavior to be more intuitive and transcompile down to a different JavaScript equivalent.
You're far better off avoiding confusion in your code as well as potentially future compatibility breaking updates if you modify the default fallback value for your nullish coalescing operation. Specifically, default to {} which is always guaranteed to be interpreted as an object and will be far less likely to be subject to breaking changes in either JavaScript or TypeScript:
if (typeof (value ?? {}) !== 'object') {
// error...
}

Check if JavaScript function returns without executing it?

I have a given function that takes, among other arguments, two optional arguments which may be functions. Both need to be optional, one will be a function, and one will either be a boolean or a function that returns a boolean.
// Obj.func(variable, String[, Object][, Boolean||Function][, Function]);
Obj.func = function(other, assorted, args, BoolOrFunc, SecondFunc) {
// execution
};
Obj.func(
[
'some',
'data'
],
'of varying types',
{
and: 'some optional arguments'
},
function() {
if(some condition) {
return true;
}
return false;
},
function() {
// do things without returning
}
);
It is my desire that both functions (and several of the other arguments, if it matters) be optional, which means I have code in the function to determine which arguments the user intended to use.
Unfortunately, as both may be functions, and may be specified directly in the function call, I cannot simply use typeof or instanceof conditionals. However, since the first function, if it exists, will always return a boolean (and the second function will not return at all), one idea I had would be to check its return value:
if(typeof BoolOrFunc === 'boolean'
|| (typeof BoolOrFunc === 'function' && typeof BoolOrFunc() === 'boolean')) {
// BoolOrFunc is either a boolean or a function that returns a boolean.
// Handle it as the intended argument.
} else {
// Otherwise, assume value passed as BoolOrFunc is actually SecondFunc,
// and BoolOrFunc is undefined.
}
This works in principle; however, running typeof BoolOrFunc() executes the function, which causes a problem if the function does more than just return a boolean: that is, if the function passed as BoolOrFunc is actually meant to be SecondFunc. SecondFunc, in this case, is something of a callback function, and may perform actions, including DOM modifications, that I don't want to execute immediately.
For this reason, my question is: Is there a way to check if a function returns without executing it?
One thing I had considered was to call BoolOrFunc.toString(), then perform a Regular Expression search for the return value, something along the lines of…
if(typeof BoolOrFunc === 'boolean'
|| (typeof BoolOrFunc === 'function'
&& BoolOrFunc.toString().search(/return (true|false);/) !== -1)) {
// BoolOrFunc is either a boolean or contains a return string with a boolean.
// Handle it as the intended argument.
}
Note that the above code may not work as written: I've not actually built a test case for it, because, well, it seems exceptionally inefficient and potentially unreliable, and I figured someone here might have a more elegant solution to my quandary. That having been said, I figured I'd include it for discussion purposes.
Meshaal made a prediction in the question:
"... one will either be a boolean or a function that returns a boolean."
"... first function, if it exists, will always return a boolean."
With this prediction the function is not a Turing Machine, because we know that it returns something. Surely it can't be done with a simple RegExp: just return !0 would break the example.
But if you parse the result of function.toString() with a parser being intelligent enough to find all possible return points, the problem should principally be solvable.
Interesting question, if I understand correctly. First, I'd probably warn against having such open-ended arguments. I'm curious as to the use case.
But that said, it's easy enough to get around the problems you mention (which may not wholly solve your problem).
This works in principle; however, running typeof BoolOrFunc() executes the function...
That's easy enough to fix, I think. At first, just check to see if BoolOrFunc is a boolean or a function (just typeof BoolOrFunc, natch). If it's a boolean, I assume we're fine. Either SecondFunc is missing (undefined) or a function -- or we're in an error state. That's all easy to handle in this first case.
So let's assume the second case, that we have BoolOrFunc-As-Function. We're going to have to execute it, whether it's "really" BoolOrFunc or SecondFunc, so, at the last moment possible in your code, do so.
This is obviously where things get complicated without more pseudo-code (or production code) from you. If the "possible BoolOrFunc" returns true or false, you know you have a function version of BoolOrFunc. If it returns undefined, you know you just called SecondFunc. Again, depending on what you're trying to do, you branch here. If you have a true or false, you have to process out "BoolOrFunc-as-function", else you've called SecondFunc and are likely done.
That doesn't answer the more generic question of how to tell if a function returns a specific type without calling it, but does solve your use case as presented here.
But this specific more generic case [sic] isn't too difficult, as long as we're dealing with real, constant booleans in the returns. In that case, the regexp route would work -- find all return\s+.*; and make sure what follows each return is true or false. Or just compare total return count is the same as that for return\s+(false|true);. Or something. And hope the javascript in the function is well formed. What a bear already.
If the function can return local variables (return MightBeBoolean; rather than return true;), you're nearly toast -- or if you accept truthiness or falsiness, you're nearly toast again, since undefined is falsey, and you can't tell the difference between BoolOrFunc or SecondFunc (which would always return "falsey"). It's possible, but not nearly worth writing the parser in any reasonable use case I can imagine. And if you're importing a lib to do that, sheesh. Good luck. Seems like overkill to have function that's slightly more defensive in its calling.
I do wonder if either functions passed as arguments are themselves passed arguments from your Obj.func, which would make things even more interesting.
Got more real code? ;^) But ultimately I'm recommending you don't do the "pass any jumble of arguments, as long as they're in order". I think you can likely do the BoolOrFunc/SecondFunc late evaluation. Otherwise, I hate to say it, but code a bit more offensively here.

Mozilla developer page - But never use this form

My question is about the Mozilla developer page: typeof operator
In the example chapter, whenever a comparison of the following form is done they comment it:
typeof Number(1) === 'number'; // but never use this form!
Although they never explain why. It's easy to see why it's a silly way of going about type-checking, but I'm curious as to the reason why they went out of their way to make that comment multiple times.
Any clues are welcome.
Note: Is it because Number() is a constructor called without the new operator? (my first guess)
Ps: Code examples were tested in Firefox's console version 27.0
They do explain why. On that same page, (a little bit past what you copied), it says
typeof new Boolean(true) === 'object'; // this is confusing. Don't use!
typeof new Number(1) === 'object'; // this is confusing. Don't use!
typeof new String("abc") === 'object'; // this is confusing. Don't use!
Notice how the new keyword is there. In your example, there is no new keyword. Kind of hard to spot, isn't it? So what they're trying to say is that since one's type is number and the other's type is object but the two look so similar, it's can be confusing what you mean.
Many problems can arise from thinking an object is a number because it acts like a number in some ways. For example, type checking with typeof and comparisons with ===.
Although, I can see that it isn't expressed very clearly on that page.
It is because of the lack of new. Writing new Number(1) creates a Number object with the value 1. This is seldom needed. However, Number(1) does not create a Number object — instead, it just returns the number 1. This is confusing (since it visually looks like object creation) and unnecessary since you can just write 1 instead.
The author(s) of that page seem to be a bit confused or intent on causing confusion.
There’s nothing wrong with that “form” except that Number(1) is redundant – it’s equivalent to 1.
Arguably, it’s confusable with new Number(x), but +x (the other common way) is kind of obscure at first glance, and there’s no chance of mixing the two up if you know to never use primitive wrappers.
Did I mention you should never use primitive wrappers?

Testing Object/Function existence for cross browser javascript

I would like advice as to best practice in testing object existence for cross-browser compatibility.
There seem to be many ways of testing for object/function/attribute existence. I could use jquery or another library, but for now I want to stick as closely as possible to w3c rather than use what amounts to a whole new language.
What I'm trying to do
I'm trying to write a utility library that tries to stick to w3c methods so I can just call
xAddEventListener(elem, type, listener, useCapture)
for all browsers rather than
elem.AddEventListener(type, listener, useCapture)
just for w3c compliant browsers. If another library already does this, please let me know.
I saw this today:
if (typeof node.addEventListener == "function")
but will this ever yield a different result than plain
if (node.addEventListener)
Style documents?
A reference to a standards or styles document would also be useful. I've found https://developer.mozilla.org/en/Browser_Detection_and_Cross_Browser_Support
but that was last updated in 2003. It advocates simple
if (document.images)
tests for most existence tests and
if (typeof(window.innerHeight) == 'number')
only with numbers because if(0) would evaluate to false
Examples to inspire comment:
if (myObject)
Can an object or function ever fail this simple test?
if (myObject != undefined)
When is this better than the previous test?
if (typeof(myObject) == 'object')
This appears to be the original way of calling type of, but some people say that typeof is a keyword and not a function. Also, why not one of the simpler tests?
if ( typeof myObject.function !== undefined ) {
One post said to alway use === or !== as it differentiates between null and undefined. Is this ever important in practice?
Another possibility is:
try {
node.addEventListener(...)
}
catch(err) {
node.attachEvent(...)
}
Which in python appears to be becoming the favourite way of dealing with these type of things.
Using exceptions looks potentially much cleaner as you could write easy to understand w3c compliant code, and then deal with exceptions when they come.
Anyway, what do people think? Please can you list the pros and cons of methods you like/dislike, rather than simply advocating your favourite.
It all depends on how specific you want to be / how much you want to assert before calling a function.
if (myObject)
Can an object or function ever fail this simple test?
No, the only values that do not pass an if clause are false, 0, "", NaN, undefined and null. These are all primitives. Objects (including functions) will always pass an if clause.
if (myObject != undefined)
When is this better than the previous test?
If you want to check whether a value is "meaningful", i.e. not undefined or null. For example,
if(numberInputtedByUser) {
// do something with inputted number
}
will fail the if clause if the number is 0, while you probably want 0 to be allowed. In such case, != undefined is a slightly better check.
if (typeof(myObject) == 'object')
This appears to be the original way of calling type of, but some people say that typeof is a keyword and not a function. Also, why not one of the simpler tests?
It is a keyword. You can call it in a function-like fashion, though. In its most bare form you can use typeof like this:
typeof myObject
You can, however, add (extraneous) parens since they don't mean anything:
typeof (myObject)
Just like you can do:
(myObject).key
or even:
(((myObject))).key
And you can then remove the space after the typeof if you want, resulting in something that looks like a function call.
As to why to use typeof - you can be even more certain of the type of variable. With the if(...) test, the values that pass can be all kind of things - basically everything except the list I posted above. With if(... != undefined), you allow even more to be passed. With if(typeof ... == 'object'), you really only allow objects which might be necessary depending on what you're processing.
if ( typeof myObject.function !== undefined ) {
One post said to alway use === or !== as it differentiates between null and undefined. Is this ever important in practice?
=== is really preferred over ==. While differentiating between null and undefined is not always necessary, it is a very good practice to save yourself from the results of quirks like 0 == ''. If you want to check whether a number is 0, then === 0 is the way to go, since == 0 also allows for an empty string (which you might not expect and probably don't want). Even in cases == doesn't cause quirks, you'd be better off using === at all times for consistency and avoiding surprising bugs.
try {
node.addEventListener(...)
}
catch(err) {
node.attachEvent(...)
}
This is of course possible and very straight-forward. Note however that try catch is said to be slow. Moreover, you don't really account for why it fails. It's a bit simple-minded (but may work fine).
if (typeof node.addEventListener == "function")
but will this ever yield a different result than plain
if (node.addEventListener)
Yes, like I said above, the first only passes functions whilst the second allows anything except that list of "falsy" values. One could add Node.addEventListener = 123, and it will pass the if clause in the second case. But IE fails to give a correct typeof result:
typeof alert !== "function"
I bet the same goes for addEventListener so you'd still be avoiding that function even if it exists.
In the end, I would just use a simple if clause. Of course this will fail when you add weird things like Node.addEventListener = 123, but then again you're bound to expect weird things happen.

Best method of testing for a function in JavaScript?

I've done quite a bit of research into this but it seems that the methods used are inconsistent and varied.
Here are some methods I have used in the past:
/* 1: */ typeof myFunc === 'function'
/* 2: */ myFunc.constructor === Function
/* 3: */ myFunc instanceof Function
As part of my research I had a look at how some well-known libraries accomplished this:
/* jQuery 1.2.6: */ !!fn && typeof fn != "string" && !fn.nodeName && fn.constructor != Array && /^[\s[]?function/.test( fn + "" )
/* jQuery 1.3b1: */ toString.call(obj) === "[object Function]"
/* Prototype 1.6: */ typeof object == "function"
/* YUI 2.6: */ typeof o === 'function'
I'm amazed there are so many different methods beings used, surely a single acceptable test has been agreed upon? And I'm completely clueless as to what the intentions were with jQuery 1.2.6's rendition, looks a bit OTT...
So, my quesiton remains, what is the best* way of testing for a function?
I would also appreciate some insight into some of the above methods, especially jQuery 1.2.6's. (I can see what they're doing, it just seems odd)
[*] By 'best', I mean the most widely accepted cross-browser compatible method.
EDIT: Yes, I know it's been discussed before but I'd still like some discussion on the most effective method. Why are there so many different used methods?
The discussions on SO thus far have only mentioned the typeof operator (mostly) but nobody has hinted at the effectiveness of alternate methods.
The best way to test if an object is a function is typeof myFunc === 'function'. If you are using a library, use that library's function test: jQuery.isFunction(myFunc).
Things can be misreported as functions when using typeof. This is very rare but a library is there to remove these inconsistencies. jQuery working around these issues:
Firefox reports function with typeof document.createElement("object")
Safari reports function with typeof document.body.childNodes
Older versions of Firefox reported regular expressions as functions (this not the case in 3.0).
Some IE built in global functions (alert) and some node methods (getAttribute) are reported to be of type "object".
Using instanceof rather than typeof circumvents some of these. For example, document.createElement("object") instanceof Function is false in Firefox.
You can view the birth of the first method in the comments for the original ticket (#3618). The new method is from changeset 5947 and seems to have been invented by Resig to solve IE memory leaks. It's probably slower, but smaller, and cleaner.
There isn't much difference between == and === here in terms of how things work but the strict evaluation is ever so slightly faster and thus preferred.
John Resig the developer of jQuery does seem to have made some bizarre choices in the internals of jQuery.
toString.call(obj) === "[object Function]"
looks quite neat but I can't think of any situation where the above would be true where the simple typeof approach would fail but perhaps he knows something the rest of use don't.
typeof o === "function"
I would go with the latter since it has greater clarity, unless you've got strong evidence that it won't work.
Why use strict equality on typeof since both operands are strings? I am overlooking some issue?
Anyway, I would go the simpler way of typeof, which seems like being done for that and is readable. instanceof is readable too, but it seems to insist more on the fact that a function is an object, which might be irrelevant to the problem.

Categories

Resources