Analysis of Class encapsulation Class libraries for javascript object-oriented Packaging

Source: Internet
Author: User

Javascript is a language with a low entry threshold. Even a technician who has never been familiar with javascript can write a simple and useful program code within a few hours.

However, javascript is a simple language. That's a big mistake. To write high-performance code, you also need to have the basic qualities of a Senior Programmer.

A java or c ++ programmer may not write high-performance javascript code, but it is easier to write high-performance javascript code.
The simplicity of javascript is based on its "broad mind" inclusiveness. It does not need to specify the type, or even any conversion type. It is object-oriented, but has no Class restrictions. It is a language that advocates freedom and is very rigorous. If you are a liberal, embrace javascript!

Object-Oriented Programming (OOP) is a popular programming method. However, javascript OOP is very similar to JAVA and c ++ in that it mainly reflects its different inheritance methods. Javascript is inherited based on PROTOTYPE. All objects are based on the prototype chain and are finally traced to the Object.

I don't want to discuss too much about the differences between the inheritance methods of javascript and those of other languages. This article mainly discusses how to encapsulate the javascript Class to better manage and maintain the basic code, reduce repeated code, and better Modular programming.

Below are some of the better Class encapsulation Class libraries found on github:
I. MY-CLASS
Project address: https://github.com/jiem/my-class
First, let's look at the basic usage:
A. Create a class
Copy codeThe Code is as follows:
(Function (){
// Create a class
VarPerson = my. Class ({
// Add a static method
STATIC :{
AGE_OF_MAJORITY: 18
},
// Constructor
Constructor: function (name, age ){
This. name = name;
This. age = age;
},
// Instance method
SayHello: function (){
Console. log ('hellofrom' + this. name + '! ');
},
// Instance method
DrinkAlcohol: function (){
This. age <Person. AGE_OF_MAJORITY?
Console. log ('tooyoung! Drinkmilkinstead! '):
Console. log ('whiskeyorbeer? ');
}
});
// Expose it to the namespace
MyLib. Person = Person;
})();
Varjohn = newmyLib. Person ('john', 16 );
John. sayHello (); // log "HellofromJohn! "
John. drinkAlcohol (); // log "Tooyoung! Drinkmilkinstead! "

B. inherit a class
Copy codeThe Code is as follows:
(Function (){
// Dreamer inherits the Person
VarDreamer = my. Class (Person ,{
// Constructor
Constructor: function (name, age, dream ){
Dreamer. Super. call (this, name, age );
This. dream = dream;
},
// Instance method
SayHello: function (){
SuperSayHello. call (this );
Console. log ('idreamof '+ this. dream + '! ');
},
// Instance method
WakeUp: function (){
Console. log ('wakeup! ');
}
});
// Super access the parent class
VarsuperSayHello = Dreamer. Super. prototype. sayHello;
// Expose it to the global namespace
MyLib. Dreamer = Dreamer;
})();
Varsylvester = newmyLib. Dreamer ('sylvester', 30, 'eatingtweety ');
Sylvester. sayHello (); // log "HellofromSylvester! IdreamofeatingTweety! "
Sylvester. wakeUp (); // log "Wakeup! "

C. Add a new method to the class
Copy codeThe Code is as follows:
// Add a new method to myLib. Dreamer
My. extendClass (myLib. Dreamer ,{
// Add a static method
STATIC :{
S_dongSomeThing: function (){
Console. log ("dosomething! ");
}
},
// Add an instance
TouchTheSky: function (){
Console. log ('touchingthesky ');
},
// Add an instance
ReachTheStars: function (){
Console. log ('sheissopretty! ');
}
});

D. Implement a class Method
Copy codeThe Code is as follows:
// Declare a new class
MyLib. ImaginaryTraveler = my. Class ({
Travel: function () {console. log ('travelingonacarpet! ');},
CrossOceans: function () {console. log ('sayinghitomobydick! ');}
});
(Function (){
// Dreamer inherits the Person method to implement ImaginaryTraveler
VarDreamer = my. Class (Person, ImaginaryTraveler ,{
// Constructor
Constructor: function (name, age, dream ){
Dreamer. Super. call (this, name, age );
This. dream = dream;
}
//...
});
// Expose it to the global namespace
MyLib. Dreamer = Dreamer;
})();
Varaladdin = newDreamer ('aladdin ');
AladdininstanceofPerson; // true
AladdininstanceofImaginaryTraveler; // false
Aladdin. travel ();
Aladdin. wakeUp ();
Aladdin. sayHello ();

If you are afraid to forget the new operator
Copy codeThe Code is as follows:
VarPerson = my. Class ({
// Youcannowcalltheconstructorwithorwithoutnew
Constructor: function (name, city ){
If (! (ThisinstanceofPerson ))
ReturnnewPerson (name, city );
This. name = name;
This. city = citye;
}
});

Let's take a look at the source code parsing of my. class:
The idea of implementing my. Class is basically like this. If there is only one parameter, a basic Class is declared. this parameter is used to declare the methods, owner, and constructor of the new Class. It is not inherited, but it can be inherited.

The idea of inheritance is that if there are two parameters, the first parameter is inherited by the parent class, and the second parameter is used to declare the methods, attributes, and constructors of the new class, it can also be inherited.

If there are more than three parameters, except the first parameter as the inherited parent class, the last parameter declares the methods, attributes, and constructors of the new class. The intermediate parameter is a method to extend the new class with a class. You can also use my. extendClass to extend the new method.
At the same time, the Class Library provides support for both commonJS and browsing environments!
Copy codeThe Code is as follows:
/* Globalsdefine: true, window: true, module: true */
(Function (){
// Namespaceobject
Varmy = {};
// Ensure that AMD modules are available
If (typeofdefine! = 'Undefined ')
Define ([], function (){
Returnmy;
});
Elseif (typeofwindow! = 'Undefined ')
// Ensure client availability
Window. my = my;
Else
// Ensure that the background is available
Module. exports = my;
// ================================================ ==============================================
// @ Methodmy. Class
// @ Paramsbody: Object
// @ ParamsSuperClass: function, ImplementClasses: function..., body: Object
// @ Returnfunction
My. Class = function (){
Varlen = arguments. length;
Varbody = arguments [len-1]; // The last parameter is the method that specifies itself
VarSuperClass = len> 1? Arguments [0]: null; // The first parameter indicates the inherited method. Both the instance and the static part are inherited.
VarhasImplementClasses = len> 2; // if the third parameter exists, the second parameter is implementClass. In this example, only the instance object is inherited.
VarClass, SuperClassEmpty;
// Constructor
If (body. constructor === Object ){
Class = function (){};
} Else {
Class = body. constructor;
// Ensure that the following constructor is not covered
Deletebody. constructor;
}
// Process the superClass part
If (SuperClass ){
// Middleware to inherit instance attributes
SuperClassEmpty = function (){};
SuperClassEmpty. prototype = SuperClass. prototype;
Class. prototype = newSuperClassEmpty (); // prototype inheritance, unreference
Class. prototype. constructor = Class; // constructor
Class. Super = SuperClass; // parent object access interface
// Static method inheritance, overload the superClass Method
Extend (Class, SuperClass, false );
}
// Process the ImplementClass part. In fact, only the instance attribute part is inherited, except SuperClass # arguments [0] # And body # arguments [length-1] #
If (hasImplementClasses)
For (vari = 1; I <len-1; I ++)
// Implement is the inherited instance attribute part, and the implementClass method of the parent object is reloaded.
Extend (Class. prototype, arguments [I]. prototype, false );
// Process the declared body part, which must be STATIC and deleted from the instance part.
ExtendClass (Class, body );
ReturnClass;
};
// ================================================ ==============================================
// @ Methodmy. extendClass
// @ ParamsClass: function, extension: Object ,? Override: boolean = true
VarextendClass = my. extendClass = function (Class, extension, override ){
// The static part inherits the static part.
If (extension. STATIC ){
Extend (Class, extension. STATIC, override );
// Ensure that some instances do not inherit static methods
Deleteextension. STATIC;
}
// The instance property inherits the instance
Extend (Class. prototype, extension, override );
};
// ================================================ ==============================================
Varextend = function (obj, extension, override ){
Varprop;
// In fact, flase indicates that the method of overwriting the parent object
If (override === false ){
For (propinextension)
If (! (Propinobj ))
Obj [prop] = extension [prop];
} Else {
// The method of the parent object is not covered here, including the toString
For (propinextension)
Obj [prop] = extension [prop];
If (extension. toString! = Object. prototype. toString)
Obj. toString = extension. toString;
}
};
})();

Ii. KLASS
Project address: https://github.com/ded/klass
First look at the usage:
A. Create a class
Copy codeThe Code is as follows:
// Declare a class
VarPerson = klass (function (name ){
This. name = name
})
. Statics ({// static method
Head :':)',
Feet: '_ | _'
})
. Methods ({// instance method
Walk: function (){}
})

B. inherit a class
Copy codeThe Code is as follows:
// SuperHuman inherits the Person
VarSuperHuman = Person. extend (function (name ){
// Automatically call the constructor of the parent class
})
. Methods ({
Walk: function (){
// Explicitly call the walk Method of the parent class
This. supr ()
This. fly ()
},
Fly: function (){}
})
NewSuperHuman ('zelda'). walk ()

C. Declare a class literally
Copy codeThe Code is as follows:
VarFoo = klass ({
Foo: 0,
Initialize: function (){
This. foo = 1
},
GetFoo: function (){
Returnthis. foo
},
SetFoo: function (x ){
This. foo = x
Returnthis. getFoo ()
}
})

D. Implement a class Method
Because sometimes you may want to overwrite or mix an instance method, you can do this:
Copy codeThe Code is as follows:
// A literal can be passed to inherit
VarAlien = SuperHuman. extend ({
Beam: function (){
This. supr ()
// Beamdomainspace
}
})
VarSpazoid = newAlien ('zoopo ')
If (beamIsDown ){
// Override the beam Method
Spazoid. implement ({
Beam: function (){
This. supr ()
// Fallbacktojets
This. jets ()
}
})
}

Next let's take a look at the klass source code parsing.:
The basic design idea of klass is clear, and it tries its best to imitate the inheritance methods of other languages. For example, if the subclass constructor calls the constructor of the parent class, you can also explicitly declare the methods of the parent class.

This determination is based on regular expression matching: fnTest =/xyz/. test (function () {xyz ;})? /\ Bsupr \ B/:/. */; keyword "super"
If the display declares a method to call the parent class, the method is encapsulated into a function that internally calls the parent class method and returns the same value to the current class.

On the other hand, constructor methods are also flexible. If initialize is declared, This is the constructor. Otherwise, if the parameter is a function, it will be used as the constructor; otherwise, the constructor of the parent class will be used.

Use statics to add static methods, and use implements and methods to add instance methods.
Implement inheritance through the extend of the parent class.
At the same time, the Class Library provides support for both commonJS and browsing environments!
Copy codeThe Code is as follows:
/**
* Klass. js-copyright @ dedfat
* Version1.0
* Https://github.com/ded/klass
* Followoursoftwarehttp: // twitter.com/dedfat :)
* MITLicense
*/
! Function (context, f ){
// FnTest is used to verify whether it is possible to use regular expressions to find a method to call the super parent class method.
VarfnTest =/xyz/. test (function () {xyz ;})? /\ Bsupr \ B /:/.*/,
Noop = function (){},
Proto = 'prototype ',
IsFn = function (o ){
Returntypeofo = f;
};
// Basic class
Functionklass (o ){
Returnextend. call (typeofo = f? O: noop, o, 1 );
}
// Wrap it into a function that uses the method with the same name as super
Functionwrap (k, fn, supr ){
Returnfunction (){
// Cache the original this. super
Vartmp = this. supr;
// Temporarily convert this. super Into a method with the same name as super.
// For the explicit statement (fnTest. text (fn) = true) in o to use the super method with the same name
This. supr = supr [proto] [k];
// Borrow execution and save the returned value
Varret = fn. apply (this, arguments );
// Restore the original this. super
This. supr = tmp;
// Return the returned value to ensure that the returned value after wrap is consistent with the original one
Returnret;
};
}
// If o and super have a method with the same name, and o explicitly declares that the method with the same name of super is used, wrap is used as a function to be executed.
// If there is no explicit statement to borrow a super method with the same name, or a method unique to o, or not, use it directly.
Functionprocess (what, o, supr ){
For (varkino ){
// If the method is not an inherited method, follow the method annotation rule and put
If (o. hasOwnProperty (k )){
What [k] = typeofo [k] = f
& Typeofsupr [proto] [k] = f
& FnTest. test (o [k])
? Wrap (k, o [k], supr): o [k];
}
}
}
// The Implementation of the Inheritance Method. fromSub is used to control whether to inherit from the method. In the above klass, fromSub is 1, indicating that the constructor does not use super for execution.
Functionextend (o, fromSub ){
// As a media class, the noop implements prototype inheritance for unreferencing.
Noop [proto] = this [proto];
Varsupr = this,
Prototype = newnoop (), // create an instance object for prototype inheritance and release the reference.
IsFunction = typeofo = f,
_ Constructor = isFunction? O: this, // It is used if o is a constructor; otherwise, this determines the constructor.
_ Methods = isFunction? {}: O, // If o is {...} put methods in the fn prototype. If initialize exists, it is the constructor. If o is a function, it is determined by _ constructor above that o is the constructor.
Fn = function () {// because kclass uses kclass, fn is actually returned, and fn is actually the constructor of the new class.
// 1 If o is {...} it will be filtered by methods and added to the fn prototype. If initialize exists in o, initialize exists in the fn prototype, which is the constructor.
// 2 If o is a function, methods cannot add anything to the fn prototype, but _ constructor will accept o as the constructor
// 3 If o is {....}, there is no initialize in it, so this is the constructor. If it is determined by call in klass, it is obvious that the constructor is noop. If it is in a non-base class, constructor is the constructor of the parent class.
// Because o is not a function, it does not automatically call the constructor of the parent class, but treats the constructor of the parent class as the constructor of the current class. this is determined by the point of this.
Console. log (this );
If (this. initialize ){
This. initialize. apply (this, arguments );
} Else {
// Call the parent class Constructor
// As shown in the preceding 3, o is not a function and will not call the constructor of the parent class.
// The base class has no parent class and does not call the parent class constructor.
FromSub | isFn (o) & supr. apply (this, arguments );
// Call the constructor of this class
// Refer to the above 2, 3, or noop or o
Console. log (_ constructor = noop );
_ Constructor. apply (this, arguments );
}
};
// Interface for constructing the Prototype Method
Fn. methods = function (o ){
Process (prototype, o, supr );
Fn [proto] = prototype;
Returnthis;
};
// Execute the new class prototype to ensure the constructor of the new class
Fn. methods. call (fn, _ methods). prototype. constructor = fn;
// Ensure that the new class can be inherited
Fn. extend = arguments. callee;
// Add instance method or static method, statics: static method, implement instance method
Fn [proto]. implement = fn. statics = function (o, optFn ){
// Ensure that o is an object. If o is a string, a method is added. If o is an object, it is added in batches.
// Because you want to copy from o
O = typeofo = 'string '? (Function (){
Varobj = {};
Obj [o] = optFn;
Returnobj;
} (): O;
// Add instance method or static method, statics: static method, implement instance method
Process (this, o, supr );
Returnthis;
};
Returnfn;
}
// Used in the background, nodejs
If (typeofmodule! = 'Undefined' & module. exports ){
Module. exports = klass;
} Else {
Varold = context. klass;
// Conflict Prevention
Klass. noConflict = function (){
Context. klass = old;
Returnthis;
};
// Used in front-end browsers
// Window. kclass = kclass;
Context. klass = klass;
}
} (This, 'function ');

3. There is also a simple implementation
The implementation idea is very simple. It is to use the original type of ECMAScript5 to inherit the Object. create method and encapsulate it into a method. If ECMAScript5 is not supported, translation degrades
Copy codeThe Code is as follows:
FunctionF (){};
F. prototype = superCtor. prototype;
Ctor. prototype = newF ();
Ctor. prototype. constructor = ctor;

Similarly, except that the last parameter is the method declaration of the current class, all other parameters are used as the inherited parent class and need to be cyclically inherited. However, the processing here is relatively simple and does not involve overwrite. You can add them by yourself.
Copy codeThe Code is as follows:
VarClass = (function (){
/**
* Inheritsfunction. (node. js)
*
* @ Paramctorsubclass 'sconstructor.
* @ Paramsuperctorsuperclass 'sconstructor.
*/
Varinherits = function (ctor, superCtor ){
// Explicitly specify the parent class
Ctor. super _ = superCtor;
// ECMAScript5 original type inheritance and unreference
If (Object. create ){
Ctor. prototype = Object. create (superCtor. prototype ,{
Constructor :{
Value: ctor,
Enumerable: false,
Writable: true,
Retriable: true
}
});
} Else {
// No stable degradation of the Object. create method
FunctionF (){};
F. prototype = superCtor. prototype;
Ctor. prototype = newF ();
Ctor. prototype. constructor = ctor;
}
};
/**
* Classfunction.
*/
Returnfunction (){
// The last parameter is the new class method, attribute, and constructor declaration.
VarsubClazz = arguments [arguments. length-1] | function (){};
// Initialize is the constructor, and no constructor is an empty function.
Varfn = subClazz. initialize = null? Function () {}: subClazz. initialize;
// Except the class with the most one parameter, the inheritance can also be used as an extension method.
For (varindex = 0; index <arguments. length-1; index ++ ){
Inherits (fn, arguments [index]);
}
// Method for implementing the new class
For (varpropinsubClazz ){
If (prop = "initialize "){
Continue;
}
Fn. prototype [prop] = subClazz [prop];
}
Returnfn;
}
})();

See the following example:
Copy codeThe Code is as follows:
/**
* ThedefinitionofCatClass.
*/
VarCat = Class ({
/**
* Constructor.
*
* @ ParamnameCat 'sname
*/
Initialize: function (name ){
This. name = name;
},
/**
* Eatfunction.
*/
Eat: function (){
Alert (this. name + "iseatingfish .");
}
});
/**
* ThedefinitionofBlackCatClass.
*/
VarBlackCat = Class (Cat ,{
/**
* Constructor.
*
* @ ParamnameCat 'sname.
* @ ParamageCat 'sage.
*/
Initialize: function (name, age ){
// Calltheconstructorofsuperclass.
BlackCat. super _. call (this, name );
This. age = age;
},
/**
* Eatfunction.
*/
Eat: function (){
Alert (this. name + "(" + this. age + ") iseatingdog .");
}
});
/**
* ThedefinitionofBlackFatCatClass.
*/
VarBlackFatCat = Class (BlackCat ,{
/**
* Constructor.
*
* @ ParamnameCat 'sname.
* @ ParamageCat 'sage.
* @ ParamweightCat 'sweight.
*/
Initialize: function (name, age, weight ){
// Calltheconstructorofsuperclass.
BlackFatCat. super _. call (this, name, age );
This. weight = weight;
},
/**
* Eatfunction.
*/
Eat: function (){
Alert (this. name + "(" + this. age + ") iseatingdog. Myweight:" + this. weight );
}
});
/**
* ThedefinitionofDogClass.
*/
VarDog = Class ({});
Varcat = newBlackFatCat ("John", 24, "100 ");
Cat. eat ();
// True
Alert (catinstanceofCat );
// True
Alert (catinstanceofBlackCat );
// True
Alert (catinstanceofBlackFatCat );
// True
Alert (cat. constructor === BlackFatCat );
// False
Alert (catinstanceofDog );

Iv. Class of the mootools Class library
Source code analysis can see here: http://www.cnblogs.com/hmking/archive/2011/09/30/2196504.html
See the specific usage:
A. Create a class
Copy codeThe Code is as follows:
VarCat = newClass ({
Initialize: function (name ){
This. name = name;
}
});
VarmyCat = newCat ('micia ');
Alert (myCat. name); // alerts 'mica'
VarCow = newClass ({
Initialize: function (){
Alert ('moooo ');
}
});

B. Inheritance implementation
Copy codeThe Code is as follows:
VarAnimal = newClass ({
Initialize: function (age ){
This. age = age;
}
});
VarCat = newClass ({
Extends: Animal,
Initialize: function (name, age ){
This. parent (age); // callsinitalizemethodofAnimalclass
This. name = name;
}
});
VarmyCat = newCat ('micia ', 20 );
Alert (myCat. name); // alerts 'micia '.
Alert (myCat. age); // alerts20.

C. Implementation of extended classes
Copy codeThe Code is as follows:
VarAnimal = newClass ({
Initialize: function (age ){
This. age = age;
}
});
VarCat = newClass ({
Implements: Animal,
SetName: function (name ){
This. name = name
}
});
VarmyAnimal = newCat (20 );
MyAnimal. setName ('micia ');
Alert (myAnimal. name); // alerts 'mica '.

V. Understanding javascript: the syntax of ganlu
First look at the usage instance
A. Create a class
Copy codeThe Code is as follows:
// Create a class Person
VarPerson = Class (object ,{
Create: function (name, age ){
This. name = name;
This. age = age;
},
SayHello: function (){
Alert ("Hello, I'm" + this. name + "," + this. age + "yearsold .");
}
});
VarBillGates = New (Person, ["BillGates", 53]);
BillGates. SayHello ();

B. Inheritance class
Copy codeThe Code is as follows:
// The Employee inherits the Person
VarEmployee = Class (Person ,{
Create: function (name, age, salary ){
Person. Create. call (this, name, age );
// Call the constructors of the base class
This. salary = salary;
},
ShowMeTheMoney: function (){
Alert (this. name + "$" + this. salary );
}
});
VarSteveJobs = New (Employee, ["SteveJobs", 53,1234]);
SteveJobs. SayHello ();
SteveJobs. ShowMeTheMoney ();

The following is the source code analysis: Obviously, a New method is added, and the instances for creating and creating classes are cleverly encapsulated. Formed a meaningful whole! Another difference is that all classes are based on the literal, rather than functions. The code is very short, but its principles are rich and clever, so you can have a taste of it!
Copy codeThe Code is as follows:
// Create a class function to declare the class and its inheritance relationship
FunctionClass (aBaseClass, aClassDefine ){
// Create a temporary function shell for the class
Functionclass _(){
This. Type = aBaseClass;
// We define a Type attribute for each class and reference its inherited class.
For (varmemberinaClassDefine)
This [member] = aClassDefine [member];
// Define all the replication classes to the currently created classes
};
Class _. prototype = aBaseClass;
Returnnewclass _();
};
// Functions used to create objects of any class
FunctionNew (aClass, aParams ){
// Create a temporary function shell for the object
Functionnew _(){
This. Type = aClass;
// We also specify a Type attribute for each object to access the class to which the object belongs.
If (aClass. Create)
AClass. Create. apply (this, aParams );
// We agree that the constructors of all classes are called Create, which is similar to DELPHI.
};
New _. prototype = aClass;
Returnnewnew _();
};

Due to the general description, there may be many issues that have not been resolved or are inaccurate.
After reading the above several analyses, you can also write your own encapsulated class library for the relevant information. As for how to implement it, you may like it. However, the basic ideas are the same prototype-based Inheritance Method and the new method of circular copy.

Originally from: Mu Yi http://www.cnblogs.com/pigtail/

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.