Search code examples
jqueryfunctionpropertiesprototypeextend

Why is jQuery.extend defined as a jQuery function property and jQuery.fn.extend defined as a jQuery prototype object property


jQuery is defined as a function

jQuery.extend is defined as a function property and is itself a function - but is not available to any this scope.

jQuery.fn.extend is defined as a prototype object property - so is available within the scope of this

Why define jQuery.extend in this way as jQuery is not actually an object its a function?

For reference the confusing line of code is:

jQuery.extend = jQuery.fn.extend = function() {...} 

noting that

jQuery.fn === jQuery.prototype 

which is an object {} and jQuery is a function

This means using jQuery.extend directly there is no object instantiated for a this context.

I don't see anywhere in the jQuery code where jQuery is set to a new jQuery() instance . In the jQuery constuctor the only instance I see returned is for the init function i.e. return new jQuery.fn.init().

At runtime within the document ready function if you check what type of object jQuery and $ are you will see it is still a function (not an object instance). So whenever jQuery.extend is called with one parameter, the function will try to extend jQuery itself but by using "this" as the target object i.e. code snippet

// Extend jQuery itself if only one argument is passed
    if (i === length) {
        target = this;
        i--;
    }

Now in my tests "this" within the extend function is referring to the jQuery function not an object instance so the function is being extended with extra "properties" off of the function. What I'm not understanding is how you can add/extend object properties to the function when it has not been instantiated with any new instance creation?


Solution

  • jQuery.extend is really just a utility function used to merge objects. It is similar to the more modern Object.assign() that didn't exist when jQuery library was started

    It is used extensively in the core to add properties to the jQuery object itself but is also available for developer to use to merge their own objects using $.extend(target [, object1 ] [, objectN ] )

    Since it is used as a static method there is no new instance.

    There are several other jQuery methods that are used both internally as utility functions and are exposed publicly such as jQuery.each and jQuery.fn.each which precedes the modern Array#forEach() but can also be used to iterate objects


    Using it in your own code allows you to do

    var a = {x:1},
        b = {y:2},
        res = $.extend({}, a, b)
    
    console.log(res) // new object { "x": 1,  "y": 2}
    console.log(a) // unmodified - still {x:1}
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


    As for section you noted where target = this; that can be explained using a simple object that has a function as property. this in the function is the object itself due to calling context.

    When called within the source core the object is jQuery

    Simple object example:

    var obj = function() {};
    obj.x = 1;
    obj.log = function() {
      // `this` is `obj`
      console.log('this.x = ', this.x)
    }
    
    
    obj.log()