jquery1.4 jquery1.4 Download
The jQuery1.4 is used here, why use 1.4 because 1.4 many features are relatively easy to analyze without adding them.
The implementation of this data is extended in the jquery static function, and we usually ($ (' #data '). Data (' Tudou ', ' abc ') calls the data on the jquery prototype, and the data on the prototype is then called under jquery static Data method implementation.
Jquery.extend ({cache: {},expando:expando,// the following elements throw Uncatchable exceptions if you// attempt to add expando properties to them.nodata: {"Embed": true, "Object": true, "applet": true},data: function ( elem, name, data ) { // is not the right element to filter out if ( elem.nodename && jquery.nodata[elem.nodename.tolowercase ()) ) {return;} elem = elem == window ?windowdata :elem;var id = elem[ expando ], cache = jquery.cache, thiscache;// handle the case Where there ' s no name immediately // No data name has not been set data return if ( !name && !id ) {return null;}// compute a unique id for the elementif ( !id ) { id = ++uuid;} avoid generating a new cache unless none exists and we// want to manipulate it.if ( typeof name === "Object" ) {elem[ expando ] = id; // if the object is passed in, extend directly to the cache object thiscache = cache[ id ] = Jquery.extend (true, {}, name);} else if ( cache[ id ] ) { // If there is storage, then get the previous thiscache = cache[ id ];} else if ( typeof data === "undefined" ) {thisCache = Emptyobject;} else { First time storage, to create a new empty object thiscache = cache[ id ] = {}; Prevent overriding the named cache with undefined values // write data to cache store according to uuidif ( data !== undefined ) {elem[ expando ] = id;thiscache[ name ] = data;} // return additional data return typeof name === " String " ? thiscache[ name ] : thiscache;},removedata: function ( elem, name ) {if ( elem.nodename && jquery.nodata[ Elem.nodeName.toLowerCase ()] ) {return;} elem = elem == window ?windowdata :elem;var id = elem[ expando ], cache = jquery.cache, thiscache = cache[ id ];// If we&nbsP;want to remove a specific section of the element ' s dataif ( name ) {if ( thisCache ) {// remove the section of cache datadelete thiscache[ name ];// if we ' ve removed all The data, remove the element ' s cacheif ( jquery.isemptyobject (ThisCache) ) {jquery.removedata ( elem );}} otherwise, we want to remove all of the element ' S data} else {// Clean up the element expandotry {delete elem[ expando ];} catch ( e ) {// IE has trouble directly removing the Expando// but it ' s ok with using removeattributeif ( elem.removeattribute ) {elem.removeattribute ( expando );}} &nbSp completely remove the data cachedelete cache[ id ];}});
The implementation of this data is to create a static variable cache object on the JQuery function, key is the name of data, and value is the value of data. Such as:
Now look at a diagram to see how the data is implemented
The implementation is that jquery assigns a "jquery" + Now () timestamp attribute to the operation of the element, whose value is the unique number of a UUID, which is added 1 per operation, and is then assigned a value in the object static variable of jquery's cache, based on that UUID. Key is like this {5:{}}. And put the data you want to add to this key 5 object {5:{tudou: "abc"}}. The only thing they're connected to is this UUID.
Look at the prototype implementation of JQuery
JQuery.fn.extend ({data: function ( key, value ) {if ( typeof key = == "undefined" && this.length ) {return jquery.data ( this[0] ) ;} else if ( typeof key === "Object" ) { // objects are directly data stored Return this.each (function () {jquery.data ( this, key );}); Var parts = key.split ("."); parts[1] = parts[1] ? "." + parts[1] : ""; // If only pass name is to get the value if ( value === undefined ) { // Settings Trigger getData custom methods They can all capture Var through bind data = this.triggerhandler ("GetData" + parts[1] + "!", [parts[0]]); if ( data === undefined && this.length ) {data = Jquery.data ( this[0], key );} Return data === undefined && parts[1] ?this.data ( parts[0] ) :d ATA;} else { // setting values will trigger setdata methods They can all be captured by bind Return this.trigger ("SetData" + parts [1] + "!", [parts[0], value]). each (function () {jquery.data ( this, key, value );}},removedata: function ( key ) {return this.each (function () {jquery.removedata ( this, key );});});
The implementation here is a lot easier, just need to multi-parameter, get/set the value to handle it, and then to call the corresponding Jquery.data method to implement the value of the set or get
Before a simple simulation of a principle is almost like this
Proxy is relatively simple, but it is easy to faint a thing, give you a few proxies + return closure basic will be dizzy:(
Proxy: function ( fn, proxy, thisObject ) {if ( arguments.length = == 2 ) {if ( typeof proxy === "string" ) { // The first way to call mode $.proxy (obj, ' fn ') thisobject = fn;fn = thisobject[ proxy ]; proxy = undefined;} else if ( proxy && !jquery.isfunction ( proxy ) ) { // the second method of invocation $.proxy (obj.fn, obj) thisobject = proxy;proxy = undefined;}} if ( !proxy && fn ) { /* * Return to refactoring good this function, So the thisObject here is pointing to the final this where to point */proxy = function () {return fn.applY ( thisobject | | this, arguments );};} Set the guid of unique handler to the same of original handler, so it can be removedif ( fn ) {proxy.guid = fn.guid = fn.guid | | proxy.guid | | jquery.guid++;} so proxy can be declared as an argumentreturn proxy;}
It's worth paying attention to this thisobject because the functions, objects, and arrays in JS are addressed, so thisobject can point to this in the object you want to delegate to. It feels very round, but it doesn't make any sense. Thisobject must be a closed bag.
var obj = {name: ' Tudousi ', test:function () {alert (this.name); return false; } }; var func = $.proxy (obj, ' test '); $ ('. Show '). Click (func);
jquery skinning three-data, proxy, event