This article mainly introduces the detailed information about setter and getter modes of jQuery3.0, which is very good and has reference value. If you need it, you can refer to setter/getter of jQuery to share a function, indicates whether to pass the parameter. To put it simply, the parameter is a setter, and the parameter is not a getter.
A function has multiple meanings and is not uncommon in programming languages. For example, function overloading: A group of functions with the same function name and different parameter lists are called overload functions. The advantage of overload is that it reduces the number of function names and avoids the pollution of namespace, which is also beneficial to the readability of the program.
Function overloading mainly involves two aspects: one is the parameter type and the same number of parameter types, which can be called function overloading; the other is the number of parameters. Different numbers are also called function overloading. Note that the overload is irrelevant to the return value of the function.
Due to weak JS features, to simulate function overloading, you can only use the second method: number of parameters. Therefore, the arguments object in the function is very important.
The following is an example
function doAdd() {var argsLength = arguments.lengthif (argsLength === 0) {return 0} else if (argsLength === 1) {return arguments[0] + 10} else if (argsLength === 2) {return arguments[0] + arguments[1]}}doAdd() // 0doAdd(5) // 15doAdd(5, 20) // 25
DoAdd implements three meanings by judging the number of parameters of the function. When argsLength is 0, 0 is directly returned; When argsLength is 1, this parameter is added to 10; when argsLength is 2, the two parameters are added.
You can use the function overload feature to implement setter/getter
function text() {var elem = this.elemvar argsLength = arguments.lengthif (argsLength === 0) {return elem.innerText} else if (argsLength === 1) {elem.innerText = arguments[0]}}
The above briefly explains the function overload and uses it to implement setter/getter. That is, the "valuer" and "value assignment" are integrated. Whether it is a value or a value is determined by the function parameters. This mode is widely used in many API designs of jQuery.
Summarizes all the APIS using this mode in jQuery, a total of 14 Functions
The source code of access is as follows:
// Multifunctional method to get and set values of a collection// The value/s can optionally be executed if it's a functionvar access = function( elems, fn, key, value, chainable, emptyGet, raw ) { var i = 0, len = elems.length, bulk = key == null; // Sets many values if ( jQuery.type( key ) === "object" ) { chainable = true; for ( i in key ) { access( elems, fn, i, key[ i ], true, emptyGet, raw ); } // Sets one value } else if ( value !== undefined ) { chainable = true; if ( !jQuery.isFunction( value ) ) { raw = true; } if ( bulk ) { // Bulk operations run against the entire set if ( raw ) { fn.call( elems, value ); fn = null; // ...except when executing function values } else { bulk = fn; fn = function( elem, key, value ) { return bulk.call( jQuery( elem ), value ); }; } } if ( fn ) { for ( ; i < len; i++ ) { fn( elems[ i ], key, raw ? value : value.call( elems[ i ], i, fn( elems[ i ], key ) ) ); } } } return chainable ? elems : // Gets bulk ? fn.call( elems ) : len ? fn( elems[ 0 ], key ) : emptyGet;};
This function is a multi-function used to obtain and set the attributes and values of a set element. Value can be an executable function. This function contains less than 60 lines of code. From top to bottom, the first if is to set multiple value values, which is a recursive call. When this recursive call is done, less than 50 lines of code are set for a single value. It is concise and readable.
To understand the access function, I drew two figures.
Two main branches in access
For ease of understanding, I classify access calls to the following categories for ease of understanding.
1. When access is called, the key value of the third parameter is null, which is the text/html method.
text: function( value ) { return access( this, function( value ) { return value === undefined ? jQuery.text( this ) : this.empty().each( function() { if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { this.textContent = value; } } ); }, null, value, arguments.length );},html: function( value ) { return access( this, function( value ) { var elem = this[ 0 ] || {}, i = 0, l = this.length; if ( value === undefined && elem.nodeType === 1 ) { return elem.innerHTML; } // See if we can take a shortcut and just use innerHTML if ( typeof value === "string" && !rnoInnerhtml.test( value ) && !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { value = jQuery.htmlPrefilter( value ); try { for ( ; i < l; i++ ) { elem = this[ i ] || {}; // Remove element nodes and prevent memory leaks if ( elem.nodeType === 1 ) { jQuery.cleanData( getAll( elem, false ) ); elem.innerHTML = value; } } elem = 0; // If using innerHTML throws an exception, use the fallback method } catch ( e ) {} } if ( elem ) { this.empty().append( value ); } }, null, value, arguments.length );},
The two methods are executed inside access
2. In contrast to the first case, the key value is passed when access is called and is not null. This is true for other Setters except text and html.
attr: function( name, value ) { return access( this, jQuery.attr, name, value, arguments.length > 1 );},prop: function( name, value ) { return access( this, jQuery.prop, name, value, arguments.length > 1 );},// Create scrollLeft and scrollTop methodsjQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) { var top = "pageYOffset" === prop; jQuery.fn[ method ] = function( val ) { return access( this, function( elem, method, val ) { var win = getWindow( elem ); if ( val === undefined ) { return win ? win[ prop ] : elem[ method ]; } if ( win ) { win.scrollTo( !top ? val : win.pageXOffset, top ? val : win.pageYOffset ); } else { elem[ method ] = val; } }, method, val, arguments.length ); };} );css: function( name, value ) { return access( this, function( elem, name, value ) { var styles, len, map = {}, i = 0; if ( jQuery.isArray( name ) ) { styles = getStyles( elem ); len = name.length; for ( ; i < len; i++ ) { map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); } return map; } return value !== undefined ? jQuery.style( elem, name, value ) : jQuery.css( elem, name ); }, name, value, arguments.length > 1 );}// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methodsjQuery.each( { Height: "height", Width: "width" }, function( name, type ) { jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) { // Margin is only for outerHeight, outerWidth jQuery.fn[ funcName ] = function( margin, value ) { var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ), extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" ); return access( this, function( elem, type, value ) { var doc; if ( jQuery.isWindow( elem ) ) { // $( window ).outerWidth/Height return w/h including scrollbars (gh-1729) return funcName.indexOf( "outer" ) === 0 ? elem[ "inner" + name ] : elem.document.documentElement[ "client" + name ]; } // Get document width or height if ( elem.nodeType === 9 ) { doc = elem.documentElement; // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], // whichever is greatest return Math.max( elem.body[ "scroll" + name ], doc[ "scroll" + name ], elem.body[ "offset" + name ], doc[ "offset" + name ], doc[ "client" + name ] ); } return value === undefined ? // Get width or height on the element, requesting but not forcing parseFloat jQuery.css( elem, type, extra ) : // Set width or height on the element jQuery.style( elem, type, value, extra ); }, type, chainable ? margin : undefined, chainable ); }; } );} );data: function( key, value ) { var i, name, data, elem = this[ 0 ], attrs = elem && elem.attributes; // Gets all values if ( key === undefined ) { if ( this.length ) { data = dataUser.get( elem ); if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { i = attrs.length; while ( i-- ) { // Support: IE 11 only // The attrs elements can be null (#14894) if ( attrs[ i ] ) { name = attrs[ i ].name; if ( name.indexOf( "data-" ) === 0 ) { name = jQuery.camelCase( name.slice( 5 ) ); dataAttr( elem, name, data[ name ] ); } } } dataPriv.set( elem, "hasDataAttrs", true ); } } return data; } // Sets multiple values if ( typeof key === "object" ) { return this.each( function() { dataUser.set( this, key ); } ); } return access( this, function( value ) { var data; // The calling jQuery object (element matches) is not empty // (and therefore has an element appears at this[ 0 ]) and the // `value` parameter was not undefined. An empty jQuery object // will result in `undefined` for elem = this[ 0 ] which will // throw an exception if an attempt to read a data cache is made. if ( elem && value === undefined ) { // Attempt to get data from the cache // The key will always be camelCased in Data data = dataUser.get( elem, key ); if ( data !== undefined ) { return data; } // Attempt to "discover" the data in // HTML5 custom data-* attrs data = dataAttr( elem, key ); if ( data !== undefined ) { return data; } // We tried really hard, but the data doesn't exist. return; } // Set the data... this.each( function() { // We always store the camelCased key dataUser.set( this, key, value ); } ); }, null, value, arguments.length > 1, null, true );},
The following figure shows how these methods are executed inside access.
For more details about the setter and getter modes of jQuery 3.0, please follow the PHP Chinese network!