Maison >interface Web >js tutoriel >Explication détaillée des modes setter et getter de jQuery 3.0
Les setter/getter de jQuery partagent une fonction, et sa signification est indiquée par la transmission ou non des paramètres. En termes simples, si les paramètres sont transmis, c'est un setter, et si les paramètres ne sont pas transmis, c'est un getter.
Il n'est pas rare dans les langages de programmation qu'une fonction ait plusieurs significations, comme la surcharge de fonctions : un groupe de fonctions avec le même nom de fonction et des listes de paramètres différentes, ce groupe de fonctions est appelé une fonction surchargée. L'avantage de la surcharge est qu'elle réduit le nombre de noms de fonctions, évite la pollution de l'espace de noms et est également très bénéfique pour la lisibilité du programme.
La surcharge de fonctions reflète principalement deux aspects. L'un est le type de paramètres. Le même nombre de types de paramètres avec des types différents peut être appelé surcharge de fonctions ; C'est ce qu'on appelle la surcharge de fonctions. Notez que la surcharge n'a rien à voir avec la valeur de retour de la fonction.
En raison des faibles caractéristiques de type de JS, si vous souhaitez simuler une surcharge de fonctions, vous ne pouvez le faire que via la deuxième méthode : le nombre de paramètres. Par conséquent, l’objet arguments au sein de la fonction est très important.
Ce qui suit est un exemple
function doAdd() { var argsLength = arguments.length if (argsLength === 0) { return 0 } else if (argsLength === 1) { return arguments[0] + 10 } else if (argsLength === 2) { return arguments[0] + arguments[1] } } doAdd() // 0 doAdd(5) // 15 doAdd(5, 20) // 25
doAdd réalise trois significations en surchargeant pour déterminer le nombre de paramètres de la fonction Lorsque argsLength est 0, il renvoie 0 directement lorsque argsLength est 1 ; , l'argument est ajouté à 10 ; lorsque argsLength vaut 2, les deux arguments sont ajoutés.
L'utilisation de la fonction de surcharge de fonctions peut implémenter setter/getter
function text() { var elem = this.elem var argsLength = arguments.length if (argsLength === 0) { return elem.innerText } else if (argsLength === 1) { elem.innerText = arguments[0] } }
Ce qui précède explique brièvement la surcharge de fonctions et son utilisation pour implémenter setter/getter. Autrement dit, le « preneur de valeur » et le « cédant » sont combinés en un seul. L'obtention ou l'attribution d'une valeur est déterminée par les paramètres de la fonction. De nombreuses conceptions d'API jQuery font un usage intensif de ce modèle.
La figure suivante résume toutes les API de jQuery qui adoptent ce modèle, avec un total de 14 fonctions
Toutes ces fonctions dépendent en interne d'une un autre accès aux fonctions, il n'est pas exagéré de dire que l'accès est au cœur de toutes ces fonctions et au cœur de l'implémentation de setter/getter. Ce qui suit est le code source de cette fonction. Il s'agit d'une fonction privée et ne peut pas être appelée en externe.
Le code source d'accès est le suivant
// Multifunctional method to get and set values of a collection // The value/s can optionally be executed if it's a function var 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; };
Le commentaire de cette fonction mentionne : Il s'agit d'une fonction multifonctionnelle utilisée pour obtenir et définir les attributs et les valeurs d'un élément de collection. value peut être une fonction exécutable. Cette fonction comporte moins de 60 lignes de code au total. En lisant de haut en bas, le premier if consiste à définir plusieurs valeurs et est un appel récursif. En excluant cet appel récursif, le code pour définir une valeur unique fait moins de 50 lignes. L'écriture est très concise et lisible.
Afin de comprendre la fonction d'accès, j'ai dessiné deux schémas
Les deux branches principales au sein de l'accès
Le processus d'exécution interne de l'accès
Les paramètres formels définis par l'accès ont 7
collection d'éléments 1.elems, qui sont passés dans le appelez ceci, ici c'est l'objet jQuery. Nous savons que l'objet jQuery lui-même est une collection avec une propriété de longueur et un index. Doit passer.
2.fn implémente la fonction setter/getter, ce qui signifie que cette fonction doit avoir des conditions pour déterminer quelle partie est un setter et quelle partie est un getter. Doit passer.
3.key Par exemple, quelle valeur de clé doit être transmise aux méthodes attr et prop pour définir ou obtenir. Certains n'ont pas besoin d'être transmis, mais sont remplacés par null à des fins d'espace réservé, comme les méthodes texte et HTML. Facultatif.
4.value ne doit être transmise que lorsqu'il s'agit d'un setter, c'est-à-dire que lorsque la valeur n'est pas définie, c'est un getter, sinon c'est un setter. Facultatif.
5.chainable Lorsqu'il est vrai, il passe en mode setter et renvoie un objet jQuery. false pour passer en mode getter. Passé dans arguments.length ou arguments.length>1 lors de l'appel.
6.emptyGet Lorsque l'objet jQuery est vide, le résultat renvoyé n'est pas défini par défaut et null est passé lorsque la méthode data est appelée.
7.raw Lorsque value est un type de fonction, raw est faux, sinon c'est vrai.
Comme mentionné ci-dessus, l'accès est au cœur de toutes les fonctions setter/getter dans jQuery. En d'autres termes, les 14 fonctions setter/getter appelleront l'accès en interne. C'est pourquoi l'accès comporte 7 paramètres et de nombreuses branches. Parce qu’il doit faire face à de nombreuses conditions. Mais tous ces setters/getters ont beaucoup de code similaire et finissent par extraire une fonction commune.
Afin de faciliter la compréhension, j'ai classé les appels d'accès comme suit pour faciliter notre compréhension.
1. Lors de l'appel d'access, la troisième clé de paramètre est passée comme nulle, qui est la méthode text/html
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 ); },
Le diagramme montre où ces deux méthodes sont exécutées dans access
为什么 key 传 null,因为 DOM API 已经提供了。text 方法使用 el.innerText 设置或获取;html 方法使用 innerHTML 设置或获取(这里简单说,实际还有一些异常处理)。
2. 与第一种情况相反,调用 access 时 key 值传了且不为 null。除了 text/html 外的其它 setter 都是如此
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 methods jQuery.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 methods jQuery.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 ); },
图示这些方法在 access 内部执行处
更多jQuery 3.0 的 setter和getter 模式详解相关文章请关注PHP中文网!