Dojo is a web control library based on the Javascript language. To understand the object-oriented mechanism of dojo, We can first review the basic object-oriented mechanism of JavaScript itself:
First, JavaScript uses functions to simulate object-oriented mechanisms, such:
Function func1 (){};
Func1 (); // function call
New func1 (); // instantiated object
In the preceding two methods, the internal this object of the function is also different.
In addition, there are two basic inheritance methods for JavaScript (of course, there are more complicated ones. Here we only list the two most basic methods)
1. Object impersonating method:
Function
Classa (scolor ){
This. Color = scolor;
This. xxx = xxx;
......
}
Function
Classb (scolor, name ){
This. newmethod = classa;
This. newmethod (scolor );
Delete this. newmethod;
......
}
Or :( classa is the same as above)
Function
Classb (scolor, sname ){
Classa. Call (this, scolor );
// Or apply
This. Name = sname;
This. sayname =
Function (){
Alert (this. Name );
};
}
2. prototype chain inheritance:
// Base class
Function classa ()
{}
Classa... = .....;
// Subclass
Function classb (){}
// Modify prototype to achieve the purpose of Inheritance
Classb. Prototype = new classa ();
// Define new attributes and Methods
Classb... = .....;
// Ensure constructor consistency (After prototype is modified, its constructor becomes classa, which should be classb)
Classb. Prototype. constructor =
Classb;
The above two methods have their own advantages and disadvantages: the object impersonating method is inefficient, and the constructor method must be used but supports multi-inheritance, while the prototype method is flexible but does not support multi-inheritance. The following hybrid method is used:
Function
Classa (scolor ){}
Classa... =... // set attributes
Function classb (){
Classa. Call (this, scolor); // attributes are inherited by the object impersonating method.
This. Name = sname;
}
Classb. Prototype = new classa (); // prototype
Inheritance Method
Classb. Prototype. sayname = function (){
Alert (this. Name );
}
Let's take a look at how dojo implements the Inheritance Mechanism:
The following is a simple example of declaring classes and using classes in Dojo. It can be seen that its core is a dojo. Declare function:
Let's take a look at the dojo. Declare function:
1> first, let's look at the first parameter: classname. You can see the following code:
......
// Add name if
Specified
If (classname ){
Proto. declaredclass = classname;
D. setobject (classname, ctor );
}
......
The Ctor is a function constructed in this method. It is actually the definition of the Declaration class. It is a function object and contains many members, including attribute definition and function definition, A detailed introduction to this will be discussed later. Here, we mainly use dojo. setobject to assign the constructed function object to a variable named classname, such as dijit. widgetset.
So here is equivalent to writing like this:
Ctor = function (){....};
Dijit. widgetset = ctor;
In addition, the proto here is the prototype of the ctor.
2> let's take a look at the third parameter: props. You can see the following code:(See the bold font description)
............
PROTO = {};
// Copy the content of a class definition object. For details, see the templatestring of dijit. Calendar above,
Value, buildrendering, and other attributes and methods.
Safemixin (PROTO, props );
//
Start to construct the ctor, that is, the definition of the constructor class. You can see that there are many attributes added by dojo.
T =! Chains |
! Chains. hasownproperty (cname );
// Singleconstructor/simpleconstructor/chainedconstructor
All
It is a function object, and its return value is also a function object. These returned function objects contain some default operations, including initialization, calling ctor, and its base class ctor, for details, refer to the definitions of the above three functions. We can see what the function simulating the dojo class did during initialization. It is worth studying, so that the length is not too long, I will not go into detail here for the time being.
Bases [0] = ctor = (chains & chains. constructor = "Manual ")?
Simpleconstructor (bases ):
(Bases. Length = 1?
Singleconstructor (props. constructor, T): chainedconstructor (bases,
T ));
// Add meta information to the constructor
// The ctor attribute here is critical, as mentioned above
The singleconstructor/simpleconstructor/chainedconstructor function is called. This is why the "class" of dojo. Declare automatically calls the constructor method during initialization (new operation !!!
Ctor. _ meta = {bases: bases, hidden: props, Chains: chains,
Parents:
Parents,Ctor: props. Constructor
};
Ctor. superclass =
Superclass & superclass. Prototype;
Ctor. Extend = extend;
// Here is a key operation. All defined attributes are taken as prototype attributes. Note that we will not talk about inheritance here, and it is not inherited here, separate it from the previous JavaScript inheritance
Ctor. Prototype =
PROTO;
// Because prototype is modified, a new value must be assigned to maintain the constructor consistency of prototype.
Proto. constructor = ctor;
//
Add commonly used methods in Dojo. Note: These methods are directly added to prototype!
Proto. getinherited =
Getinherited;
Proto. inherited = inherited;
Proto. isinstanceof =
Isinstanceof;
............
// Finally, assign the constructed Class Object ctor (essentially a function object) to the declared Class Name
Dojo. setobject (classname, ctor)
.............
So here we can actually know that the declare class in Dojo is essentially a function object. In fact, it is the following code:
Ctor =
Function (){};
Ctor. Prototype =
Props property definition .....
Class name variable {eval (classname)} = ctor;
3> let's take a look at the second parameter, which is related to the Inheritance Mechanism of dojo:(See the bold font description)
..................
If (OPTs. Call (superclass)
= "[Object array]") {
// Sort the array of base classes when multiple base classes exist.
Bases =
C3mro (superclass );
T = bases [0];
Mixins = bases. Length-T;
// The first object in the base class Array
Superclass = bases [mixins];
} Else {
// Only one base class
Bases = [0];
If (superclass ){
If (OPTs. Call (superclass) = "[object function]") {
T =
Superclass. _ Meta;
Bases = bases. Concat (T? T. bases:
Superclass );
} Else {
Err ("base class is not a callable
Constructor .");
}
} Else if (superclass! = NULL ){
Err ("unknown base class. Did you use dojo. Require To pull it in? ")
}
}
// Start to construct base class attributes and merge their prototype content
If (superclass ){
For (I = mixins-1; -- I ){
// Copy prototype
,Superclass is the first function object in the base class array. After forcenew, it becomes a prototype containing superclass.
An object of an attribute
PROTO = forcenew (superclass );
If (! I ){
// Stop if nothing to add (the last Base)
Break;
}
// Mix in properties
T = bases [I];
// Merge the prototypes of all base classes and use them as the prototypes of the subsequent sub-classes to share attributes.
(T. _ Meta
? Mixown: mix) (PROTO, T. Prototype );
// Construct
Merge prototype-based temporary function objects of the base class
Ctor = new function;
Ctor. superclass = superclass;
Ctor. Prototype = proto;
Superclass = Proto. constructor = ctor;
// The above line of code is used to adjust the constructor of the constructor constructed, maintain consistency, and then modify the superclass for subsequent iteration. In fact, this line is written into the following two lines for better understanding:
// Ctor. Prototype. constructor = ctor;
// Superclass = ctor;
}
} Else {
PROTO = {};
}
.................
Here we just roughly repeat the main line of dojo. Declare, followed by the source code of dojo. Declare (based on dojo1.5). You can refer to it. For more information about dojo. the implementation details of declare are much more worth discussing. However, due to the long length, we will continue to discuss the detailed implementation of Dojo's object-oriented mechanism.
Dojo. Declare and dojo. Require (similar to Java import) and dojo. Provide
These three functions are used together to encapsulate Javascript into a dojo language mode that is close to object-oriented, which is a unique feature of dojo compared to other web control libraries.
Another point: in Dojo. the declare method also implements a useful chain mechanism, which is used by defining the "-chains-" variable. If you are interested, you can study it. I will not describe it too much here.
Add the dojo. Declare source code: (dojo1.5)
D. Declare =
Function (classname, superclass, props ){
// Crack Parameters
If (typeof classname! = "String "){
Props = superclass;
Superclass = classname;
Classname = "";
}
Props = props | | {};
VaR proto, I, T, ctor, name, bases,
Chains, mixins = 1, parents = superclass;
// Build
Prototype
If (OPTs. Call (superclass) = "[object array]") {
// C3 Mro
Bases = c3mro (superclass );
T =
Bases [0];
Mixins = bases. Length-T;
Superclass =
Bases [mixins];
} Else {
Bases = [0];
If (superclass ){
If (OPTs. Call (superclass) = "[Object
Function] ") {
T = superclass. _ Meta;
Bases = bases. Concat (T? T. Bases: superclass );
} Else {
Err ("base class is not a callable constructor .");
}
} Else if (superclass! = NULL ){
Err ("unknown base class. Did you use dojo. Require To pull it in? ")
}
}
If (superclass ){
For (I = mixins-
1; -- I ){
PROTO = forcenew (superclass );
If (! I ){
// Stop if nothing to add (the last Base)
Break;
}
// Mix in
Properties
T = bases [I];
(T. _ meta? Mixown
: Mix) (PROTO, T. Prototype );
// Chain in new
Constructor
Ctor = new function;
Ctor. superclass = superclass;
Ctor. Prototype = proto;
Superclass = Proto. constructor = ctor;
}
} Else {
PROTO = {};
}
// Add all
Properties
Safemixin (PROTO, props );
// Add
Constructor
T = props. constructor;
If (T! =
Op. constructor ){
T. Nom = cname;
Proto. Constructor
= T;
}
// Collect chains and flags
For (I = mixins-1; I; -- I) {// intentional assignment
T =
Bases [I]. _ Meta;
If (T & T. Chains ){
Chains = mix (chains | |{}, T. Chains );
}
}
If (PROTO ["-chains-"]) {
Chains = mix (chains || {},
PROTO ["-chains-"]);
}
// Build ctor
T =! Chains |
! Chains. hasownproperty (cname );
Bases [0] = ctor = (chains &&
Chains. constructor = "Manual ")? Simpleconstructor (bases ):
(Bases. Length = 1? Singleconstructor (props. constructor, T ):
Chainedconstructor (bases, t ));
// Add meta information to
Constructor
Ctor. _ meta = {bases: bases, hidden: props, Chains:
Chains,
Parents: parents, ctor: props. constructor };
Ctor. superclass = superclass & superclass. Prototype;
Ctor. Extend = extend;
Ctor. Prototype = proto;
Proto. constructor = ctor;
// Add "standard" methods to
Prototype
Proto. getinherited = getinherited;
Proto. inherited = inherited;
Proto. isinstanceof =
Isinstanceof;
// Add name if specified
If (classname ){
Proto. declaredclass = classname;
D. setobject (classname, ctor );
}
// Build
Chains and add them to the prototype
If (chains ){
For (name in chains ){
If (PROTO [name] & typeof
Chains [name] = "string" & name! = Cname ){
T =
PROTO [name] = chain (name, bases, chains [name] = "after ");
T. Nom = Name;
}
}
}
// Chained methods do not return values
// No need to chain
"Invisible" Functions
Return ctor; // Function
};