JQuery 3.0 Setter and getter mode detailed _jquery

Source: Internet
Author: User
Tags exception handling

JQuery's Setter/getter share a function, indicating what it means by whether or not it is passed in. Simply say that it is a setter, not a getter.

A function has many meanings that are not uncommon in programming languages, such as function overloading: a set of functions that have the same function name and different parameter lists, which are called overloaded functions. The advantage of overloading is that it reduces the number of function names, avoids the contamination of namespaces, and is useful for the readability of programs.

Function overload mainly embodies the two aspects, one is the type of parameters, the same number of different types of parameters can be called function overload, the second is the number of parameters, the number of different is also called function overload. Note that overloading is not related to the return value of a function.

Because of the characteristics of the JS weak type, to simulate the function overload can only be achieved by the number of the second way: parameters. Therefore, the arguments object in the function is very important.

Here's an example

function Doadd () {
var argslength = arguments.length
if (argslength = = 0) {return
0
} else if (argslengt h = = 1) {return
arguments[0] +
} else if (argslength = = 2) {return
arguments[0] + arguments[1]
}
   }
Doadd ()//0
Doadd (5)//
Doadd (5, 20)//25

Doadd achieves three meanings by judging the number of parameters of the function, Argslength is 0 o'clock, returns 0 directly, Argslength is 1 o'clock, the parameter is added to 10, and Argslength is added to the two parameters of 2 o'clock.

Using function overload attribute can realize setter/getter

function text () {
var elem = This.elem
var argslength = arguments.length
if (argslength = = 0) {return
El Em.innertext
} else if (argslength = = 1) {
elem.innertext = arguments[0]
}

The above simple explanation of function overload and the use of it to implement Setter/getter. That is, "the receiver" and "the assignment" in unity. Whether it is a value or an assignment is determined by the parameters of the function. Many of JQuery's API designs use this pattern in large numbers.

The following figure summarizes all of the APIs in JQuery that use this pattern, with a total of 14 functions

All of these functions are dependent on another function access, and it is no exaggeration to say that access is at the heart of all these functions and is the core of the implementation of Setter/getter. Here is the function of the source code, it is a private function, the outside is not called it.

Access's source code is as follows

Multifunctional method to get and set values of a collection//The VALUE/S can optionally is executed if it ' s a funct Ion var access = function (Elems, FN, key, value, chainable, Emptyget, raw) {var i = 0, len = elems.length, bu
  LK = 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; };

The comment on the function mentions: This is a versatile function that gets and sets the properties and values of a collection element. Value can be an executable function. This function has less than 60 lines of code. Read from top to down, the first if is to set multiple value values, is a recursive call. Planing this recursive call, the code that sets a single value is less than 50 lines. Write very concise, resistant to reading.

To understand the access function, I drew two graphs

Two main branches within access

The execution process inside access

Access defines a formal parameter with 7

A collection of 1.elems elements, the actual call to newsletters is this, where this is a jquery object, and we know that the jquery object itself is a collection with the length attribute and index. Must pass.

2.FN implements the Setter/getter function, which means that the function needs to be conditionally able to determine which part is setter and which part is getter. Must pass.

3.key such as attr and prop methods to pass, set or get the value of which key. Some do not have to pass, but in order to occupy a null substitution, such as text, HTML method. Optional.

4.value only when the setter to pass, that is, the value of undefined is getter, otherwise it is setter. Optional.

5.chainable when True, enter setter mode, which returns the JQuery object. False enters Getter mode. When invoked, passed through Arguments.length or arguments.length>1.

6.emptyGet when the JQuery object is empty, the result returned, which is not passed as the Undefined,data method call, newsletters is null.

7.raw the raw is false when value is a function type, otherwise true.

It says that access is at the heart of all the setter/getter functions of jQuery, in other words, all 14 functions within the Setter/getter function call access. That's why access has 7 parameters, and there are many branches inside. Because it has to deal with a lot of conditions. But all of these setter/getter have a lot of code in common, and finally a public function is extracted.

For the sake of understanding, I classify access's calls below to facilitate our understanding.

1. When you call access, the third parameter key passes a value of NULL, respectively, 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 = = One | | | th
        Is.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; }//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 a exception, use the Fallback method} catch (E) {}} if (elem) {th
    Is.empty (). append (value);
}, NULL, value, arguments.length); },

The two methods are illustrated in the access internal execution office

Why the key is null because the DOM API is already available. The text method is set or fetched using El.innertext, and the HTML method is set or fetched using InnerHTML (here's a little bit of actual exception handling).

2. In contrast to the first case, the key value is passed and not NULL when the access is invoked. Except for the other setters outside the text/html.

Attr:function (name, value) {return access (this, jquery.attr, name, value, Arguments.length > 1);}, Prop:func tion (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) {V
  AR 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", Wi
    DTH: "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] = funct
        Ion (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 A//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") {returnThis.each (function () {Datauser.set (this, key);
  } );
    Return to access (this, function (value) {var data;  The calling JQuery object (element matches) is not empty//(and therefore has a element appears at this[0]) and The//' value ' parameter is not undefined. An empty JQuery object/would result in ' undefined ' for elem = this[0] which would//throw an exception if a
    Ttempt to read a data cache is made. if (elem && value = = undefined) {//attempt to get data from the cache//The key'll always be C
      amelcased in 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); },

Diagram These methods in the access internal execution office

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.