JavaScript (_.isFunction) code optimization - javascript

I needed to check an js object if is a function and i thought that this code should do it:
typeof param === 'function'
then i thought that checking with _.isFunction source code will be an good ideea.
Underscore has the if below wrapped arround the above check, which i'm not sure what exactly does or mean. If someone can explain this would be great. Thanks
// Optimize `isFunction` if appropriate.
if (typeof (/./) !== 'function') {
..
}

In some old versions of V8, regular expressions objects had a type of "function" (initially, regular expressions objects were callable as functions, even if nobody used that feature).
That's why it wasn't possible to use typeof param === 'function' to check if a value is a function.
This isn't the case now. Use typeof, not _.isFunction, this code is obsolete.

Related

Overusing Object.prototype.toString.call?

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.

MooTools 1.5.2 exploring typeOf and instanceOf

I decided to explore MooTools javascript core file to understand how such javascript frameworks work, unfortunately there are a lot of things in javascript that confuses me a lot because I don't know why particular function is made that way.
In the beginning of MooTools Core javascript file I see two functions: typeOf and instanceOf. I don't understand the purpose of these two lines of code:
var typeOf = this.typeOf = function(item){
var instanceOf = this.instanceOf = function(item, object){
Why function is assigned to typeOf variable and this.typeOf and why not just for var typeOf or just this.typeOf? And the same thing is with instanceOf.
I would be really grateful if anyone could explain why functions are assigned to variable and to global object what advantages can it give? I understand how it works but I simply can't understand why need to do it.
Doing var typeOf = this.typeOf has 3 purposes. One is to work with a small variable name inside the file and avoid using this.typeOf all the time, second and more important is to avoid mixing up scope inside a scope where this is something else. The third purpose, using this.typeOf is to export it to the scope where you are, and MooTools exports to global, ie the window object in the browser for example.
The function .typeOf is described in the docs and you can see it as a more usable method than the native typeof. Look at these diferences:
in MooTools:
typeOf([]) // gives you "array"
typeOf({}) // gives you "object"
typeOf(document.createElement('div')) // gives you "element"
in Native JavaScript
typeof [] // gives you "object"
typeof {} // gives you "object"
typeof document.createElement('div') // gives you "object"
So MooTools gives a much more valuable result. Similar behavior can be found in .instanceOf().

implementation of angular.isBoolean?

I was reviewing some source code and underscore/lodash was included just for the _.isBoolean function. The underscore source is below:
_.isBoolean = function(obj) {
return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
};
Looking at Function components in ng I see similar functions (angular.isObject, angular.isString, angular.isNumber, etc), but no angular.isBoolean function.
The angular.js source has this an internal function (source below), but an issue requesting to make public (feat: register isBoolean as a public member of global angular #5185) was closed saying "other libraries like underscore and lodash solve these problems well".
function isBoolean(value) {
return typeof value === 'boolean';
}
Questions:
My initial reaction was to copy isBoolean and make a named function in my code, but which implementation is more correct?
Do I use the underscore version in anticipation of compatibility with a future upgrade?
I assume it is a bad idea to "duck punch" my implementation into angular.isBoolean?
I was reviewing some source code and underscore/lodash was included just for the _.isBoolean function. […] My initial reaction was to convert isBoolean to a local function
Yes, good idea (if you emphasize the just). Maybe not even a function, but simply inline it.
but which implementation is more correct?
They behave differently when objects that are instances of the Boolean class are passed in. Will such ever occur in the app you are reviewing? Probably not. If they do, only you will know whether you want to consider them as booleans.
Apart from that, val === true || val === false has the same effect as typeof val == "boolean".
I assume it is a bad idea to "duck punch" my implementation into angular.isBoolean?
It's unlikely that angular will ever do this, so you hardly will provoke a collision. Still, ask yourself: Is it actually useful there? Will other code use it? For more discussion, have a look at Don't modify objects you don't own.

Why does IE choke on ({function:1}[typeof somefunc])?

Ok, I've been doing some research and starting using this convention when testing for object types or more apt, detecting typeof ..
({function:1}[typeof somefunc])
and this works, but alas - I tested in IE, error. So, no longer using it.. :-) ,.. but.
So, I reverted to testing in a standard way, no biggie (typeof somefunc === "function" or $.isFunction(somefunc)). But I am curious "why" it doesn't work in IE.
Also, can someone explain why this "does" work in Firefox, or what i mean to say is that the expression is odd to me, I want to know the internals of WHY It works (even though in selective browsers). I don't understand how its backreferencing the function:1 as a test with the typeof?
The JScript parser in IE8 and earlier is following the old ECMAScript 3.1 (1999) rules for object initializers, which require that if you want to use a reserved word (like function) as a property name, it must be in quotes. As of ECMAScript5 (2009), the quotes aren't required anymore because the context is unambiguous. Versions of IE released since the spec was updated (IE9+) do allow you to leave off the quotes.
The difference is that in ECMAscript5, the PropertyName in the object initializer grammar is just IdentifierName, not Identifier. Identifier is an IdentifierName that isn't a ReservedWord. function is a valid IdentifierName, but not a valid Identifier because it is a ReservedWord. More: Identifier Names and Identifiers. But the older spec didn't make that distinction between IdentifierName and Identifier, and so to use function there, you have to put it in quotes. (Thanks to chuckj for reminding me that this changed in ECMAScript5.)
Also, can someone explain why this "does" work in Firefox, or what i mean to say is that the expression is odd to me...
Yes, it's quite odd and anyone working on code using it is likely to stumble on it. It's a short way of writing (typeof somefunc=="function"). Here's what's happening:
The expression creates an object with one property, in this case the property name is function and the value is 1.
The typeof somefunc part is evaluated and returns "function" for a JavaScript function, "object" for a wide range of objects, "number" for a number primitive, "string" for a string primitive, etc.
That property name is used to look up a property on the object created in Step 1. If the property is found, the overall result of the expression is 1, a truthy value. If the property is not found, the overall result is undefined, a falsey value.
So ({function:1}[typeof somefunc]) tests if typeof returns "function" for somefunc. Similarly you can do ({object:1}[typeof someobj]) to check if typeof returns "object" for someobj, or ({string:1}[typeof somestring]) to check if typeof returns "string" for somestring.
Side note: This obscure way of doing the test doesn't perform well at all compared to the straightforward (typeof somefunc=="function"): Test when true | Test when false Unsurprising, given that typeof x == y can be highly optimized by a good optimizing engine. So this way of doing the check is harder to read, longer, no easier to type, and usually slower. Hmmm.... :-)
{function:1} is an object with exactly one key, 'function', mapped to a truthy value, 1. So, ({function:1}['function']) is truthy, but (for example) ({function:1}['string']) is falsy.
Most likely, the reason that IE doesn't support it is that function is a reserved word (as you must know), and IE apparently is getting confused by its use in this context. (If so, this is a mistake in IE: surprisingly, the spec actually does allow reserved words to be used in this context.)
just put function in quotes as function is a reserved keyword but "function" is just a string literal
({"function":1}[typeof somefunc])
should work just fine
but then, why won't you simply use:
(typeof somefunc == "function")
it's shorter and more intuitive

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