6

Consider this JavaScript code:

var x = new date()

// "ReferenceError: date is not defined" - useful error, hints at a typo ('D'ate)

var x = new MyClass.foo()

// "TypeError: undefined is not a function" - bad error, no hint it might be 'F'oo

The error itself is correct, because MyClass doesn't have a foo method, so MyClass.foo does indeed return undefined, and new doesn't like that. The problem is this doesn't hint at all that the user might have misspelled the method name. Real-life example:

new Meteor.collection('foo')  // instead of:
new Meteor.Collection('foo')  // c and C look alike with many fonts at small size

Is there a portable way to detect that an object doesn't have a method before new gets undefined passed to it, automatically? __noSuchMethod__ is exactly what I'm looking for, but it looks like it's a non-standard extension. Looks like IE doesn't support it and V8 refused to implement it. The Chromium team also doesn't care much about implementing Proxy support.

Looks like there is some support for Proxy for Node (see this and this) and in the form of a shim ("a polyfill for the upcoming ECMAScript Reflect API" but see mpm's comments below).

Related questions (what this one boils down to):

Community
  • 1
  • 1
Dan Dascalescu
  • 110,650
  • 40
  • 276
  • 363
  • At some point in the future you will be able to use [proxies](http://wiki.ecmascript.org/doku.php?id=harmony:proxies) [for that](http://wiki.ecmascript.org/doku.php?id=harmony:proxies#simulating_nosuchmethod_doesnotunderstand). – Felix Kling Feb 22 '14 at 11:38
  • the shim doesnt emulate Proxie, it is impossible to emulate proxies, it emulates Reflect api , just to be clear and not give wrong ideas to people.You just cant shim proxies. – mpm Feb 22 '14 at 12:03
  • 3
    "Is there a portable way " Not in ES5 , not in V8 without harmony flags(to enable proxies). The answer is NO unless you enable an experimental feature. – mpm Feb 22 '14 at 12:06
  • @mpm: I'm not an expert on the topic, but [the shim's README](https://github.com/tvcutsem/harmony-reflect) says "The Proxy object is also updated to follow the latest [direct proxies](http://wiki.ecmascript.org/doku.php?id=harmony:direct_proxies) [spec](http://people.mozilla.org/~jorendorff/es6-draft.html#sec-proxy-factory-function)." – Dan Dascalescu Feb 22 '14 at 12:09
  • 1
    The proxy object doesnt exist in ES5. You can have proxies already in Chrome by enabling them,but it's an experimental feature. You dont need a shim for that.They are supported without flags in Firefox, but you cant shim proxies that's impossible. The README says "updated" not created adhoc from nothing. It's important for people who read your question that they are not misled into thinking that a lib can give them proxies. That's not true nor possible. – mpm Feb 22 '14 at 12:13
  • are you open to using something like [sweetjs](http://sweetjs.org/) to expand the syntax of javascript to include the functionality you want? – J. Holmes Feb 22 '14 at 19:27
  • @32bitkid: I'd be open to it. Doubt the Meteor team would though - that's [my main impetus for researching this topic](https://github.com/meteor/meteor/issues/1804#issuecomment-35351707). – Dan Dascalescu Feb 22 '14 at 21:13
  • Maybe somebody smarter than I can figure out how to do it in vanilla JS, I was thinking something along the lines of a sweetjs macro that overrode `new` to unroll to something like `(tmp=((tmp=((tmp=Foo)?tmp:_t("Foo")).Bar)?tmp:_t("Bar")).Baz?tmp:+_t("Baz"))` where `_t` is a `throw(name + " does not exist")`. – J. Holmes Feb 22 '14 at 22:09
  • "To me, what you're essentially asking is "How do I avoid debugging my/my team's code?" There are four ways to avoid this: 1. Don't make mistakes. 2. Go through your code with a fine tooth-comb and pull your hair out while swearing. 3. Increase your font size and/or use a monospace font. 4. Be Jon Skeet. Generally, #2 and three work for me. – Agi Hammerthief Mar 06 '14 at 15:15
  • 1
    The error would have been thrown with or without the new operator. Applying an invocation to not-a-function is the cause. The new operator simply creates a new empty object, binds the this keyword of the function instance to the new object, and sets the prototype of the object to the prototype stored in the function. If you get this error it is not even sure that you messed up variable or property naming, but it's most likely; Something might have gone wrong with the initialization. JSHint can help you figure out what went wrong too, imho you're solving a problem that doesn't need solving. – dot slash hack Mar 10 '14 at 23:09

1 Answers1

3

More than a year after this question, V8 probably changed the error messages

var MyClass = function() {
  this.Foo = function() { console.log("Foo"); }
}

new MyClass().foo();

Produces this error today

Uncaught TypeError: (intermediate value).foo is not a function

Used with named object

var mc = new MyClass();
mc.foo();

It is even more useful

Uncaught TypeError: mc.foo is not a function

Used with typo in object name is usefull, too:

new myClass().foo();

Uncaught ReferenceError: myClass is not defined

Jan Turoň
  • 26,696
  • 21
  • 102
  • 153