From: http://www.ajaxwing.com/index.php? Id = 2
I. background
Looking back at the development of programming languages, it is not difficult to find that this is a process of continuous encapsulation: From the first assembly language, to the process-oriented language, and then to the object-oriented language, the scripting language with object-oriented features is further encapsulated to reduce the burden on programmers step by step and gradually improve the efficiency of programming. This article is about JavaScript, so let's take a look at how JavaScript is a language. So far, JavaScript is a scripting language that does not fully support object-oriented features. The reason for this is that JavaScript does support the concept of objects. in the program, we can see that all objects are objects, but Javascipt does not support class encapsulation and inheritance. Readers who once had C ++, Java, php, and python programming experience will know that these languages allow us to use classes to design objects, and these classes can be inherited. JavaScript does support custom objects and inheritance, but it uses prototype ). Readers who have used JavaScript or read design patterns will understand this technology, as described below:
Each object contains a prototype object. When you query an attribute of an object or request a method, the runtime environment first searches for the current object. If the search fails, it searches for its prototype object. Note that prototype is also an object, so this search process also applies to the prototype object of the object until the prototpye of the current object is empty.
In JavaScript, the prototype of an object is invisible at runtime and can be set only before the object is created when the object constructor is defined. The following operations are all incorrect:
O2.prototype = o1;
/*
At this time, only one attribute named prototype of o2 is defined,
The prototype of o1 is not set to o2.
*/
//---------------
F2 = function (){};
O2 = new f2;
F2.prototype = o1;
/*
At this time, o1 is not the prototype of o2,
Because o2 has been created before prototype is set in f2.
*/
//---------------
F1 = function (){};
F2 = function (){};
O1 = new f1;
F2.prototype = o1;
O2 = new f2;
/*
Similarly, o1 is not 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 shown in the preceding example, if you want the constructor F2 to inherit the attributes and methods defined by another constructor F1, you must first create an F1 instance object, and immediately set it to the prototype of F2. Therefore, you will find that the prototype inheritance method does not encourage inheritance. On the one hand, JavaScript is designed as an embedded scripting language, for example, embedded in a browser, applications written with it are generally not very complex and do not need inheritance. On the other hand, if the inheritance is deep, the prototype chain will be long, the time needed to search for object attributes and methods will become longer, reducing the overall running efficiency of the program.
Ii. Problem
Currently, JavaScript is increasingly used. A very important aspect of web2.0 is the user experience. A good user experience requires not only the artist to do well, but also the response speed and dynamic effect. Many well-known web applications use a lot of JavaScript code, such as Flickr and Gmail. Some even use Javasript to compile browser-based GUI, such as Backbase and Qooxdoo. Therefore, JavaScript code development and maintenance become a very important issue. Many people do not like to invent their own wheels. They hope that JavaScript, like other programming languages, will have a mature and stable Javasript library to improve their development speed and efficiency. More people hope that the JavaScript code they write can be very modular and reusable like the code written in other object-oriented languages, which makes maintenance easier. However, JavaScript does not support these requirements well. Most development tasks must start with a new one and it is inconvenient to maintain them.
3. Existing solutions
There will naturally be solutions if needed, and there are two mature solutions:
1. Now many people use a JavaScript library named prototype. js in their own projects, which is developed by the MVC web framework Ruby on Rails and uses the 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 class concept. The class you write can define an initialize initialization function. This initialization function is called first when you create a class instance. Just like its name, prototype. js is the core of prototype. Although many reusable code is provided, it does not fundamentally solve the JavaScript development and maintenance problems.
2. People who use asp.net generally have heard of or used a framework called Atlas, which is Microsoft's powerful AJAX Tool. Atlas allows the client code to be written in the class method, and is similar to prototype. js has better object-oriented features, such as defining private attributes and private methods of classes, supporting inheritance, and writing interfaces Like java. Atlas is a solution from the client to the server, but it can only be used in asp.net, copyright and other issues limit its scope of use.
The only fundamental solution to this problem is to wait for the release of JavaScript2.0 (or ECMAScript4.0) standard. In the next version of JavaScript, the language has the object-oriented feature. In addition, Microsoft JScript. NET can use these features. Of course, waiting is not a wise way.
Iv. Modello framework
If the above statement makes you feel a little dizzy, it is best not to rush to understand the Modello framework. First, ensure that you can understand these concepts accurately:
JavaScript constructor: In JavaScript, custom objects are designed by constructor. Add the constructor to the new operator to create an instance object.
Prototype in JavaScript: if an object P is set to a prototype of constructor F, the instance object created using F inherits the properties and methods of P.
Class: object-oriented languages use classes to encapsulate and design objects. By type, class members are divided into attributes and methods. By access permission, class members are classified into static members, Private Members, protected members, and public members.
Class inheritance: the object-oriented language allows a class to inherit the attributes and methods of another class. The inherited class is called a subclass, And the inherited class is called a parent class. Some languages allow a subclass to inherit only one parent class (single inheritance), while some languages allow inheritance of multiple (multiple inheritance)
Closure in JavaScript: The function scope is a closure. JavaScript allows you to define internal function I in function O. Internal function I can always access the variables defined in its external function O. Even after the external function O returns, you can call the internal function I to access the variables defined in the external function O. That is to say, if you define a variable V with var in constructor C, use this to define a function F, and the Instance Object O created by C calls O. f, F can always access V, but O. V does not work because it is not defined by this. In other words, V becomes a private member of O. This feature is very important. If you have not fully understood it, please refer to this article Private Members in JavaScript
Understanding the above concepts is no longer difficult for you to understand the following content. Let's get started!
For example, Modello is a framework that allows and encourages you to write classes using JavaScript. Traditional JavaScript uses constructors to customize objects and prototype to implement inheritance. In Modello, you can forget the obscure prototype, because Modello uses classes to design objects and implement inheritance using classes, just like other object-oriented languages, and is easier to use. Believe it? Continue.
Classes written using Modello have the following features:
Private, public, and static members
Class inheritance, multi-Inheritance
Namespace
Type Authentication
Modello also has the following features:
Fewer concepts and more convenient use
Small, only about two hundred lines of code
The design phase and runtime phase are completely separated. prototype is not required when inheritance is used, and a parent class instance is not required.
Compatible with prototype. js classes and JavaScript Constructors
Cross-browser and cross-browser version
Open source code, BSD licenced, allows free use in personal or commercial projects
The following describes how to use Modello:
1. Define a class
Point = Class. create ();
/*
Create a class. People who have used prototype. js feel familiar with it ;)
*/
2. Register a class
Point. register ("Modello. Point ");
/*
"Modello" is the namespace, and "Point" is the class name, separated "."
If the registration is successful,
Point. namespace is equal to "Modello", and Point. classname is equal to "Point ".
If Modello fails, an exception is thrown, indicating the cause of the failure.
*/
Point. register ("Point"); // use the default namespace "std" here"
Class. register (Point, "Point"); // use the Class register Method
3. Get the registered class
P = Class. get ("Modello. Point ");
P = Class. get ("Point"); // use the default namespace "std" here"
4. Use inheritance
ZPoint = Class. create (Point); // ZPoint inherits the Point
ZPoint = Class. create ("Modello. Point"); // inherits the registered Class
ZPoint = Class. create (Point1, Point2 [,...]);
/*
Multi-inheritance. Classes in parameters can also be replaced by registered class names.
*/
/*
Inheritance relationship:
Point. subclasses content is [ZPoint]
ZPoint. superclasses content is [Point]
*/
5. Define static members of a 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" to define public members
This. x = 0;
This. y = 0;
This. initialize = function (x, y) {// initialize the function
This. x = x;
This. y = y;
$ Class. count + = 1; // access static members
// Access private attributes using public methods
This. setName = function (name ){
_ Name = name;
}
This. getName = function (){
Return _ getName ();
}
This. toString = function (){
Return "Point (" + this. x + "," + this. y + ")";
}
// Note: The initialize and toString methods take effect only when defined as public members.
This. add = function (){
// Call the static method and use the $ class passed in by the constructor
Return $ class. add (this. x, this. y );
}
}
ZPoint. construct = function ($ self, $ class ){
This. z = 0; // this. x, this. y inherits from Point
// Reload the initialization function of the 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.
// Note: The $ self variable passed in by the constructor is used here.
$ Self. super0.initialize. call (this, x, y );
// This method can be used to call any method of the parent class, but it is limited to the public method of the parent class.
}
// Reload the toString method of the Point
This. toString = function (){
Return "Point (" + this. x + "," + this. y +
"," + This. z + ")";
}
}
// Writing skills
Class. create (). register ("Modello. Point"). construct = function ($ self, $ class ){
//...
}
7. Create a class instance
// 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. The following describes the precautions and suggestions for using Modello:
When inheritance is used, the passed parent class can be a class defined using prototype. js or a constructor defined using JavaScript.
A class is actually a function. The Inheritance Method of a common prototype is also applicable to classes defined by Modello.
The Class can be not registered. This Class is called an anonymous Class and cannot be obtained through the Class. get method.
If the $ self and $ class parameters are provided as in the preceding example when defining a class constructor, Modello will pass the instance itself to $ self when creating the instance, pass the class itself to $ class. $ Self is generally used when accessing the parent class members, and $ class is generally used when accessing static members. Although $ self and $ class are powerful, it is not recommended that you use them in other scenarios unless you have understood the source code of Modello and have special requirements. Do not try to replace this with $ self, which may cause you trouble.
The subclass cannot access the private member of the parent class, and the Private member cannot be accessed in the static method.
The name of Private Members in Modello is not restricted, but it is a good habit to start "_".
Modello does not support protection (protected) members. If you want the parent class members to be able to access the quilt class, you must define the parent class members as public. You can also refer to the naming method "this. _ property" to protect members :)
Try to define some auxiliary methods with high computing complexity as static members, which can improve the running efficiency.
You can use Modello's inheritance and type identification to implement basic interface functions. You have already discovered this ;)
When multi-inheritance is used, the parent class on the left has a higher priority than the parent class on the right. That is to say, if multiple parent Classes define the same method, the leftmost parent class defines the method to be inherited.
The class functions written using Modello are comparable to those written using Atlas, and are simpler to use. If you want to replace prototype with the Modello framework. in js, you only need to include modello first. js, and then remove prototype. define several lines of code for the Class in js, and everything will run normally.
If you find the Modello bug, you are welcome to contact me via email. If you think Modello should have more functions, you can try to read the source code and you will find that Modello can easily expand the functions you need.
Modello originally meant "the model of a large artistic work" and hoped that Modello could help you write high-quality JavaScript code.
5. Download
Modello complete reference and: http://modello.sourceforge.net