I have been playing around with call method in JavaScript and I found something interesting:
I was creating a custom map function and I did something like this:
function map(collection, callback, context) {
if (!collection || !collection.hasOwnProperty('length') || typeof(callback) !== 'function') {
throw new TypeError();
}
var newArray = [];
var isFunction = typeof(callback.call) === 'function'; // this I added after to prove my point.
console.log('is callback.call a function? ' + (isFunction ? 'yes it is!' : 'no, it is not a function'));
for (var i = 0, len = collection.length; i < len; i++) {
newArray[i] = callback.call(context, collection[i], i, collection);
}
return newArray;
}
At this point I executed my map
function with following arguments:
var arr = map(Array.apply(null, { length: 2 }), Number.call);
I skipped value for context argument, so it is undefined
. Which supposed to be cool. Also what is a little bit strange as callback
I passed call
method so in the end: I invoke call
method on call
method (which is also cool).
But for unknown reason browser gives me this error:
is callback.call a function? yes it is!
Uncaught TypeError: callback.call is not a function
at map (eval at map (:10:9), <anonymous>:10:32)
at eval (eval at map (:10:9), <anonymous>:15:11)
at map (<anonymous>:10:9)
at <anonymous>:1:1
I wonder what is a real reason behind this. callback.call
for sure is a function. Is there any way to handle such a case? How can I check if provided arguments will give me an error like this?
It was when I provide context:
map(Array.apply(null, { length: 2 }), Number.call, Number)
// is callback.call a function? yes it is!
// [0, 1]
CodePen (is missing an error in console, I recommend using browser to reproduce)
EDIT: Just to clarify the context is not required at all:
map([1, 2], function(i) {
return i + 5;
});
// is callback.call a function? yes it is!
// [6, 7]
EDIT#2 I can see how the other questions relate to mine. And they explained the reason behind this, also on Firefox there is quite good error message for this:
TypeError: Function.prototype.call called on incompatible undefined
So my final question is:
Is there a way to detect this kind of "incompatibility"?