From 3d732cca6b5076a9d13eee98e2b075b37384cd91 Mon Sep 17 00:00:00 2001 From: Jason Bedard Date: Tue, 12 Dec 2017 22:43:30 -0800 Subject: [PATCH] Core: deprecate jQuery.isFunction Fixes gh-3609 --- src/ajax.js | 7 +- src/ajax/jsonp.js | 7 +- src/ajax/load.js | 5 +- src/attributes/classes.js | 9 +- src/attributes/val.js | 9 +- src/callbacks.js | 5 +- src/core.js | 16 +--- src/core/access.js | 7 +- src/core/init.js | 7 +- src/core/ready-no-deferred.js | 7 +- src/deferred.js | 21 ++--- src/deprecated.js | 6 +- src/effects.js | 17 ++-- src/event.js | 6 +- src/event/trigger.js | 5 +- src/manipulation.js | 9 +- src/offset.js | 5 +- src/serialize.js | 5 +- src/traversing/findFilter.js | 5 +- src/var/isFunction.js | 13 +++ src/wrap.js | 11 +-- test/data/testinit.js | 4 +- test/unit/basic.js | 5 +- test/unit/core.js | 147 -------------------------------- test/unit/deferred.js | 6 +- test/unit/deprecated.js | 155 ++++++++++++++++++++++++++++++++++ test/unit/effects.js | 2 +- test/unit/manipulation.js | 2 +- test/unit/queue.js | 2 +- 29 files changed, 268 insertions(+), 237 deletions(-) create mode 100644 src/var/isFunction.js diff --git a/src/ajax.js b/src/ajax.js index 27e533955..dd1321240 100644 --- a/src/ajax.js +++ b/src/ajax.js @@ -1,6 +1,7 @@ define( [ "./core", "./var/document", + "./var/isFunction", "./var/rnothtmlwhite", "./ajax/var/location", "./ajax/var/nonce", @@ -11,7 +12,7 @@ define( [ "./event/trigger", "./deferred", "./serialize" // jQuery.param -], function( jQuery, document, rnothtmlwhite, location, nonce, rquery ) { +], function( jQuery, document, isFunction, rnothtmlwhite, location, nonce, rquery ) { "use strict"; @@ -66,7 +67,7 @@ function addToPrefiltersOrTransports( structure ) { i = 0, dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; - if ( jQuery.isFunction( func ) ) { + if ( isFunction( func ) ) { // For each dataType in the dataTypeExpression while ( ( dataType = dataTypes[ i++ ] ) ) { @@ -834,7 +835,7 @@ jQuery.each( [ "get", "post" ], function( i, method ) { jQuery[ method ] = function( url, data, callback, type ) { // Shift arguments if data argument was omitted - if ( jQuery.isFunction( data ) ) { + if ( isFunction( data ) ) { type = type || callback; callback = data; data = undefined; diff --git a/src/ajax/jsonp.js b/src/ajax/jsonp.js index 8c406e722..28ae0365d 100644 --- a/src/ajax/jsonp.js +++ b/src/ajax/jsonp.js @@ -1,9 +1,10 @@ define( [ "../core", + "../var/isFunction", "./var/nonce", "./var/rquery", "../ajax" -], function( jQuery, nonce, rquery ) { +], function( jQuery, isFunction, nonce, rquery ) { "use strict"; @@ -36,7 +37,7 @@ jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) { // Get callback name, remembering preexisting value associated with it - callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ? + callbackName = s.jsonpCallback = isFunction( s.jsonpCallback ) ? s.jsonpCallback() : s.jsonpCallback; @@ -87,7 +88,7 @@ jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { } // Call if it was a function and we have a response - if ( responseContainer && jQuery.isFunction( overwritten ) ) { + if ( responseContainer && isFunction( overwritten ) ) { overwritten( responseContainer[ 0 ] ); } diff --git a/src/ajax/load.js b/src/ajax/load.js index 3ce3a5aae..defdb0174 100644 --- a/src/ajax/load.js +++ b/src/ajax/load.js @@ -1,12 +1,13 @@ define( [ "../core", "../core/stripAndCollapse", + "../var/isFunction", "../core/parseHTML", "../ajax", "../traversing", "../manipulation", "../selector" -], function( jQuery, stripAndCollapse ) { +], function( jQuery, stripAndCollapse, isFunction ) { "use strict"; @@ -24,7 +25,7 @@ jQuery.fn.load = function( url, params, callback ) { } // If it's a function - if ( jQuery.isFunction( params ) ) { + if ( isFunction( params ) ) { // We assume that it's the callback callback = params; diff --git a/src/attributes/classes.js b/src/attributes/classes.js index 1c75821b2..0c90a8dff 100644 --- a/src/attributes/classes.js +++ b/src/attributes/classes.js @@ -1,10 +1,11 @@ define( [ "../core", "../core/stripAndCollapse", + "../var/isFunction", "../var/rnothtmlwhite", "../data/var/dataPriv", "../core/init" -], function( jQuery, stripAndCollapse, rnothtmlwhite, dataPriv ) { +], function( jQuery, stripAndCollapse, isFunction, rnothtmlwhite, dataPriv ) { "use strict"; @@ -27,7 +28,7 @@ jQuery.fn.extend( { var classes, elem, cur, curValue, clazz, j, finalValue, i = 0; - if ( jQuery.isFunction( value ) ) { + if ( isFunction( value ) ) { return this.each( function( j ) { jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); } ); @@ -64,7 +65,7 @@ jQuery.fn.extend( { var classes, elem, cur, curValue, clazz, j, finalValue, i = 0; - if ( jQuery.isFunction( value ) ) { + if ( isFunction( value ) ) { return this.each( function( j ) { jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); } ); @@ -113,7 +114,7 @@ jQuery.fn.extend( { return stateVal ? this.addClass( value ) : this.removeClass( value ); } - if ( jQuery.isFunction( value ) ) { + if ( isFunction( value ) ) { return this.each( function( i ) { jQuery( this ).toggleClass( value.call( this, i, getClass( this ), stateVal ), diff --git a/src/attributes/val.js b/src/attributes/val.js index d764ec6d1..c719b34b3 100644 --- a/src/attributes/val.js +++ b/src/attributes/val.js @@ -3,9 +3,10 @@ define( [ "../core/stripAndCollapse", "./support", "../core/nodeName", + "../var/isFunction", "../core/init" -], function( jQuery, stripAndCollapse, support, nodeName ) { +], function( jQuery, stripAndCollapse, support, nodeName, isFunction ) { "use strict"; @@ -13,7 +14,7 @@ var rreturn = /\r/g; jQuery.fn.extend( { val: function( value ) { - var hooks, ret, isFunction, + var hooks, ret, valueIsFunction, elem = this[ 0 ]; if ( !arguments.length ) { @@ -42,7 +43,7 @@ jQuery.fn.extend( { return; } - isFunction = jQuery.isFunction( value ); + valueIsFunction = isFunction( value ); return this.each( function( i ) { var val; @@ -51,7 +52,7 @@ jQuery.fn.extend( { return; } - if ( isFunction ) { + if ( valueIsFunction ) { val = value.call( this, i, jQuery( this ).val() ); } else { val = value; diff --git a/src/callbacks.js b/src/callbacks.js index 8831e531a..78e9b4fd0 100644 --- a/src/callbacks.js +++ b/src/callbacks.js @@ -1,7 +1,8 @@ define( [ "./core", + "./var/isFunction", "./var/rnothtmlwhite" -], function( jQuery, rnothtmlwhite ) { +], function( jQuery, isFunction, rnothtmlwhite ) { "use strict"; @@ -125,7 +126,7 @@ jQuery.Callbacks = function( options ) { ( function add( args ) { jQuery.each( args, function( _, arg ) { - if ( jQuery.isFunction( arg ) ) { + if ( isFunction( arg ) ) { if ( !options.unique || !self.has( arg ) ) { list.push( arg ); } diff --git a/src/core.js b/src/core.js index 037e31740..5916b03aa 100644 --- a/src/core.js +++ b/src/core.js @@ -16,11 +16,12 @@ define( [ "./var/fnToString", "./var/ObjectFunctionString", "./var/support", + "./var/isFunction", "./var/isWindow", "./core/DOMEval" ], function( arr, document, getProto, slice, concat, push, indexOf, class2type, toString, hasOwn, fnToString, ObjectFunctionString, - support, isWindow, DOMEval ) { + support, isFunction, isWindow, DOMEval ) { "use strict"; @@ -137,7 +138,7 @@ jQuery.extend = jQuery.fn.extend = function() { } // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !jQuery.isFunction( target ) ) { + if ( typeof target !== "object" && !isFunction( target ) ) { target = {}; } @@ -203,15 +204,6 @@ jQuery.extend( { noop: function() {}, - isFunction: function( obj ) { - - // Support: Chrome <=57, Firefox <=52 - // In some browsers, typeof returns "function" for HTML elements - // (i.e., `typeof document.createElement( "object" ) === "function"`). - // We don't want to classify *any* DOM node as a function. - return typeof obj === "function" && typeof obj.nodeType !== "number"; - }, - isNumeric: function( obj ) { // As of jQuery 3.0, isNumeric is limited to @@ -419,7 +411,7 @@ function isArrayLike( obj ) { var length = !!obj && "length" in obj && obj.length, type = jQuery.type( obj ); - if ( jQuery.isFunction( obj ) || isWindow( obj ) ) { + if ( isFunction( obj ) || isWindow( obj ) ) { return false; } diff --git a/src/core/access.js b/src/core/access.js index 86cdbc7e6..2e1eb4121 100644 --- a/src/core/access.js +++ b/src/core/access.js @@ -1,6 +1,7 @@ define( [ - "../core" -], function( jQuery ) { + "../core", + "../var/isFunction" +], function( jQuery, isFunction ) { "use strict"; @@ -22,7 +23,7 @@ var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { } else if ( value !== undefined ) { chainable = true; - if ( !jQuery.isFunction( value ) ) { + if ( !isFunction( value ) ) { raw = true; } diff --git a/src/core/init.js b/src/core/init.js index 8841264de..8865238c8 100644 --- a/src/core/init.js +++ b/src/core/init.js @@ -2,10 +2,11 @@ define( [ "../core", "../var/document", + "../var/isFunction", "./var/rsingleTag", "../traversing/findFilter" -], function( jQuery, document, rsingleTag ) { +], function( jQuery, document, isFunction, rsingleTag ) { "use strict"; @@ -63,7 +64,7 @@ var rootjQuery, for ( match in context ) { // Properties of context are called as methods if possible - if ( jQuery.isFunction( this[ match ] ) ) { + if ( isFunction( this[ match ] ) ) { this[ match ]( context[ match ] ); // ...and otherwise set as attributes @@ -106,7 +107,7 @@ var rootjQuery, // HANDLE: $(function) // Shortcut for document ready - } else if ( jQuery.isFunction( selector ) ) { + } else if ( isFunction( selector ) ) { return root.ready !== undefined ? root.ready( selector ) : diff --git a/src/core/ready-no-deferred.js b/src/core/ready-no-deferred.js index a7722ae9a..4428020ef 100644 --- a/src/core/ready-no-deferred.js +++ b/src/core/ready-no-deferred.js @@ -1,7 +1,8 @@ define( [ "../core", - "../var/document" -], function( jQuery, document ) { + "../var/document", + "../var/isFunction" +], function( jQuery, document, isFunction ) { "use strict"; @@ -52,7 +53,7 @@ jQuery.extend( { while ( readyCallbacks.length ) { fn = readyCallbacks.shift(); - if ( jQuery.isFunction( fn ) ) { + if ( isFunction( fn ) ) { executeReady( fn ); } } diff --git a/src/deferred.js b/src/deferred.js index a627f5ed6..0425d3631 100644 --- a/src/deferred.js +++ b/src/deferred.js @@ -1,8 +1,9 @@ define( [ "./core", + "./var/isFunction", "./var/slice", "./callbacks" -], function( jQuery, slice ) { +], function( jQuery, isFunction, slice ) { "use strict"; @@ -19,11 +20,11 @@ function adoptValue( value, resolve, reject, noValue ) { try { // Check for promise aspect first to privilege synchronous behavior - if ( value && jQuery.isFunction( ( method = value.promise ) ) ) { + if ( value && isFunction( ( method = value.promise ) ) ) { method.call( value ).done( resolve ).fail( reject ); // Other thenables - } else if ( value && jQuery.isFunction( ( method = value.then ) ) ) { + } else if ( value && isFunction( ( method = value.then ) ) ) { method.call( value, resolve, reject ); // Other non-thenables @@ -81,14 +82,14 @@ jQuery.extend( { jQuery.each( tuples, function( i, tuple ) { // Map tuples (progress, done, fail) to arguments (done, fail, progress) - var fn = jQuery.isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; // deferred.progress(function() { bind to newDefer or newDefer.notify }) // deferred.done(function() { bind to newDefer or newDefer.resolve }) // deferred.fail(function() { bind to newDefer or newDefer.reject }) deferred[ tuple[ 1 ] ]( function() { var returned = fn && fn.apply( this, arguments ); - if ( returned && jQuery.isFunction( returned.promise ) ) { + if ( returned && isFunction( returned.promise ) ) { returned.promise() .progress( newDefer.notify ) .done( newDefer.resolve ) @@ -142,7 +143,7 @@ jQuery.extend( { returned.then; // Handle a returned thenable - if ( jQuery.isFunction( then ) ) { + if ( isFunction( then ) ) { // Special processors (notify) just wait for resolution if ( special ) { @@ -238,7 +239,7 @@ jQuery.extend( { resolve( 0, newDefer, - jQuery.isFunction( onProgress ) ? + isFunction( onProgress ) ? onProgress : Identity, newDefer.notifyWith @@ -250,7 +251,7 @@ jQuery.extend( { resolve( 0, newDefer, - jQuery.isFunction( onFulfilled ) ? + isFunction( onFulfilled ) ? onFulfilled : Identity ) @@ -261,7 +262,7 @@ jQuery.extend( { resolve( 0, newDefer, - jQuery.isFunction( onRejected ) ? + isFunction( onRejected ) ? onRejected : Thrower ) @@ -379,7 +380,7 @@ jQuery.extend( { // Use .then() to unwrap secondary thenables (cf. gh-3000) if ( master.state() === "pending" || - jQuery.isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { return master.then(); } diff --git a/src/deprecated.js b/src/deprecated.js index 8523ee5b8..82ef686e0 100644 --- a/src/deprecated.js +++ b/src/deprecated.js @@ -2,9 +2,10 @@ define( [ "./core", "./core/nodeName", "./core/camelCase", + "./var/isFunction", "./var/isWindow", "./var/slice" -], function( jQuery, nodeName, camelCase, isWindow, slice ) { +], function( jQuery, nodeName, camelCase, isFunction, isWindow, slice ) { "use strict"; @@ -44,7 +45,7 @@ jQuery.proxy = function( fn, context ) { // Quick check to determine if target is callable, in the spec // this throws a TypeError, but we will just return undefined. - if ( !jQuery.isFunction( fn ) ) { + if ( !isFunction( fn ) ) { return undefined; } @@ -70,6 +71,7 @@ jQuery.holdReady = function( hold ) { jQuery.isArray = Array.isArray; jQuery.parseJSON = JSON.parse; jQuery.nodeName = nodeName; +jQuery.isFunction = isFunction; jQuery.isWindow = isWindow; jQuery.camelCase = camelCase; diff --git a/src/effects.js b/src/effects.js index 514baaec8..a778de106 100644 --- a/src/effects.js +++ b/src/effects.js @@ -2,6 +2,7 @@ define( [ "./core", "./core/camelCase", "./var/document", + "./var/isFunction", "./var/rcssNum", "./var/rnothtmlwhite", "./css/var/cssExpand", @@ -18,8 +19,8 @@ define( [ "./manipulation", "./css", "./effects/Tween" -], function( jQuery, camelCase, document, rcssNum, rnothtmlwhite, cssExpand, isHiddenWithinTree, - swap, adjustCSS, dataPriv, showHide ) { +], function( jQuery, camelCase, document, isFunction, rcssNum, rnothtmlwhite, cssExpand, + isHiddenWithinTree, swap, adjustCSS, dataPriv, showHide ) { "use strict"; @@ -385,7 +386,7 @@ function Animation( elem, properties, options ) { for ( ; index < length; index++ ) { result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); if ( result ) { - if ( jQuery.isFunction( result.stop ) ) { + if ( isFunction( result.stop ) ) { jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = result.stop.bind( result ); } @@ -395,7 +396,7 @@ function Animation( elem, properties, options ) { jQuery.map( props, createTween, animation ); - if ( jQuery.isFunction( animation.opts.start ) ) { + if ( isFunction( animation.opts.start ) ) { animation.opts.start.call( elem, animation ); } @@ -428,7 +429,7 @@ jQuery.Animation = jQuery.extend( Animation, { }, tweener: function( props, callback ) { - if ( jQuery.isFunction( props ) ) { + if ( isFunction( props ) ) { callback = props; props = [ "*" ]; } else { @@ -460,9 +461,9 @@ jQuery.Animation = jQuery.extend( Animation, { jQuery.speed = function( speed, easing, fn ) { var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { complete: fn || !fn && easing || - jQuery.isFunction( speed ) && speed, + isFunction( speed ) && speed, duration: speed, - easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing + easing: fn && easing || easing && !isFunction( easing ) && easing }; // Go to the end state if fx are off @@ -489,7 +490,7 @@ jQuery.speed = function( speed, easing, fn ) { opt.old = opt.complete; opt.complete = function() { - if ( jQuery.isFunction( opt.old ) ) { + if ( isFunction( opt.old ) ) { opt.old.call( this ); } diff --git a/src/event.js b/src/event.js index b10c43f8d..aba26103d 100644 --- a/src/event.js +++ b/src/event.js @@ -2,6 +2,7 @@ define( [ "./core", "./var/document", "./var/documentElement", + "./var/isFunction", "./var/rnothtmlwhite", "./var/slice", "./data/var/dataPriv", @@ -9,7 +10,8 @@ define( [ "./core/init", "./selector" -], function( jQuery, document, documentElement, rnothtmlwhite, slice, dataPriv, nodeName ) { +], function( jQuery, document, isFunction, documentElement, rnothtmlwhite, + slice, dataPriv, nodeName ) { "use strict"; @@ -418,7 +420,7 @@ jQuery.event = { enumerable: true, configurable: true, - get: jQuery.isFunction( hook ) ? + get: isFunction( hook ) ? function() { if ( this.originalEvent ) { return hook( this.originalEvent ); diff --git a/src/event/trigger.js b/src/event/trigger.js index 1ecda7d68..cf40b4faa 100644 --- a/src/event/trigger.js +++ b/src/event/trigger.js @@ -4,9 +4,10 @@ define( [ "../data/var/dataPriv", "../data/var/acceptData", "../var/hasOwn", + "../var/isFunction", "../var/isWindow", "../event" -], function( jQuery, document, dataPriv, acceptData, hasOwn, isWindow ) { +], function( jQuery, document, dataPriv, acceptData, hasOwn, isFunction, isWindow ) { "use strict"; @@ -128,7 +129,7 @@ jQuery.extend( jQuery.event, { // Call a native DOM method on the target with the same name as the event. // Don't do default actions on window, that's where global variables be (#6170) - if ( ontype && jQuery.isFunction( elem[ type ] ) && !isWindow( elem ) ) { + if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { // Don't re-trigger an onFOO event when we call its FOO() method tmp = elem[ ontype ]; diff --git a/src/manipulation.js b/src/manipulation.js index 50ec9f1cb..ae713fe29 100644 --- a/src/manipulation.js +++ b/src/manipulation.js @@ -1,6 +1,7 @@ define( [ "./core", "./var/concat", + "./var/isFunction", "./var/push", "./core/access", "./manipulation/var/rcheckableType", @@ -22,7 +23,7 @@ define( [ "./traversing", "./selector", "./event" -], function( jQuery, concat, push, access, +], function( jQuery, concat, isFunction, push, access, rcheckableType, rtagName, rscriptType, wrapMap, getAll, setGlobalEval, buildFragment, support, dataPriv, dataUser, acceptData, DOMEval, nodeName ) { @@ -131,15 +132,15 @@ function domManip( collection, args, callback, ignored ) { l = collection.length, iNoClone = l - 1, value = args[ 0 ], - isFunction = jQuery.isFunction( value ); + valueIsFunction = isFunction( value ); // We can't cloneNode fragments that contain checked, in WebKit - if ( isFunction || + if ( valueIsFunction || ( l > 1 && typeof value === "string" && !support.checkClone && rchecked.test( value ) ) ) { return collection.each( function( index ) { var self = collection.eq( index ); - if ( isFunction ) { + if ( valueIsFunction ) { args[ 0 ] = value.call( this, index, self.html() ); } domManip( self, args, callback, ignored ); diff --git a/src/offset.js b/src/offset.js index 2ef0adb04..83b1c3a53 100644 --- a/src/offset.js +++ b/src/offset.js @@ -3,6 +3,7 @@ define( [ "./core/access", "./var/document", "./var/documentElement", + "./var/isFunction", "./css/var/rnumnonpx", "./css/curCSS", "./css/addGetHookIf", @@ -11,7 +12,7 @@ define( [ "./core/init", "./css", "./selector" // contains -], function( jQuery, access, document, documentElement, rnumnonpx, +], function( jQuery, access, document, documentElement, isFunction, rnumnonpx, curCSS, addGetHookIf, support, isWindow ) { "use strict"; @@ -46,7 +47,7 @@ jQuery.offset = { curLeft = parseFloat( curCSSLeft ) || 0; } - if ( jQuery.isFunction( options ) ) { + if ( isFunction( options ) ) { // Use jQuery.extend here to allow modification of coordinates argument (gh-1848) options = options.call( elem, i, jQuery.extend( {}, curOffset ) ); diff --git a/src/serialize.js b/src/serialize.js index 2e28ce1e0..635d5b646 100644 --- a/src/serialize.js +++ b/src/serialize.js @@ -1,10 +1,11 @@ define( [ "./core", "./manipulation/var/rcheckableType", + "./var/isFunction", "./core/init", "./traversing", // filter "./attributes/prop" -], function( jQuery, rcheckableType ) { +], function( jQuery, rcheckableType, isFunction ) { "use strict"; @@ -60,7 +61,7 @@ jQuery.param = function( a, traditional ) { add = function( key, valueOrFunction ) { // If value is a function, invoke it and use its return value - var value = jQuery.isFunction( valueOrFunction ) ? + var value = isFunction( valueOrFunction ) ? valueOrFunction() : valueOrFunction; diff --git a/src/traversing/findFilter.js b/src/traversing/findFilter.js index 3bd036a18..023a2cefb 100644 --- a/src/traversing/findFilter.js +++ b/src/traversing/findFilter.js @@ -1,9 +1,10 @@ define( [ "../core", "../var/indexOf", + "../var/isFunction", "./var/rneedsContext", "../selector" -], function( jQuery, indexOf, rneedsContext ) { +], function( jQuery, indexOf, isFunction, rneedsContext ) { "use strict"; @@ -11,7 +12,7 @@ var risSimple = /^.[^:#\[\.,]*$/; // Implement the identical functionality for filter and not function winnow( elements, qualifier, not ) { - if ( jQuery.isFunction( qualifier ) ) { + if ( isFunction( qualifier ) ) { return jQuery.grep( elements, function( elem, i ) { return !!qualifier.call( elem, i, elem ) !== not; } ); diff --git a/src/var/isFunction.js b/src/var/isFunction.js new file mode 100644 index 000000000..a05858284 --- /dev/null +++ b/src/var/isFunction.js @@ -0,0 +1,13 @@ +define( function() { + "use strict"; + + return function isFunction( obj ) { + + // Support: Chrome <=57, Firefox <=52 + // In some browsers, typeof returns "function" for HTML elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + return typeof obj === "function" && typeof obj.nodeType !== "number"; + }; + +} ); diff --git a/src/wrap.js b/src/wrap.js index 88b9bb56d..41b716f9f 100644 --- a/src/wrap.js +++ b/src/wrap.js @@ -1,9 +1,10 @@ define( [ "./core", + "./var/isFunction", "./core/init", "./manipulation", // clone "./traversing" // parent, contents -], function( jQuery ) { +], function( jQuery, isFunction ) { "use strict"; @@ -12,7 +13,7 @@ jQuery.fn.extend( { var wrap; if ( this[ 0 ] ) { - if ( jQuery.isFunction( html ) ) { + if ( isFunction( html ) ) { html = html.call( this[ 0 ] ); } @@ -38,7 +39,7 @@ jQuery.fn.extend( { }, wrapInner: function( html ) { - if ( jQuery.isFunction( html ) ) { + if ( isFunction( html ) ) { return this.each( function( i ) { jQuery( this ).wrapInner( html.call( this, i ) ); } ); @@ -58,10 +59,10 @@ jQuery.fn.extend( { }, wrap: function( html ) { - var isFunction = jQuery.isFunction( html ); + var htmlIsFunction = isFunction( html ); return this.each( function( i ) { - jQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html ); + jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); } ); }, diff --git a/test/data/testinit.js b/test/data/testinit.js index d6c0236e6..211824a89 100644 --- a/test/data/testinit.js +++ b/test/data/testinit.js @@ -171,7 +171,7 @@ this.ajaxTest = function( title, expect, options ) { QUnit.test( title, expect, function( assert ) { var requestOptions; - if ( jQuery.isFunction( options ) ) { + if ( typeof options === "function" ) { options = options( assert ); } options = options || []; @@ -208,7 +208,7 @@ this.ajaxTest = function( title, expect, options ) { if ( !completed ) { if ( !handler ) { assert.ok( false, "unexpected " + status ); - } else if ( jQuery.isFunction( handler ) ) { + } else if ( typeof handler === "function" ) { handler.apply( this, arguments ); } } diff --git a/test/unit/basic.js b/test/unit/basic.js index b46a04c28..29042caa5 100644 --- a/test/unit/basic.js +++ b/test/unit/basic.js @@ -76,7 +76,7 @@ QUnit.test( "show/hide", function( assert ) { } QUnit.test( "core", function( assert ) { - assert.expect( 25 ); + assert.expect( 23 ); var elem = jQuery( "
" ); @@ -90,9 +90,6 @@ QUnit.test( "core", function( assert ) { assert.ok( jQuery.isPlainObject( { "a": 2 } ), "jQuery.isPlainObject(object)" ); assert.ok( !jQuery.isPlainObject( "foo" ), "jQuery.isPlainObject(String)" ); - assert.ok( jQuery.isFunction( jQuery.noop ), "jQuery.isFunction(jQuery.noop)" ); - assert.ok( !jQuery.isFunction( 2 ), "jQuery.isFunction(Number)" ); - assert.ok( jQuery.isNumeric( "-2" ), "jQuery.isNumeric(String representing a number)" ); assert.ok( !jQuery.isNumeric( "" ), "jQuery.isNumeric(\"\")" ); diff --git a/test/unit/core.js b/test/unit/core.js index 7c7514ccc..fcff895b1 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -404,153 +404,6 @@ QUnit[ "assign" in Object ? "test" : "skip" ]( "isPlainObject(Object.assign(...) } ); - -QUnit.test( "isFunction", function( assert ) { - assert.expect( 20 ); - - var mystr, myarr, myfunction, fn, obj, nodes, first, input, a; - - // Make sure that false values return false - assert.ok( !jQuery.isFunction(), "No Value" ); - assert.ok( !jQuery.isFunction( null ), "null Value" ); - assert.ok( !jQuery.isFunction( undefined ), "undefined Value" ); - assert.ok( !jQuery.isFunction( "" ), "Empty String Value" ); - assert.ok( !jQuery.isFunction( 0 ), "0 Value" ); - - // Check built-ins - assert.ok( jQuery.isFunction( String ), "String Function(" + String + ")" ); - assert.ok( jQuery.isFunction( Array ), "Array Function(" + Array + ")" ); - assert.ok( jQuery.isFunction( Object ), "Object Function(" + Object + ")" ); - assert.ok( jQuery.isFunction( Function ), "Function Function(" + Function + ")" ); - - // When stringified, this could be misinterpreted - mystr = "function"; - assert.ok( !jQuery.isFunction( mystr ), "Function String" ); - - // When stringified, this could be misinterpreted - myarr = [ "function" ]; - assert.ok( !jQuery.isFunction( myarr ), "Function Array" ); - - // When stringified, this could be misinterpreted - myfunction = { "function": "test" }; - assert.ok( !jQuery.isFunction( myfunction ), "Function Object" ); - - // Make sure normal functions still work - fn = function() {}; - assert.ok( jQuery.isFunction( fn ), "Normal Function" ); - - assert.notOk( jQuery.isFunction( Object.create( fn ) ), "custom Function subclass" ); - - obj = document.createElement( "object" ); - - // Some versions of Firefox and Chrome say this is a function - assert.ok( !jQuery.isFunction( obj ), "Object Element" ); - - // Since 1.3, this isn't supported (#2968) - //ok( jQuery.isFunction(obj.getAttribute), "getAttribute Function" ); - - nodes = document.body.childNodes; - - // Safari says this is a function - assert.ok( !jQuery.isFunction( nodes ), "childNodes Property" ); - - first = document.body.firstChild; - - // Normal elements are reported ok everywhere - assert.ok( !jQuery.isFunction( first ), "A normal DOM Element" ); - - input = document.createElement( "input" ); - input.type = "text"; - document.body.appendChild( input ); - - // Since 1.3, this isn't supported (#2968) - //ok( jQuery.isFunction(input.focus), "A default function property" ); - - document.body.removeChild( input ); - - a = document.createElement( "a" ); - a.href = "some-function"; - document.body.appendChild( a ); - - // This serializes with the word 'function' in it - assert.ok( !jQuery.isFunction( a ), "Anchor Element" ); - - document.body.removeChild( a ); - - // Recursive function calls have lengths and array-like properties - function callme( callback ) { - function fn( response ) { - callback( response ); - } - - assert.ok( jQuery.isFunction( fn ), "Recursive Function Call" ); - - fn( { some: "data" } ); - } - - callme( function() { - callme( function() {} ); - } ); -} ); - -QUnit.test( "isFunction(cross-realm function)", function( assert ) { - assert.expect( 1 ); - - var iframe, doc, - done = assert.async(); - - // Functions from other windows should be matched - Globals.register( "iframeDone" ); - window.iframeDone = function( fn, detail ) { - window.iframeDone = undefined; - assert.ok( jQuery.isFunction( fn ), "cross-realm function" + - ( detail ? " - " + detail : "" ) ); - done(); - }; - - iframe = jQuery( "#qunit-fixture" )[ 0 ].appendChild( document.createElement( "iframe" ) ); - doc = iframe.contentDocument || iframe.contentWindow.document; - doc.open(); - doc.write( "" ); - doc.close(); -} ); - -supportjQuery.each( - { - GeneratorFunction: "function*() {}", - AsyncFunction: "async function() {}" - }, - function( subclass, source ) { - var fn; - try { - fn = Function( "return " + source )(); - } catch ( e ) {} - - QUnit[ fn ? "test" : "skip" ]( "isFunction(" + subclass + ")", - function( assert ) { - assert.expect( 1 ); - - assert.equal( jQuery.isFunction( fn ), true, source ); - } - ); - } -); - -QUnit[ typeof Symbol === "function" && Symbol.toStringTag ? "test" : "skip" ]( - "isFunction(custom @@toStringTag)", - function( assert ) { - assert.expect( 2 ); - - var obj = {}, - fn = function() {}; - obj[ Symbol.toStringTag ] = "Function"; - fn[ Symbol.toStringTag ] = "Object"; - - assert.equal( jQuery.isFunction( obj ), false, "function-mimicking object" ); - assert.equal( jQuery.isFunction( fn ), true, "object-mimicking function" ); - } -); - QUnit.test( "isNumeric", function( assert ) { assert.expect( 43 ); diff --git a/test/unit/deferred.js b/test/unit/deferred.js index f64d4fec8..9ba97181d 100644 --- a/test/unit/deferred.js +++ b/test/unit/deferred.js @@ -14,7 +14,7 @@ jQuery.each( [ "", " - new operator" ], function( _, withNew ) { var defer = createDeferred(); - assert.ok( jQuery.isFunction( defer.pipe ), "defer.pipe is a function" ); + assert.ok( typeof defer.pipe === "function", "defer.pipe is a function" ); defer.resolve().done( function() { assert.ok( true, "Success on resolve" ); @@ -49,7 +49,7 @@ jQuery.each( [ "", " - new operator" ], function( _, withNew ) { assert.strictEqual( defer.promise(), promise, "promise is always the same" ); assert.strictEqual( funcPromise, func, "non objects get extended" ); jQuery.each( promise, function( key ) { - if ( !jQuery.isFunction( promise[ key ] ) ) { + if ( typeof promise[ key ] !== "function" ) { assert.ok( false, key + " is a function (" + jQuery.type( promise[ key ] ) + ")" ); } if ( promise[ key ] !== func[ key ] ) { @@ -1097,7 +1097,7 @@ QUnit.test( "jQuery.when - always returns a new promise", function( assert ) { }, function( label, args ) { var result = jQuery.when.apply( jQuery, args ); - assert.ok( jQuery.isFunction( result.then ), "Thenable returned from " + label ); + assert.ok( typeof result.then === "function", "Thenable returned from " + label ); assert.strictEqual( result.resolve, undefined, "Non-deferred returned from " + label ); assert.strictEqual( result.promise(), result, "Promise returned from " + label ); diff --git a/test/unit/deprecated.js b/test/unit/deprecated.js index 9837b3bae..19810151f 100644 --- a/test/unit/deprecated.js +++ b/test/unit/deprecated.js @@ -165,6 +165,161 @@ QUnit.test( "jQuery.nodeName", function( assert ) { ); } ); + +QUnit.test( "core", function( assert ) { + assert.expect( 2 ); + + assert.ok( jQuery.isFunction( jQuery.noop ), "jQuery.isFunction(jQuery.noop)" ); + assert.ok( !jQuery.isFunction( 2 ), "jQuery.isFunction(Number)" ); +} ); + + +QUnit.test( "isFunction", function( assert ) { + assert.expect( 20 ); + + var mystr, myarr, myfunction, fn, obj, nodes, first, input, a; + + // Make sure that false values return false + assert.ok( !jQuery.isFunction(), "No Value" ); + assert.ok( !jQuery.isFunction( null ), "null Value" ); + assert.ok( !jQuery.isFunction( undefined ), "undefined Value" ); + assert.ok( !jQuery.isFunction( "" ), "Empty String Value" ); + assert.ok( !jQuery.isFunction( 0 ), "0 Value" ); + + // Check built-ins + assert.ok( jQuery.isFunction( String ), "String Function(" + String + ")" ); + assert.ok( jQuery.isFunction( Array ), "Array Function(" + Array + ")" ); + assert.ok( jQuery.isFunction( Object ), "Object Function(" + Object + ")" ); + assert.ok( jQuery.isFunction( Function ), "Function Function(" + Function + ")" ); + + // When stringified, this could be misinterpreted + mystr = "function"; + assert.ok( !jQuery.isFunction( mystr ), "Function String" ); + + // When stringified, this could be misinterpreted + myarr = [ "function" ]; + assert.ok( !jQuery.isFunction( myarr ), "Function Array" ); + + // When stringified, this could be misinterpreted + myfunction = { "function": "test" }; + assert.ok( !jQuery.isFunction( myfunction ), "Function Object" ); + + // Make sure normal functions still work + fn = function() {}; + assert.ok( jQuery.isFunction( fn ), "Normal Function" ); + + assert.notOk( jQuery.isFunction( Object.create( fn ) ), "custom Function subclass" ); + + obj = document.createElement( "object" ); + + // Some versions of Firefox and Chrome say this is a function + assert.ok( !jQuery.isFunction( obj ), "Object Element" ); + + // Since 1.3, this isn't supported (#2968) + //ok( jQuery.isFunction(obj.getAttribute), "getAttribute Function" ); + + nodes = document.body.childNodes; + + // Safari says this is a function + assert.ok( !jQuery.isFunction( nodes ), "childNodes Property" ); + + first = document.body.firstChild; + + // Normal elements are reported ok everywhere + assert.ok( !jQuery.isFunction( first ), "A normal DOM Element" ); + + input = document.createElement( "input" ); + input.type = "text"; + document.body.appendChild( input ); + + // Since 1.3, this isn't supported (#2968) + //ok( jQuery.isFunction(input.focus), "A default function property" ); + + document.body.removeChild( input ); + + a = document.createElement( "a" ); + a.href = "some-function"; + document.body.appendChild( a ); + + // This serializes with the word 'function' in it + assert.ok( !jQuery.isFunction( a ), "Anchor Element" ); + + document.body.removeChild( a ); + + // Recursive function calls have lengths and array-like properties + function callme( callback ) { + function fn( response ) { + callback( response ); + } + + assert.ok( jQuery.isFunction( fn ), "Recursive Function Call" ); + + fn( { some: "data" } ); + } + + callme( function() { + callme( function() {} ); + } ); +} ); + +QUnit.test( "isFunction(cross-realm function)", function( assert ) { + assert.expect( 1 ); + + var iframe, doc, + done = assert.async(); + + // Functions from other windows should be matched + Globals.register( "iframeDone" ); + window.iframeDone = function( fn, detail ) { + window.iframeDone = undefined; + assert.ok( jQuery.isFunction( fn ), "cross-realm function" + + ( detail ? " - " + detail : "" ) ); + done(); + }; + + iframe = jQuery( "#qunit-fixture" )[ 0 ].appendChild( document.createElement( "iframe" ) ); + doc = iframe.contentDocument || iframe.contentWindow.document; + doc.open(); + doc.write( "" ); + doc.close(); +} ); + +supportjQuery.each( + { + GeneratorFunction: "function*() {}", + AsyncFunction: "async function() {}" + }, + function( subclass, source ) { + var fn; + try { + fn = Function( "return " + source )(); + } catch ( e ) {} + + QUnit[ fn ? "test" : "skip" ]( "isFunction(" + subclass + ")", + function( assert ) { + assert.expect( 1 ); + + assert.equal( jQuery.isFunction( fn ), true, source ); + } + ); + } +); + +QUnit[ typeof Symbol === "function" && Symbol.toStringTag ? "test" : "skip" ]( + "isFunction(custom @@toStringTag)", + function( assert ) { + assert.expect( 2 ); + + var obj = {}, + fn = function() {}; + obj[ Symbol.toStringTag ] = "Function"; + fn[ Symbol.toStringTag ] = "Object"; + + assert.equal( jQuery.isFunction( obj ), false, "function-mimicking object" ); + assert.equal( jQuery.isFunction( fn ), true, "object-mimicking function" ); + } +); + QUnit.test( "jQuery.isWindow", function( assert ) { assert.expect( 14 ); diff --git a/test/unit/effects.js b/test/unit/effects.js index d023dc8c1..462524ef3 100644 --- a/test/unit/effects.js +++ b/test/unit/effects.js @@ -2507,7 +2507,7 @@ function testEasing( assert, speed, easing, complete ) { assert.equal( options.duration, 10, "Duration set properly" ); assert.equal( - jQuery.isFunction( options.easing ) ? options.easing() : options.easing, + typeof options.easing === "function" ? options.easing() : options.easing, "linear", "Easing set properly" ); diff --git a/test/unit/manipulation.js b/test/unit/manipulation.js index 528a192ce..07ab43419 100644 --- a/test/unit/manipulation.js +++ b/test/unit/manipulation.js @@ -1415,7 +1415,7 @@ QUnit.test( "jQuery.clone() (#8017)", function( assert ) { assert.expect( 2 ); - assert.ok( jQuery.clone && jQuery.isFunction( jQuery.clone ), "jQuery.clone() utility exists and is a function." ); + assert.ok( jQuery.clone && typeof jQuery.clone === "function", "jQuery.clone() utility exists and is a function." ); var main = jQuery( "#qunit-fixture" )[ 0 ], clone = jQuery.clone( main ); diff --git a/test/unit/queue.js b/test/unit/queue.js index 0a6862d6b..f604cea04 100644 --- a/test/unit/queue.js +++ b/test/unit/queue.js @@ -261,7 +261,7 @@ QUnit.test( ".promise(obj)", function( assert ) { var obj = {}, promise = jQuery( "#foo" ).promise( "promise", obj ); - assert.ok( jQuery.isFunction( promise.promise ), ".promise(type, obj) returns a promise" ); + assert.ok( typeof promise.promise === "function", ".promise(type, obj) returns a promise" ); assert.strictEqual( promise, obj, ".promise(type, obj) returns obj" ); } ); -- 2.39.5