SteveSanderson / knockout-es5

Knockout.js meets ECMAScript 5 properties
158 stars 39 forks source link

Uncaught TypeError: Function.prototype.toString is not generic for inspecting variables #61

Open jmvtrinidad opened 7 years ago

jmvtrinidad commented 7 years ago

Hi, Whenever I inspect computedVariables error shows Uncaught TypeError: Function.prototype.toString is not generic. Any Idea @ntrrgc. ko-es5-error

From the meantime, I inserted this code as checking.

var isToStringAllowed = true;
try{
    coercedObj.toString()
} catch(e) {
    isToStringAllowed = false
}
if (isToStringAllowed && coercedObj !== Window.prototype && 'toString' in coercedObj
  && coercedObj.toString() === '[object Window]') {
...
ntrrgc commented 7 years ago

First, I want to explain why such an error would be thrown. Basic JavaScript data types all have a method named toString(). It's important to note that each method pertains to one class (Function, String, Number or Object) and only handles their kind.

So this works:

> Function.prototype.toString.call(function myFunction() {})
"function myFunction() {}"

But this doesn't:

> Function.prototype.toString.call({})
Uncaught TypeError: Function.prototype.toString is not generic(…)

How could this happen when not forcing it with call, like in the code above? (thing.toString()) Well, through somewhat strange inheritance or method assignment:

> var a = {};
> a.toString = Function.prototype.toString;
> a.toString()
Uncaught TypeError: Function.prototype.toString is not generic(…)

You may want to check why you have objects with a broken toString() method.

In any case, we'd rather not have the debugger break on any object no matter how broken its toString() method is, so running it inside a try/catch is indeed a good idea.

Instead of calling toString() twice, with only the first call guarded, I suggest replacing it by a safe function that cannot fail:

function safeToString(thing) {
    try {
        return thing.toString();
    } catch (e) {
        return "[toString failed]";
    }
}
...

if (coercedObj !== Window.prototype && "toString" in coercedObj
  && safeToString(coercedObj) == "[object Window]") { ...
jmvtrinidad commented 7 years ago

Thanks for the good catch there.