From: http://www.ajaxwing.com/index.php?id=2
1. Background
Looking back at the development of programming languages, it is not difficult to find that this is a The process of continuous encapsulation: from the initial assembly language, to process-oriented language, then to object-oriented language, and then to scripting language with object-oriented characteristics, encapsulation layer by layer, step by step, reduce the burden of programmers, and gradually improve writing Program efficiency. This article is about JavaScript, so let’s first understand what kind of language JavaScript is. As of now, JavaScript is a scripting language that does not fully support object-oriented features. The reason why I say this is because JavaScript does support the concept of objects. We see objects in the program, but Javascipt does not support class encapsulation and inheritance. Readers who have had programming experience in C, Java, or php or python will know that these languages allow us to use classes to design objects, and these classes are inheritable. JavaScript does support custom objects and inheritance, but it uses another method: prototype (Chinese translation: prototype). Readers who have used JavaScript or read "Design Patterns" will understand this technology, which is described as follows:
Each object contains a prototype object. When querying an object for a property or requesting a method, The running environment will first search in the current object, and if the search fails, search its prototype object. Note that prototype is also an object, so this search process also applies to the object's prototype object until the current object's prototpye is empty.
In JavaScript, the object's prototype is invisible at runtime and can only be set when defining the object's constructor before creating the object. The following usages are all wrong:
o2.prototype = o1;
/*
At this time, only an attribute named "prototype" of o2 is defined,
does not o1 is set to the prototype of o2.
*/
// ---------------
f2 = function(){};
o2 = new f2;
f2.prototype = o1;
/*
At this time, o1 has not become the prototype of o2,
because o2 has been created before f2 sets prototype.
*/
// ---------------
f1 = function(){};
f2 = function() {};
o1 = new f1;
f2.prototype = o1;
o2 = new f2;
/*
Similarly, at this time o1 is not the prototype of o2,
Because JavaScript does not allow the prototype object of the constructor to be directly referenced by other variables.
*/
The correct usage should be:
f1 = function(){};
f2 = function(){};
f2.prototype = new f1;
o2 = new f2;
As can be seen from the above example: if you want the constructor F2 to inherit the properties and methods defined by another constructor F1, then you must first create a An instance object of F1 and immediately sets it as the prototype of F2 . So you will find that using prototype inheritance method actually discourages the use of inheritance: on the one hand, because JavaScript is designed as an embedded scripting language, for example, it is embedded in a browser, and applications written with it are generally not very large. It is very complicated and does not require inheritance; on the other hand, if the inheritance is deeper, the prototype chain will be longer, and the time spent searching for object properties and methods will become longer, reducing the overall operating efficiency of the program.
Second, problem
Nowadays, JavaScript is used in more and more situations. A very important aspect of web2.0 is user experience. A good user experience requires not only good art, but also response speed and dynamic effects. Many well-known web2.0 applications use a lot of JavaScript code, such as Flickr, Gmail, etc. Some people even use Javasript to write browser-based GUIs, such as Backbase, Qooxdoo, etc. Therefore, the development and maintenance of JavaScript code has become a very important issue. Many people don't like to invent the wheel themselves. They hope that JavaScript can have a mature and stable JavaScript library like other programming languages to improve their development speed and efficiency. What more people hope is that the JavaScript code they write can have good modularity and good reusability like code written in other object-oriented languages, so that it will be more convenient to maintain. However, current JavaScript does not support these requirements very well. Most development has to be started from scratch, and it is very inconvenient to maintain.
Three, existing solutions
If there is a demand, there will naturally be a solution. There are two more mature ones:
1. Now many people use a set of solutions in their own projects. A JavaScript library called prototype.js, which is developed by the MVC web framework Ruby on Rails and uses a JavaScript base library. This library is well designed and has good reusability and cross-browser features. Using prototype.js can greatly simplify the development of client code. prototype.js introduces the concept of classes. Classes written with it can define an initialization function of initialize. This initialization function will be called first when creating a class instance. As its name suggests, the core of prototype.js is still prototype. Although it provides a lot of reusable code, it does not fundamentally solve the development and maintenance problems of JavaScript.
2. People who use asp.net will generally have heard of or used a framework called Atlas, which is Microsoft's AJAX tool. Atlas allows client code to be written using class methods, and has better object-oriented features than prototype.js, such as defining private properties and private methods of classes, supporting inheritance, writing interfaces like Java, etc. Atlas is a client-to-server solution, but it can only be used in asp.net, and copyright and other issues limit its scope of use.
There is only one fundamental solution to the problem, which is to wait for the introduction of the JavaScript2.0 (or ECMAScript4.0) standard. The next version of JavaScript already has object-oriented features in the language. Additionally, these features are already available with Microsoft's JScript.NET. Of course, waiting is not a wise approach.
4. Modello Framework
If the above expression makes you feel a little dizzy, it is best not to rush to understand the Modello Framework. First make sure that you can accurately understand these concepts:
JavaScript Constructor: In JavaScript, custom objects are designed through constructors. Operator new plus a constructor will create an instance object
prototype in JavaScript: If an object P is set as the prototype of a constructor F, then the instance object created using F will inherit the attributes and properties of P Method
Class: Object-oriented languages use classes to encapsulate and design objects. By type, class members are divided into attributes and methods. According to access permissions, class members are divided into static members, private members, protected members, and public members
Inheritance of classes: Object-oriented languages allow one class to inherit the attributes and methods of another class. The inherited class is called a subclass. The inherited class is called the parent class. Some languages allow a subclass to inherit only one parent class (single inheritance), and some languages allow it to inherit multiple (multiple inheritance)
The closure feature in JavaScript: the scope of a function is a closure. JavaScript allows an inner function I to be defined in a function O. The inner function I can always access the variables defined in its outer function O. Even after the external function O returns, if you call the internal function I, you can still access the variables defined in the external function O. That is to say, if you use var to define a variable V in the constructor C and use this to define a function F, when the instance object O created by C calls O.F, F can always access V, but using O.V like this Accessing it does not work, because V is not defined by this. In other words, V becomes a private member of O . This feature is very important. If you haven’t fully understood it yet, please refer to this article "Private Members in JavaScript"
To understand the above concepts, it is not difficult for you to understand the following content. Let’s get started!
As the title says, Modello is a framework that allows and encourages you to write classes in JavaScript. Traditional JavaScript uses constructors to customize objects and prototypes to implement inheritance. In Modello, you can forget about obscure prototypes, because Modello uses classes to design objects and classes to implement inheritance, just like other object-oriented languages, and it is simpler to use. Don’t believe it? Please read on.
Classes written using Modelello have the following features:
Private members, public members and static members
Class inheritance, multiple inheritance
Namespace
Type identification
Modello also has the following features:
Fewer concepts, more convenient usage
Small and compact, with only about two hundred lines of code
Complete separation of design and runtime, using inheritance There is no need to use prototype or create an instance of the parent class first
Class compatible with prototype.js, compatible with JavaScript constructor
Cross-browser, cross-browser version
Open source code, BSD licensed, Allowed to be used for free in personal or commercial projects
Here’s how to use Modello:
1. Define a class
Point = Class.create();
/*
Create a class. People who have used prototype.js will find it familiar;)
*/
2. Register a class
Point.register("Modello.Point");
/ *
Here "Modello" is the namespace, "Point" is the class name, separated by "."
If the registration is successful,
Point.namespace is equal to "Modello", Point.classname is equal to "Point ".
If it fails, Modello will throw an exception indicating the reason for the failure.
*/
Point.register("Point"); // The default namespace "std" is used here
Class.register(Point, "Point"); // Use the register method of Class
3 to get the registered class
P = Class.get("Modello.Point");
P = Class.get("Point") ; // The default namespace "std" is used here
4, and inheritance is used
ZPoint = Class.create(Point); // ZPoint inherits Point
ZPoint = Class.create("Modello.Point"); // Inherit the registered class
ZPoint = Class.create(Point1, Point2[, ...]);
/*
More inherit.The class in the parameter can also be replaced by the registered class name
*/
/*
Inheritance relationship:
Point.subclasses The content is [ZPoint]
ZPoint.superclasses The content is [ Point ]
*/
5, defining static members of the class
Point.count = 0;
Point.add = function(x, y) {
return x y;
}
6, define the constructor of the class
Point.construct = function($self, $class) {
// Use "var" to define private members
var _name = "";
var _getName = function () {
return _name;
}
// Use "this" Define public members
this.x = 0;
this.y = 0;
this.initialize = function (x, y) { // Initialization function
this.x = x;
This.y = y;
$class.count = 1; // Access static members
// Public methods access private properties
this.setName = function (name) {
_name = name;
}
this.getName = function () {
return _getName(); 🎜> return "Point(" . add = function () {
// Call the static method, and use the $ class
return $ class.add (this.x, this.y);
🎜>
>}
ZPoint.construct = function($self, $class) {
this.z = 0; // this.x, this.y inherited from Point
// Overload the initialization function of Point
this.initialize = function (x, y, z) {
this.z = z;
// Call the initialization function of the first parent class,
// The second parent class is $self.super1, and so on.
$self variable. This method can be used, but it is limited to the public methods of the parent class
}
// Overload the toString method of Point
this.toString = function () {
return "Point( " This. ().register("Modello.Point").construct = function($self, $class) {
// ...
}
7, create an instance of the class
// Two methods: new and create
point = new Point(1, 2);
point = Point.create(1, 2);
point = Class.get("Modello .Point").create(1, 2);
zpoint = new ZPoint(1, 2, 3);
8, type identification
ZPoint.subclassOf(Point); // Return true
point.instanceOf(Point); // Return true
point.isA(Point); // Return true
zpoint.isA(Point); // Return true
zpoint .instanceOf(Point); // Return false
// The above classes can be replaced with registered class names
The above are all the functions provided by Modello. Here are some notes and suggestions on using Modello:
When using inheritance, the parent class passed in can be a class defined using prototype.js or a constructor defined using JavaScript
The class is actually It is also a function. The ordinary prototype inheritance method is also applicable to classes defined with Modello.
The class does not need to be registered. This kind of class is called an anonymous class and cannot be obtained through the Class.get method.
If you define a class constructor, As in the above example, two parameters $self and $class are provided. Modello will pass the instance itself to $self and the class itself to $class when creating the instance. $self is generally used when accessing parent class members, and $class is generally used when accessing static members. Although $self and $class are very powerful, it is not recommended that you use them in other situations unless you have read the source code of Modello and really have special needs. Don't even try to use $self instead of this, as this may cause you trouble.
Subclasses cannot access private members of the parent class, and private members cannot be accessed in static methods.
There are no special restrictions on the names of private members in Modello. But it is a good habit to start with "_"
Modello does not support protected members. If you want the parent class members to be accessible by the subclass, you must define the parent class members as public. You can also refer to naming methods like "this._property" to represent protected members:)
Try to define some auxiliary methods with high computational complexity as static members, which can improve operating efficiency
Use Modello Inheritance and type identification can realize basic interface functions, you have already discovered this;)
When using multiple inheritance, the parent class on the left has higher priority than the parent class on the right. That is to say, if multiple parent classes define the same method, the method defined by the leftmost parent class will eventually be inherited.
The functions of classes written using Modello are comparable to those written using Atlas, and are simpler to use. If you want to use the Modello framework instead of the simple class framework in prototype.js, just include modello.js first, and then remove the few lines of code that define Class in prototype.js, and everything will run normally.
If you find a bug in Modello, you are very welcome to contact me via email. If you think Modello should have more functions, you can try reading the source code, and you will find that Modello can easily extend the functions you need.
Modello’s original meaning is “model of large works of art”. I hope Modello can help you write high-quality JavaScript code.
5, download
Modello’s complete reference instructions and download address: http://modello.sourceforge.net