Skip to content
Browse files

Callbacks.add now accepts array-like objects (like Arguments). Now us…

…es the slice method of the args array in fireWith rather than a quite slow jQuery.merge.
  • Loading branch information...
1 parent 8cc217e commit 87c83b04589e91a96adcfce788c6207295f83a5b @jaubourg jaubourg committed Apr 25, 2012
Showing with 6 additions and 6 deletions.
  1. +6 −6 src/callbacks.js
View
12 src/callbacks.js
@@ -94,12 +94,11 @@ jQuery.Callbacks = function( options ) {
var start = list.length;
(function add( args ) {
jQuery.each( args, function( _, arg ) {
- var type;
- if ( ( type = jQuery.type(arg) ) === "array" ) {
+ if ( jQuery.isFunction( arg ) && ( !options.unique || !self.has( arg ) ) ) {
+ list.push( arg );
+ } else if ( arg && arg.length ) {
// Inspect recursively
@krisselden
krisselden added a note Oct 6, 2012

This treats every Function as an array like object (and String too but that was fixed later) and loops through prototype, so if something like say Modernizr pollyfills bind, it will add bind to the callbacks.

@jaubourg
jQuery Foundation member
jaubourg added a note Oct 6, 2012

Except no function is ever passed to this test. Just look at #97.

Also, jQuery doesn't support Object.prototype extensions.

@krisselden
krisselden added a note Oct 6, 2012

That is simply not true ( !options.unique || !self.has( arg ) ) can fall through to else if with a function: http://jsfiddle.net/krisselden/JFSNW/

Modernizr bind is a Function.prototype extension not an Object.prototype extension and it doesn't require it being on the prototype to make it fail (see above fiddle).

The intention of the unique check I'm sure is just to prevent list.push( arg ); not to recursively add, the meaning was changed when the condition was reordered.

@jaubourg
jQuery Foundation member
jaubourg added a note Oct 6, 2012

Very nice catch! Could you open a ticket for that in the bug tracker so that we can tackle this properly (easy given you gave us the unit test \o/).

@jaubourg
jQuery Foundation member
jaubourg added a note Oct 6, 2012

Nevermind, I did it already: http://bugs.jquery.com/ticket/12665

@jaubourg
jQuery Foundation member
jaubourg added a note Oct 6, 2012
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
add( arg );
- } else if ( type === "function" && ( !options.unique || !self.has( arg ) ) ) {
- list.push( arg );
}
});
})( arguments );
@@ -121,7 +120,7 @@ jQuery.Callbacks = function( options ) {
remove: function() {
if ( list ) {
jQuery.each( arguments, function( _, arg ) {
- var index = 0;
+ var index;
while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
list.splice( index, 1 );
// Handle firing indexes
@@ -170,7 +169,8 @@ jQuery.Callbacks = function( options ) {
},
// Call all callbacks with the given context and arguments
fireWith: function( context, args ) {
- args = [ context, jQuery.merge( [], args || [] ) ];
+ args = args || [];
+ args = [ context, args.slice ? args.slice() : args ];
@gibson042
jQuery Foundation member
gibson042 added a note Apr 26, 2012

This seems a little fishy. Function.apply accepts undefined etc., so why manipulate args at all?

@jaubourg
jQuery Foundation member
jaubourg added a note Apr 26, 2012
@gibson042
jQuery Foundation member
gibson042 added a note Apr 26, 2012

Hahahaha. I just knew I was putting my foot in my mouth. But still, why the slice?

@jaubourg
jQuery Foundation member
jaubourg added a note Apr 26, 2012

Because without it, we have this:

var cb = $.Callbacks( "memory" ),
    myArray = [ "yes" ];

cb.fireWith( null, myArray );
myArray[ 0 ] = "err... no";
cb.add(function( value ) {
    console.log( value ); // outputs "err... no"
});

I removed don't protect for Arguments objects, because, quite franckly, the following deserves to fail:

(function() {
    var cb = $.Callbacks( "memory" ),
        myArray = arguments;

    cb.fireWith( null, myArray );
    myArray[ 0 ] = "err... no";
    cb.add(function( value ) {
        console.log( value ); // outputs "err... no"
    });
}

But maybe I should add it back once @rwaldron deals with these common decls (so that I don't have to declare yet another slice)

@staabm
staabm added a note Apr 26, 2012

@rwldrn

@jaubourg
jQuery Foundation member
jaubourg added a note Apr 26, 2012

Damn him and his silly username! ;)

@gibson042
jQuery Foundation member
gibson042 added a note Apr 26, 2012

You're good. That addresses both my primary question and my now unnecessary follow-up, but I'm not convinced that we should treat arrays and arguments differently. I'm with you on the common declarations; stack.push( slice.call( args || [] ) ) is definitely where we want to go in the long run (and that is acceptable because IE throws an exception on anything that isn't array/arguments... so give us a length and we'll take a list 😉).

@rwaldron
jQuery Foundation member
rwaldron added a note Apr 26, 2012

Yeah, sorry about the username non-sense. I registered as "rwldrn" a long time ago. I also have "rwaldron" but that doesn't have any of my project stuff :\

@jaubourg
jQuery Foundation member
jaubourg added a note Apr 26, 2012

@rwldrn yeah, I find you a little short on this one... Bwahahahahaha! ;P

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
if ( list && ( !fired || stack ) ) {
if ( firing ) {
stack.push( args );

0 comments on commit 87c83b0

Please sign in to comment.
Something went wrong with that request. Please try again.