Skip to main content

Bug Tracker

Side navigation

#11949 closed bug (wontfix)

Opened June 21, 2012 06:04PM UTC

Closed June 21, 2012 07:55PM UTC

Last modified August 03, 2012 12:59AM UTC

Cannot bind to 'watch' event in Firefox

Reported by: rkattouw@wikimedia.org Owned by: rkattouw@wikimedia.org
Priority: undecided Milestone: None
Component: unfiled Version: 1.7.2
Keywords: Cc:
Blocked by: Blocking:
Description

Firefox has this annoying behavior where Object.prototype.watch is a native function, so if you create an empty object with var foo = {}; then foo['watch'] will be a function rather than undefined, but foo.hasOwnProperty( 'watch' ) will be false.

This means that if you bind to a custom event called 'watch', jQuery.event.add looks for events['watch'], finds it, assumes it's an array, and calls .push() on it, which causes a JS error.

jsFiddle: http://jsfiddle.net/aAjqy/

Behavior in Chrome: "I've been watched" appears every second

Behavior in Firefox: JS error on line 3008 of jquery.js, handlers.push is not a function

Attachments (0)
Change History (17)

Changed June 21, 2012 07:10PM UTC by dmethvin comment:1

owner: → rkattouw@wikimedia.org
status: newpending

Can you provide a test case? I don't see the problem in the console. And if Firefox is doing this, your first stop should be Bugzilla not here.

Changed June 21, 2012 07:55PM UTC by rwaldron comment:2

resolution: → wontfix
status: pendingclosed

This is definitely not a jQuery bug. Mozilla and Firefox devs have known about this for sometime - if they're not acting on it, then it's their fault for adding non-standard behaviours to Object.prototype.

The fix: use a different word.

Changed August 02, 2012 10:03PM UTC by rkattouw@wikimedia.org comment:3

Replying to [comment:1 dmethvin]:

Can you provide a test case? I don't see the problem in the console. And if Firefox is doing this, your first stop should be Bugzilla not here.

I provided a test case, there's a jsfiddle link right there in the bug report.

Changed August 02, 2012 10:11PM UTC by Krinkle comment:4

Refined: http://jsfiddle.net/MTFeW/

Please reopen.

I know we don't support extending of object prototype, but in this case it is a native extension (just like Object.prototype.hasOwnProperty, toString or any other *native* (even standardized) protoypes).

The uncaught exception is thrown from the .on() call (TypeError on handlers.push)

Changed August 02, 2012 10:12PM UTC by Catrope comment:5

Replying to [comment:2 rwaldron]:

This is definitely not a jQuery bug. Mozilla and Firefox devs have known about this for sometime - if they're not acting on it, then it's their fault for adding non-standard behaviours to Object.prototype.

Yes, this Firefox behavior is totally crazy and should be fixed in the browser. However, other things that are legitimately in Object.prototype also don't work. The very same bug occurs for events called 'hasOwnProperty', 'constructor', 'toString', etc.; see also Krinkle's comment.

The fix: use a different word.

I'd argue that the fix is to use .hasOwnProperty() whenever using user input to index into an object. If it's possible to trigger a JS error in a library by feeding it certain strings (especially if those strings are in /[A-Za-z]+/), then that is a bug in the library.

Changed August 02, 2012 11:32PM UTC by Krinkle comment:6

http://jsfiddle.net/qk99m/

(see console for exception(s))

Changed August 02, 2012 11:52PM UTC by rwaldron comment:7

Replying to [comment:4 Krinkle]:

Refined: http://jsfiddle.net/MTFeW/ Please reopen. I know we don't support extending of object prototype, but in this case it is a native extension (just like Object.prototype.hasOwnProperty, toString or any other *native* (even standardized) protoypes).

It absolute is not like "Object.prototype.hasOwnProperty", "toString" or any other *native*. Those are all standard Object.prototype properties as defined in ES5.1. Object.prototype.watch is a non-standard property that was added by Mozilla a long time ago and they must live with the consequences of their actions.

The uncaught exception is thrown from the .on() call (TypeError on handlers.push)

Changed August 02, 2012 11:55PM UTC by rwaldron comment:8

Replying to [comment:5 Catrope]:

Replying to [comment:2 rwaldron]: > This is definitely not a jQuery bug. Mozilla and Firefox devs have known about this for sometime - if they're not acting on it, then it's their fault for adding non-standard behaviours to Object.prototype. > Yes, this Firefox behavior is totally crazy and should be fixed in the browser. However, other things that are legitimately in Object.prototype also don't work. The very same bug occurs for events called 'hasOwnProperty', 'constructor', 'toString', etc.; see also Krinkle's comment.

Krinkle is wrong and so are you for using his comment as a reference.

> The fix: use a different word. I'd argue that the fix is to use .hasOwnProperty() whenever using user input to index into an object. If it's possible to trigger a JS error in a library by feeding it certain strings (especially if those strings are in /[A-Za-z]+/), then that is a bug in the library.

You're asking jQuery to break backwards compatibility because you're trying to do something that we told you is incorrect and unsupported by the library.

This is not going to be re-opened.

Changed August 03, 2012 12:14AM UTC by Catrope comment:9

Replying to [comment:8 rwaldron]:

You're asking jQuery to break backwards compatibility because you're trying to do something that we told you is incorrect and unsupported by the library.

How would jQuery break backwards compatibility by making .on('toString') actually work rather than cause a JS error? That doesn't make sense to me, could you explain that further?

Changed August 03, 2012 12:16AM UTC by Catrope comment:10

Replying to [comment:7 rwaldron]:

It absolute is not like "Object.prototype.hasOwnProperty", "toString" or any other *native*. Those are all standard Object.prototype properties as defined in ES5.1. Object.prototype.watch is a non-standard property that was added by Mozilla a long time ago and they must live with the consequences of their actions.

Agreed, .watch is not like hasOwnProperty or toString, it's not standard. But forget about .watch. This same bug also occurs when doing stuff like $('.foo').on('toString') , and that's the case in every browser. So while I originally filed this as a Firefox-specific bug (and the title is still Firefox-specific, I don't seem to be able to edit the title unfortunately), it's actually not. Object.prototype.toString is present in all browsers, and consequently .on('toString') breaks in all browsers. I think that's a legitimate bug.

Changed August 03, 2012 12:18AM UTC by dmethvin comment:11

jQuery allows events to be triggered on JavaScript objects. If there is a method with the same name as the event, it is called. The method could be directly on the object, or in the prototype chain.

Changed August 03, 2012 12:21AM UTC by Krinkle comment:12

(concurrency conflict)

Replying to [comment:7 rwaldron]:

Replying to [comment:4 Krinkle]: > Refined: http://jsfiddle.net/MTFeW/ > > Please reopen. > > I know we don't support extending of object prototype, but in this case it is a native extension (just like Object.prototype.hasOwnProperty, toString or any other *native* (even standardized) protoypes). It absolute is not like "Object.prototype.hasOwnProperty", "toString" or any other *native*. Those are all standard Object.prototype properties as defined in ES5.1. Object.prototype.watch is a non-standard property that was added by Mozilla a long time ago and they must live with the consequences of their actions. > > The uncaught exception is thrown from the .on() call (TypeError on handlers.push)

I couldn't care less about Mozilla's "watch" property. There are two important factors here that you appear to be missing:

1) Isn't jQuery's primary objective to take care of cross-browser differences and quirks. Are we saying "screw you for using IE8, Firefox 3, Opera 11, we don't support non-standard behavior in browsers". There are LOTS of things in jQuery for supporting cross-browser differences (hey, all properties in jQuery.support.* ?).

2) This bug title may be phrased bad, but the fact is that this bug is *not* limited to Mozilla's non-standard "watch" Object.prototype. The bug is that *ANY* inherited property (including all the lovely ES 5.1 standard prototypes like "toString" and "constructor") break jQuery's .on() method when passed as the event name:

This throws an exception:

jQuery("<div>").on("constructor.myNamespace", function () {});

Changed August 03, 2012 12:29AM UTC by rwaldron comment:13

@Catrope

Throwing an exception would not break BC, attempting to filter properties with hasOwnProperty would break BC.

@Krinkle I'm not missing anything.

1) Isn't jQuery's primary objective to take care of cross-browser differences and quirks. Are we saying "screw you for using IE8, Firefox 3, Opera 11, we don't support non-standard behavior in browsers".

Don't confuse "the DOM" with "JavaScript". jQuery does nothing to the native environment (standard or not).

There are LOTS of things in jQuery for supporting cross-browser differences (hey, all properties in jQuery.support.* ?).

Again, the DOM.

2) This bug title may be phrased bad, but the fact is that this bug is *not* limited to Mozilla's non-standard "watch" Object.prototype. The bug is that *ANY* inherited property (including all the lovely ES 5.1 standard prototypes like "toString" and "constructor") break jQuery's .on() method when passed as the event name:

"toString" and "constructor" existed long before 5.1 and if this ticket said "toString" instead of "watch", it would be closed for the same reason.

Changed August 03, 2012 12:34AM UTC by Catrope comment:14

Replying to [comment:13 rwaldron]:

@Catrope Throwing an exception would not break BC, attempting to filter properties with hasOwnProperty would break BC.

How would it break BC (other than making something that used to be broken work, but by that definition every bug fix breaks BC ^^)? This is not clear to me, could you explain?

Changed August 03, 2012 12:35AM UTC by dmethvin comment:15

When an event is triggered, a method with the same name as the event name is called. It works that way for both JavaScript objects and for DOM objects.

http://jsfiddle.net/h5HnZ/

To trigger handlers bound via jQuery without also triggering the native event, use .triggerHandler() instead. -- http://api.jquery.com/trigger/

Changed August 03, 2012 12:37AM UTC by Catrope comment:16

Replying to [comment:15 dmethvin]:

When an event is triggered, a method with the same name as the event name is called. It works that way for both JavaScript objects and for DOM objects. http://jsfiddle.net/h5HnZ/ > To trigger handlers bound via jQuery without also triggering the native event, use .triggerHandler() instead. -- http://api.jquery.com/trigger/

Yes, but neither of these things is at issue here. I'm not trying to use events with JS objects, I'm trying to use them with DOM elements. And yes, when triggering events that have the same name as a method, the method is called. But this bug is about an error that's thrown when registering a handler for the event, not when triggering the event. My code isn't triggering any events because the JS error from .on() causes it to die before it even reaches .trigger() (or triggerHandler as appropriate).

Changed August 03, 2012 12:59AM UTC by Catrope comment:17