Bug Tracker

Opened 7 years ago

Closed 7 years ago

Last modified 7 years ago

#11949 closed bug (wontfix)

Cannot bind to 'watch' event in Firefox

Reported by: rkattouw@… Owned by: rkattouw@…
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 foowatch? 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 eventswatch?, 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

Change History (17)

comment:1 Changed 7 years ago by dmethvin

Owner: set to rkattouw@…
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.

comment:2 Changed 7 years ago by Rick Waldron

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.

comment:3 in reply to:  1 Changed 7 years ago by rkattouw@…

Replying to 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.

comment:4 Changed 7 years ago by 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).

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

comment:5 in reply to:  2 ; Changed 7 years ago by Catrope

Replying to 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.

comment:6 Changed 7 years ago by Krinkle

http://jsfiddle.net/qk99m/

(see console for exception(s))

comment:7 in reply to:  4 ; Changed 7 years ago by Rick Waldron

Replying to 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)

comment:8 in reply to:  5 ; Changed 7 years ago by Rick Waldron

Replying to Catrope:

Replying to 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.

comment:9 in reply to:  8 Changed 7 years ago by Catrope

Replying to 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?

comment:10 in reply to:  7 Changed 7 years ago by Catrope

Replying to 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.

comment:11 Changed 7 years ago by dmethvin

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.

comment:12 Changed 7 years ago by Krinkle

(concurrency conflict)

Replying to rwaldron:

Replying to 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 () {});

comment:13 Changed 7 years ago by Rick Waldron

@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.

comment:14 in reply to:  13 Changed 7 years ago by Catrope

Replying to 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?

comment:15 Changed 7 years ago by 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/

comment:16 in reply to:  15 Changed 7 years ago by Catrope

Replying to 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).

Note: See TracTickets for help on using tickets.