Source code analysis of mootools: core. js

Source: Internet
Author: User
Tags iterable mootools hasownproperty

I have long wanted to write such a blog. Maybe it's a series of mootools, But it's estimated that there won't be enough time recently, so the series will be too pitfall. If you are interested, you can continue. I think that starting from the source code of mootools, you can write a good JavaScript intermediate textbook. If I have time, I will make a series of slogans. <Br/> I analyzed the core of mootools, core. js. The version I saw is 1.2.4dev, which was cloned from GitHub. Git clone git: // The core of core. JS is the native function. Then there are some common tools and simple and practical extensions for objects and arrays. The object extension class is named hash. I have written the analysis into the code in detail, so you can read it patiently. I believe there will be a lot of GAINS. </P> <p> [JavaScript] <br/> var mootools = {<br/> 'version': '1. 2.4dev ', <br/> 'build': '% build %' <br/>}; <br/> // native is the absolute core of mootools, all classes are constructed by native functions. <br/> var native = function (options) {<br/> // if no configuration exists, is an initial empty object <br/> Options = options | |{}; <br/> // specify the class name from the configuration <br/> var name = options. name; <br/> // The original built-in object that is retained when packaging the built-in object <br/> var legacy = options. legacy; <br/> // whether to prevent methods in the original object's prototype from being overwritten <br /> Var protect = options. protect; <br/> // attributes or methods to be added to the class. If generics is not false, add them to prototype, static at the same time <br/> // here methods indicates that the author wants options. all methods passed in by implement <br/> VaR methods = options. implement; <br/> // whether all attributes and methods of the object are static. If you do not want to perform static operations, you can only set the value to false. <br/> var generics = options. generics; <br/> // initialization method <br/> var initialize = options. initialize; <br/> // used for subsequent operations of the add method <br/> var afterimplement = options. afterimplement | Function () {}; <br/> // use the built-in object as the prototype if the initialize method is not provided <br/> var object = initialize | legacy; <br/> // set this parameter to false only when the constant value of generics is false. In other cases, set this parameter to true. <br/> generics = generics! = False; <br/> // set the class constructor <br/> object. constructor = native; <br/> // unify the static attributes of class objects. $ the name value of the family object is native. $ type function does not use this value. <br/> object. $ family = {Name: 'native '}; <br/> // inherit the legacy prototype <br/> If (legacy & initialize) object. prototype = legacy. prototype; <br/> object. prototype. constructor = object; <br/> If (name) {<br/> // The type name must be in lower case. <br/> var family = Name. tolowercase (); <br/> // write the prototype chain, so that you can modify the prototype to make $ F Amily change, which is useful when adjusting the parent class name <br/> // $ family of the prototype chain is actually used by the $ type function <br/> object. prototype. $ family = {Name: Family}; <br/> // make the object. type (someobject) can determine whether the object and someobject are of the same type <br/> native. typize (object, family); <br/>}< br/> // function for adding attributes or methods to an object (in prototype, and add the object as a static property or method based on generics) <br/> // parameter name method, indicates that all the methods that the author wants to add are methods <br/> var add = function (OBJ, name, method, force) {<br/> // only if the object is not protected or forcibly overwritten or prototyp E does not include this property or method. <br/> If (! Protect | force |! OBJ. prototype [name]) obj. prototype [name] = method; <br/> // static <br/> If (generics) native. genericize (OBJ, name, protect); <br/> // operation after adding a method <br/> afterimplement. call (OBJ, name, method); <br/> return OBJ; <br/> }; <br/> // alias the attribute or method in the Class Object <br/> object. alias = function (A1, A2, A3) {<br/> // if it is an object. alias ('foreach', 'REACH') <br/> If (typeof a1 = 'string') {<br/> var pa1 = This. prototype [a1]; <br/> // If pa1 has a value, that is, A1 is an attribute or method in prototype <br/> If (a1 = pa1) return add (this, A2, A1, a3); <br/>}< br/> // If A1 is a set, batch processing is performed. <br/> // For example, object. alias ({func1: 'functionone', func2: 'functiontwo'}) <br/> for (var a in A1) This. alias (A, A1 [a], A2); <br/> // chain operation supported <br/> return this; <br/> }; <br/> // extend the Class Object (adding attributes and methods) <br/> object. implement = function (A1, A2, A3) {<br/> If (typeof a1 = 'string') Return Add (this, A1, A2, A3); <br/> for (var p in A1) add (this, P, A1 [p], A2 ); <br/> // chain operation supported <br/> return this; <br/> }; <br/> // Add the extension implementation specified in the configuration (add attributes and methods) <br/> If (methods) object. implement (methods); <br/> // return Class Object <br/> return object; <br/> }; <br/> // attributes or methods of static class objects <br/> // If check is true, the existing static attributes or methods with the same name are not overwritten. <br/> native. genericize = function (object, property, check) {<br/> If ((! Check |! Object [property]) & typeof object. prototype [property] = 'function') object [property] = function () {<br/> var ARGs = array. prototype. slice. call (arguments); <br/> // The first parameter in the parameter list is passed as the this reference of the original instance method. <br/> return object. prototype [property]. apply (ARGs. shift (), argS); <br/>}; <br/> // expand multiple objects at the same time (add attributes and methods) <br/> native. implement = function (objects, properties) {<br/> for (VAR I = 0, L = objects. length; I <L; I ++) objects [I]. implement (properties); <br/>}; <br/> // Add the type Judgment Method to the class instance, use $ type to determine whether it is the same class or inherit from the same parent class <br/> native. typize = function (object, family) {<br/> If (! Object. type) object. type = function (item) {<br/> return ($ type (item) === family); <br/> }; <br/> (function () {<br/> // Enable Native, the core built-in object of JavaScript, that is, adding attributes and methods to facilitate future extension, existing data will not be overwritten <br/> var natives = {'array': array, 'date': date, 'function': function, 'number': Number, 'regexp': Regexp, 'string': string}; <br/> for (var n in natives) New Native ({Name: N, initialize: natives [N], protect: true}); <B R/> // assign the type Method to the Boolean, native, and object instances. You can determine the type. <br/> var types = {'boolean': Boolean, 'native ': native, 'object': Object}; <br/> for (VAR t in types) native. typize (types [T], t ); <br/> // statically convert the instance methods of array and string to array and string <br/> var generics ={< br/> 'array ': ["Concat", "indexof", "Join", "lastindexof", "pop", "push", "reverse", "shift", "slice ", "sort", "splice", "tostring", "unshift", "Val Ueof "], <br/> 'string': [" charat "," charcodeat "," Concat "," indexof "," lastindexof "," match ", "Replace", "Search", "slice", "split", "substr", "substring", "tolowercase", "touppercase ", "valueof"] <br/>}; <br/> for (VAR g in generics) {<br/> for (VAR I = generics [g]. length; I --;) native. genericize (natives [g], generics [g] [I], true); <br/>}< br/> })(); <br/> var hash = new Native ({<br/> // specify the class name for $ Type method <br/> name: 'hash', <br/> initialize: function (object) {<br/> // if the object is a hash object, copy a clean copy. <br/> // use the getclean method to obtain the attributes and methods of the object (excluding its prototype ), <br/> // use the $ unlink method to unreference an object whose median value is <br/> if ($ type (object) = 'hash ') object = $ unlink (object. getclean (); <br/> // Start copying <br/> for (var key in object) This [Key] = object [Key]; <br/> return this; <br/>}< br/>}); <br/> hash. implement ({<br/> // Traverse the attributes and methods of the hash instance and execute the FN function. The first parameter is the value of the attribute or method, and the second parameter is the key name <br/> foreach: function (FN, BIND) {<br/> for (var key in this) {<br/> If (this. hasownproperty (key) fn. call (bind, this [Key], key, this); <br/>}< br/>}, <br/> // get a clean copy, the inherited attributes or methods are not copied. <br/> getclean: function () {<br/> var clean ={}; <br/> for (var key in this) {<br/> If (this. hasownproperty (key) clean [Key] = This [Key]; <br/>}< br/> return C Lean; <br/>}, <br/> // obtain the total number of attributes and methods of the hash instance, excluding the inherited attributes and Methods. <br/> getlength: function () {<br/> var length = 0; <br/> for (var key in this) {<br/> If (this. hasownproperty (key) length ++; <br/>}< br/> return length; <br/>}< br/> }); <br/> // The foreach method alias of the hash class is each <br/> hash. alias ('foreach ', 'each'); <br/> array. implement ({<br/> // traverses the array instance and executes the FN function. The first parameter is the value, and the second parameter is the array subscript <br/> foreach: function (FN, bind) {<br /> For (VAR I = 0, L = This. length; I <L; I ++) fn. call (bind, this [I], I, this); <br/>}< br/> }); <br/> // obtain the foreach method alias of the array class as each <br/> array. alias ('foreach', 'each '); <br/> // converts an input iteration object to an array <br/> function $ A (iterable) {<br/> // if it is a DOM set <br/> If (iterable. ITEM) {<br/> var L = iterable. length, array = new array (l); <br/> while (L --) array [l] = iterable [l]; <br/> return array; <br/>}< br/> retu Rn array. prototype. slice. call (iterable); <br/>}; <br/> // return a function, this function returns the I entry of the List of accepted parameters <br/> function $ arguments (I) {<br/> return function () {<br/> return arguments [I]; <br/> }; <br/> // check whether the object's properties or methods have been defined, whether the variable has been assigned a value, or whether it is 0 <br/> function $ chk (OBJ) {<br/> return !! (OBJ | OBJ = 0); <br/>}; <br/> // general timer clearing method, if timer does not exist, no error is returned. <br/> function $ clear (timer) {<br/> cleartimeout (timer); <br/> clearinterval (timer ); <br/> return NULL; <br/> }; <br/> // check whether the object property has been defined or whether the variable has been assigned a value <br/> // that is, the object is not undefined <br/> function $ defined (OBJ) {<br/> return (OBJ! = Undefined); <br/>}; <br/> // iteration object. Execute FN (value, key) on all attributes or methods) <br/> function $ each (iterable, FN, bind) {<br/> // obtain the type name of the iteration object <br/> var type = $ type (iterable ); <br/> // if it is an arguments, collection, or array type, run the array each method, <br/> // execute the each method of hash in other cases <br/> (type = 'arguments '| type = 'collection' | type =' array ')? Array: hash ). each (iterable, FN, bind); <br/>}; <br/> // empty function <br/> function $ empty (){}; <br/> // implement original extension through the shallow copy. Note that the original extension is not removed. <br/> function $ extend (original, extended) {<br/> for (var key in (Extended | |{}) original [Key] = extended [Key]; <br/> return original; <br/>}; <br/> // shortcut for instantiating a hash object <br/> function $ H (object) {<br/> return new hash (object ); <br/>}; <br/> // If a function is input, the function is returned. If other values are input, Function <br/> function $ Lambda (value) {<br/> return ($ type (value) = 'function ')? Value: function () {<br/> return value; <br/>}; <br/> // recursively merges all objects in the parameter list, the attribute or method that appears later overwrites the previous one. <br/> // if it is a deep copy, $ unlink is used to remove the reference. <br/> function $ Merge () {<br/> // convert arguments to a real array object, so that you can use array methods such as unshift <br/> var ARGs = array. slice (arguments); <br/> // insert an empty object at the beginning of the array <br/> args. unshift ({}); <br/> return $ Mixin. apply (null, argS); <br/>}; <br/> // recursively merges the attributes and methods of all objects in the parameter list, the following will overwrite the preceding <br/> // here the mix is inserted above Is also the first parameter in the parameter list <br/> function $ Mixin (MIX) {<br/> for (VAR I = 1, L = arguments. length; I <L; I ++) {<br/> var object = arguments [I]; <br/> // only process object objects, $ merge parameters must be enabled for an object. <br/> if ($ type (object )! = 'Object') continue; <br/> for (var key in object) {<br/> var op = object [Key], MP = mix [Key]; <br/> mix [Key] = (MP & $ type (OP) = 'object' & $ type (MP) = 'object ')? $ Mixin (MP, OP): $ unlink (OP); <br/>}< br/> return mix; <br/> }; <br/> // obtain the attribute or method of the first object that has been assigned a value from left to right in the input parameter list, <br/> // or the value of the first variable that has been assigned a value <br/> // the value of the first variable that is not undefined <br/> function $ pick () {<br/> for (VAR I = 0, L = arguments. length; I <L; I ++) {<br/> If (arguments [I]! = Undefined) return arguments [I]; <br/>}< br/> return NULL; <br/> }; <br/> // obtain a pseudo-random number between min and max <br/> function $ random (Min, max) {<br/> return math. floor (math. random () * (max-min + 1) + min); <br/>}; <br/> // converts the input object into an array package, if it is an array, the array is directly returned. If it is undefined, an empty array is returned. <br/> function $ splat (OBJ) {<br/> var type = $ type (OBJ ); <br/> return (type )? (Type! = 'Array' & type! = 'Arguments ')? [OBJ]: OBJ): []; <br/>}; <br/> // returns the current timestamp, which is equivalent to new date (). gettime () <br/> var $ time = date. now | function () {<br/> // if there is no date. now function, you can directly obtain the valueof value of the new date object. The "+" here is the conversion function <br/> return + new date; <br/> }; <br/> // execute all function calls in the parameter list in simple try-catch in sequence. <br/> function $ try () {<br/> for (VAR I = 0, L = arguments. length; I <L; I ++) {<br/> try {<br/> return arguments [I] (); <br/>} catch (E) {}< br/>}< br/> RET Urn NULL; <br/>}; <br/> // determines the type of the Instance Object. <br/> function $ type (OBJ) {<br/> If (OBJ = undefined) return false; <br/> // If (obj. $ family) Return (obj. $ family. name = 'number '&&! Isfinite (OBJ ))? False: obj. $ family. name; <br/> // if it is a single Dom node <br/> If (obj. nodename) {<br/> switch (obj. nodetype) {<br/> // element <br/> case 1: Return 'element'; <br/> // text node <br/> case 3: return (// s /). test (obj. nodevalue )? 'Textnode': 'whitspace'; <br/>}< br/>} else if (typeof obj. length = 'number') {<br/> If (obj. callee) return 'arguments '; <br/> // Dom collection (htmlelements collection) <br/> else if (obj. ITEM) return 'collection'; <br/>}< br/> return typeof OBJ; <br/>}; <br/> // unreference an object, make it independent. The returned object is modified without affecting the original object <br/> function $ unlink (object) {<br/> var unlinked; <br/> switch ($ type (object) {<br/> case 'object': <br/> Unlinked ={}; <br/> for (var p in object) unlinked [p] = $ unlink (object [p]); <br/> break; <br/> case 'hash': <br/> // The Hash itself calls $ Unlink. <br/> unlinked = new hash (object ); <br/> break; <br/> case 'array': <br/> unlinked = []; <br/> for (VAR I = 0, L = object. length; I <L; I ++) unlinked [I] = $ unlink (object [I]); <br/> break; <br/> default: return object; <br/>}< br/> return unlinked; <br/>}; <br/> [/JavaScript] <br/> from my perspective, I think the core should be written more concisely. Of course, this degree of data is required to speak, at present, mootools does not need to extend the hash and array attributes to the core. in JS, the related $ h can also be removed. I also think that $ Chk and $ defined are written in a bit duplicate, wasting code space. The advantage of micro-core is that it can make the above expansion more flexible. From the perspective of serving the product, it can be smaller, because it can build smaller JS on demand, and the expensive traffic will be reduced, user waits are also reduced. At the same time, if the business of the Framework Service is abnormal and complex, a few reasonable branches can be generated more flexibly. This can solve the conflict between the framework maintenance cost and the production performance. 

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: 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.