Brand new chain operations

Source: Internet
Author: User
Tags tojson mootools hasownproperty

This is a problem encountered by every framework, whether to implement chained call using prototype extension or to bind methods to an object. If prototype extensions are used, it means they are at odds with all other frameworks that take this path, and there are two daunting opponents on this path-prototype and mootools. If you bind all methods to one object (I usually call it a namespace object), the method calling is not so elegant. Even jquery can only implement node chain operations. But what a framework can achieve is determined by its infrastructure. Jquery is doing its best in terms of what it involves, but do you have any idea that mootools implements the same functions and requiresCodeA little less. This is because jquery is working on a jquery object, while mootools is armed with a lot of objects such as array, String, number, class, event, and element. The benefits of prototype extension are obviously easy to see. We can directly implement chain operations on the literal. For the second type, to implement chained operations, you need to perform prototype extension on a custom object. However, this means that chained operations can only be performed in instance methods, please try again. John resigs wants to make a new-free Instantiation to alleviate the pain of this call (maybe for people in other languages, there are a lot of separate method calls, but in the JS field, chain operations have been used on a large scale, and you still call them one by one when writing Javascript. This is obviously not a trend and will be "lagging behind "!)

 
// Jquery $. trim ("ABC"); // Google closure librarygoog. string. trim ("ABC"); // dojo toolkitdojo. string. trim ("ABC ");

Libraries with a non-obvious layered structure like jquery will attach these tools and methods to namespace objects. However, if the library is large, it won't work like Google closure, it will be messy and messy. When calling a method, there is a process of searching for the method. Here, there will be a consumption of sexual energy. Because the native objects with no extensions are directly returned, the second call may fail.

// Assume that I have added the capitalize method $. capitalize ($. Trim ("ABC") for jquery "));

Is it ugly ?! But now I figured it out. My framework is still very weak, and it cannot be an enemy of prototype and mootools, or it will be killed by them. After thinking for a long time, I divided the native object (prototype) method into three layers. The first is supported by all browsers, and the second is not supported by IE6, but has been included in the draft ECMA, such as javascript1.6 iterator, they can be simulated without using new language features. The third is a custom method, which is needed. Some methods are implemented by many mainstream frameworks, for example, string capitalize, camelize, substitute, array unique, flatten, object each or foreach. We don't need to worry about the first one. The second one is just a compatibility issue. The implementation method is similar, and the effect is the same anyway. Third, if they are also added to the prototype, it is easy to cause a name conflict with other class libraries, because sometimes they are just the same name, and the goal is totally different. Well, it's time to introduce my brand new chain operations.

we know that the reason why a query can be called in a chain is that its method returns objects with all methods each time. This type of object is called an instance because it can call methods on its prototype chain cheaply. In turn, we thought that the prototype chain is actually an object. We can implement these objects independently, which is called an aggregate of extension methods , such as stringext, numberext, and arrayext. The rest is the "instance" problem. The "instance" can have all the methods, including native and custom. Obviously, it is unrealistic to allow an object to work on four native objects. I have made four types of objects accordingly. These objects, I call them proxy objects , are all methods collectively combined, but these methods are completely different from the aggregate of extension methods. They are all proxy methods, the logic is the same. The difference is that a method name is attached to the function body, such as "toarray" and "came e. At the beginning, we put this operation object into a chain function ). This is actually an adapter, but for the sake of simplicity, I will temporarily skip these logics and directly call the chained function (adjustproxy) in it. This function selects different proxy objects based on the type of the operation object, or simply returns the result without doing so. The most important thing is to wait for a method of this proxy object to be called. As I said, it is only a proxy method. The only difference is the method name and the object. When called, it first obtains the method name from itself and the target and type of the operation object from the internal this. Even this type can be calculated, but since it has been computed last time, it is not repeated. With the method name, we can determine whether the operation object supports this method by nature. If not, we can find the corresponding method with the same name from the corresponding extension method collection . Then, call the method and put the result in the chained function (adjustproxy ...... In this way, the chain operation is implemented.

 // by situ zhengmei http://www.cnblogs.com/rubylouvre/ 2010.17var Lang ={}; // get from qwapfunction GetType (OBJ) {var type = typeof OBJ; If (type = 'object') {If (OBJ = NULL) return 'null'; else if (obj. window = OBJ) return 'window'; // window else if (obj. nodename) Return (obj. nodename + ''). replace ('#', ''); // document/element else if (! OBJ. constructor) return 'unknown '; // to_s is the object. prototype. tostring else return to_s.call (OBJ ). slice (8,-1 ). tolowercase ();} return type;} function oneobject (array, Val) {var result ={}, value = Val! = Void 0? VAL: 1; for (VAR I = 0, n = array. length; I 
    • Lang, which is an internal private object and is responsible for storing four types of Extension Method aggregates and corresponding proxy objects.
    • GetType, helper function, with the same function as is.
    • Oneobject, an important auxiliary function in our framework, is used to generate a hash object for the IF branch.
    • Makeproxy: Creates a proxy object. All the methods in it have a name for reflection. These proxy Methods return another Proxy object and attach the real return value to it.
    • Adjustproxy to adjust the proxy object. This method is called in the proxy method. valueof and tostring are used to break the chain operation and return the desired result.
 
// Lang full picture lang = {stringproxy :{/*...... */}, Stringext :{/*...... */}, Numberproxy :{/*...... */}, Numberext :{/*...... */}, Arrayproxy :{/*...... */}, Arrayext :{/*...... */}, Objectproxy :{/*...... */}, Objectext :{/*...... */}}

Then let's define the aggregate of these extension methods. The functions in them are just like defining the prototype functions.

String extension:

// By situ is the United States http://www.cnblogs.com/rubylouvre/ 2010.10.17var stringext = Lang. stringext = {// determine whether a string contains another character contains: function (string, separator) {return (separator )? (Separator + This + separator ). indexof (separator + String + separator)>-1: This. indexof (string)>-1 ;}, startswith: function (pattern) {return this. indexof (pattern) = 0;}, endswith: function (pattern) {var d = This. length-pattern. length; return D> = 0 & this. lastindexof (pattern) === D ;}, toarray: function (crash) {return !! Crash? This. split (''): This. split (/\ s +/g) ;}, // get bytelen: function () {return this. replace (/[^ \ x00-\ xFF]/g ,"--"). length;}, empty: function () {return this. valueof () = '';}, blank: function () {return/^ \ s * $ /. test (this) ;},// length, New String Length, truncation, new string ending field // returns the new string truncate: function (length, truncation) {length = length | 30; truncation = void (0 )? '...': Truncation; return this. length> length? This. slice (0, length-truncation. length) + truncation: string (this) ;}, camelize: function () {return this. replace (/-([A-Z])/g, function ($1, $2) {return $2. touppercase () ;}) ;}, capitalize: function () {return this. replace (/\ B [a-Z]/g, function (s) {return S. touppercase () ;}) ;}, underscore: function () {return this. replace (/([a-z0-9]) ([A-Z] +)/g, function (match, First, Second) {return first + "_" + (secon D. length> 1? Second: second. tolowercase ());}). replace (/\-/g, '_') ;}, toint: function (Radix) {return parseint (this, Radix | 10) ;}, tofloat: function () {return parsefloat (this) ;}, escaperegexp: function () {return this. replace (/([-. * +? ^ $ {} () | [\] \/\])/G, '\ $1');}, // http://www.cnblogs.com/rubylouvre/archive/2010/02/09/1666165.html padleft: function (digits, Radix, filling) {var num = This. tostring (Radix | 10); filling = filling | "0"; while (Num. length <digits) {num = filling + num;} return num;}, padright: function (digits, Radix, filling) {var num = This. tostring (Radix | 10); filling = filling | "0"; while (Num. length <di Gits) {num + = filling;} return num ;},// http://www.cnblogs.com/rubylouvre/archive/2009/11/08/1598383.html times: function (n) {var STR = This, Res = ""; while (n> 0) {If (N & 1) RES + = STR; STR + = STR; n >>= 1;} return res ;}, // The content to be replaced must be surrounded by # {}. Substitute: function (object, Regexp) {return this. replace (Regexp | (/\\? # {([^ {}] +) \}/G), function (match, name) {If (match. charat (0) = '\') Return match. slice (1); Return (object [name]! = Undefined )? Object [name]: '';}) ;}}

Array Extension:

VaR arrayext = Lang. arrayext = {// deeply copy the current array clone: function () {var I = This. length, result = []; while (I --) result [I] = cloneof (this [I]); return result ;}, // determine whether the array contains the element contains: function (EL) {return this. indexof (EL )! =-1 ;}, without: function () {// remove the same element as the input parameter var ARGs = a_slice.call (arguments); return this. filter (function (EL) {return args. indexof (EL )! ==- 1 ;}) ;}, // http://msdn.microsoft.com/zh-cn/library/bb383786.aspx // remove the first match for an element in the array object. Remove: function (item) {var Index = This. indexof (item); If (index! =-1) return arrayext. removeat. Call (this, index); return NULL ;}, // remove the elements at the specified position in the array object. Removeat: function (INDEX) {return this. splice (index, 1) ;}, // shuffling the array, but does not affect the original object // Jonas raoni Soares Silva http://jsfromhell.com/array/shuffle [V1.0] shuffle: function () {var shuff = This. concat (), J, X, I = shuff. length; For (; I> 0; j = math. random (I-1), x = shuff [-- I], shuff [I] = shuff [J], shuff [J] = x) {}; return shuff ;}, min: function () {// more than math. min. apply ({}, this) efficient return math. min. AP Ply (Math, this) ;}, MAX: function () {return math. max. apply (Math, this) ;}, // randomly selects an element from the array. Random: function () {return arrayext. shuffle. call (this) [0];}, ensure: function () {// Add var ARGs = a_slice.call (arguments); ARGs only when the original array does not exist. foreach (function (EL) {If (this. indexof (EL) <0) This. push (EL) ;}, this); return this ;}, // obtain the specific property pluck: function (name) {var result = [] for each element of the object array. prop; this. foreach (Fu Nction (EL) {prop = El [name]; If (prop! = NULL) result. push (PROP) ;}); return result ;}, sortby: function (FN, scope) {var array = This. map (function (El, index) {return {El: El, re: fn. call (scope, El, index )};}). sort (function (left, right) {var A = left. re, B = right. re; return a <B? -1: A> B? 1: 0;}); Return arrayext. pluck. call (array, 'El ');}, compact: function () {// return the elements not null or undefined in the original array in the form of an array return this. filter (function (EL) {return El! = NULL;}) ;}, unique: function () {// returns a new array var result = []; for (VAR I = 0, L = This. length; I <L; I ++) {If (result. indexof (this [I]) <0) {result. push (this [I]) ;}} return result ;}, flatten: function () {var result = []; this. foreach (function (value) {If (is (value, "array") {result = result. concat (arrayext. flatten. call (value);} else {result. push (value) ;}}); return result ;}, // var A = [0, 1, 2, 9]; // var A _ = [0, 5, 2]; // puts (. diff (A _) // --> 1, 9 DIFF: function (array) {var result = [], L = This. length, L2 = array. length, diff = true; For (VAR I = 0; I <L; I ++) {for (VAR J = 0; j <L2; j ++) {If (this [I] === array [J]) {diff = false; break ;}} diff? Result. Push (this [I]): Diff = true;} return result. Unique ();}};

Number Extension:

VaR numberext = Lang. numberext = {times: function (FN, bind) {for (VAR I = 0; I <this; I ++) fn. call (bind, I); return this;}, padleft: function (digits, Radix, filling) {return stringext. padleft. apply (this, [digits, Radix, filling]) ;}, padright: function (digits, Radix, filling) {return stringext. padright. apply (this, [digits, Radix, filling]) ;}, upto: function (number, FN, scope) {for (VAR I = This + 0; I = number; I --) fn. call (scope, I); return this ;}, round: function (base) {If (base) {base = math. pow (10, base); Return math. round (this * base)/base;} else {return math. round (this) ;}}var mathfns = ["ABS", "ACOs", "asin", "atan", "atan2", "Ceil", "Cos ", "exp", "floor", "log", "pow", "sin", "SQRT", "Tan"]; mathfns. foreach (function (name) {numberext [name] = function () {return math [name] (this );}});

object extension:

Function ispureobject (OBJ) {return !! (OBJ & is (OBJ, "object") & OBJ [ctor] === object & OBJ [ctor] [proto]. hasownproperty ("isprototypeof");} // get from mootools function cloneof (item) {If (is (item, "array") {return arrayext. clone. call (item);} else if (ispureobject (item) {return objectext. clone. call (item) ;}else {return item ;}// get from mootools function mergeone (source, key, value) {If (is (value, "array ")) {source [Key] = arrayext. clone. call (value);} else if (ispureobject (value) {If (is (source, "object") {objectext. merge. call (source [Key], value);} else {source [Key] = objectext. clone. call (value) ;}} else {source [Key] = value;} return source ;}; var objectext = Lang. objectext = {// take its subset to form a new object. Keys is a string array subset: function (KEYS) {var Results = {}; for (VAR I = 0, L = keys. length; I

Finally, four proxy objects are defined.

VaR stringfns = ["charat", "charcodeat", "Concat", "indexof", "lastindexof", "localecompare", "match", "quote", "replace ", "Search", "slice", "split", "substring", "tolowercase", "tolocalelowercase", "touppercase", "tolocaleuppercase", "trim ", "tojson"] makeproxy ("string", stringfns. concat (object. keys (stringext); var arrayfns = ["tolocalestring", "Concat", "Join", "pop", "push", "shift", "slice ", "sort", "reverse", "splice", "unshift", "indexof", "lastindexof", "Every", "some", "foreach", "map ", "filter", "reduce", "reduceright"] makeproxy ("array", arrayfns. concat (object. keys (arrayext); var numberfns = ["tolocalestring", "tofixed", "toexponential", "toprecision", "tojson"] makeproxy ("Number", numberfns. concat (object. keys (numberext); var objectfns = ["tolocalestring", "hasownproperty", "isprototypeof", "propertyisenumerable"]; makeproxy ("object", objectfns. concat (object. keys (objectext )));

Use:

 
Alert (chain ("eee"). capitalize (). toarray (true) // E, E, E

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.