Note: As required by the project, I recently learned javscript. I thought JavaScript was a weak scripting language. You can simply take a look at it. When we see its object-oriented part, we find that the object mechanism is very different from that of C ++ and Java, and it is quite refreshing. I found some information and found a name named Douglas.
Crockford's Daniel wrote deeply, but all of them are in English, so he wanted to translate some classic articles. This is one of them.
Classical inheritance)
Original ENGLISH
You are smart and free
-- John Lennon
Javscript is a non-type object-oriented language. It adopts an original type Inheritance Mechanism different from class inheritance. Although this confused programmers who are familiar with traditional object-oriented languages such as C ++ and Java, as will be shown in this article, the original type Inheritance Method of JavaScript is much more powerful than the class inheritance method.
But there is a question first-why do we focus on inheritance? There are two main reasons. One is type conversion. A strong type language requires a clear mechanism to convert different types of references. However, for a weak type language like JavaScript, all object references are of the same type and do not need to be converted. The second is code reuse. You can define a type and create a large number of objects with the same method. You can also create many objects with similar methods through class inheritance. The class inheritance method is doing well in this respect, but the original type inheritance can do better.
To illustrate this, I will first introduce several basic functions to imitate the style of a traditional class language, then give some models that are not available in the class language, and finally explain these basic functions.
Class inheritance
First, write a parenizor class, which has an attribute value and the corresponding set and get methods, and a tostring () method that wraps the value in parentheses.
function Parenizor(value) { this.setValue(value);}Parenizor.method('setValue', function (value) { this.value = value; return this;});Parenizor.method('getValue', function () { return this.value;});Parenizor.method('toString', function () { return '(' + this.getValue() + ')';});
Although the syntax of this Code is a bit odd, it is easy to identify the class inheritance mode. The method uses a name and function object as the parameter and adds it to the class as a public method.
Therefore, you can write
myParenizor = new Parenizor(0);myString = myParenizor.toString();
As expected, the value of mystring is "(0 )".
Now we create a class that inherits from parenizor, except that the tostring method produces "-0-" When the value is not 0 or not empty, it is the same as parenizor in other aspects.
function ZParenizor(value) { this.setValue(value);}ZParenizor.inherits(Parenizor);ZParenizor.method('toString', function () { if (this.getValue()) { return this.uber('toString'); } return "-0-";});
The inherits method in the Code is similar to Java's extends. The Uber method is equivalent to the super method in Java, and allows the subclassing method to call the version of the parent class. (To avoid conflicts with reserved words, the name is changed .)
Now you can write it like this
myZParenizor = new ZParenizor(0);myString = myZParenizor.toString();
This time, the value of mystring is "-0.
Although JavaScript does not have a class, it can write "class" code.
Multi-Inheritance
Through the prototype attribute of the operation function, you can implement multiple inheritance to create a new class that inherits multiple classes. Any multi-inheritance is difficult to implement and causes name conflicts. Although javascript can implement any multi-inheritance, this example follows a principle called Swiss inheritance.
There is a numbervalue class, which has a setvalue method to check whether the value of the attribute value is a number within a certain range. If not, an exception is thrown. If you only need to inherit setvalue and setrange from this class to zparenizor class, you only need to write
ZParenizor.swiss(NumberValue, 'setValue', 'setRange');
This adds only the required methods.
Parasitic inheritance
There is another method to establish zparenizor. Unlike inheriting from parenizor, you only need to create a constructor that calls parenizor () and return the call result. Unlike adding a public method, constructor adds a method called a privileged method.
function ZParenizor2(value) { var that = new Parenizor(value); that.toString = function () { if (this.getValue()) { return this.uber('toString'); } return "-0-" }; return that;}
Class inheritance is a "yes" relationship, while parasitic inheritance is a "previously, but not now" relationship. Constructor plays a major role in object construction. Note that the Uber method is still available in privileged functions.
Class Enhancement
Javscript allows you to add or replace any existing class method, and you can call this method in any existing or future instances of this class at any time. You can directly extend a class at any time. However, the inherited method can only be called in the New Inherited subclass instance after the parent class is changed. We call this class enhancement to avoid conflicts with extends that have additional meanings in Java.
Object Enhancement
In static object-oriented language, a new class must be defined even if a new object that is slightly different from other objects is required. However, in Javascript, you can add methods for a single object without defining additional classes. This is an infinite power, because it can reduce the number of classes and the difficulty of coding. Recall that the T object of limit Crip is like a hash table. You can add new attributes at any time. If the attribute value is a function, the new method is added.
Therefore, the above Code does not actually require the zparenizor class, but can be implemented simply by modifying the instance.
myParenizor = new Parenizor(0);myParenizor.toString = function () { if (this.getValue()) { return this.uber('toString'); } return "-0-";};myString = myParenizor.toString();
Now, only a tostring method is added to the myparenizor object, without any inheritance. It is precisely because the Javascript language does not have the concept of class that we can evolve any single object instance.
Basic functions
To make the preceding example work properly, I have written several basic functions. The first is to add a method function to the class.
Function.prototype.method = function (name, func) { this.prototype[name] = func; return this;};
It adds a public method to function. prototype so that all functions can obtain this method through class enhancement. It uses a name and a function as a parameter and adds it as a function to the prototype object of the function.
The return value of method is this. When I write a function that does not return a value, I am used to returning this, which facilitates chained programming.
The next function is inherits. It can be seen literally that it is used to make a class inherit from other classes. This function can only be used after both classes are defined but before the extended class adds a new method.
Function.method('inherits', function (parent) { var d = {}, p = (this.prototype = new parent()); this.method('uber', function uber(name) { if (!(name in d)) { d[name] = 0; } var f, r, t = d[name], v = parent.prototype; if (t) { while (t) { v = v.constructor.prototype; t -= 1; } f = v[name]; } else { f = p[name]; if (f == this[name]) { f = v[name]; } } d[name] += 1; r = f.apply(this, Array.prototype.slice.apply(arguments, [1])); d[name] -= 1; return r; }); return this;});
Added function again! We created a new parent instance and used it as the new prototype. At the same time, we modified the constructor attribute and added the Uber Method for prototype.
The Uber method looks for a method with a given name in its prototype. It is used in case of parasitic inheritance or object enhancement. If you are using class inheritance, you need to find the method of the given name in the prototype of the parent. The Return Statement uses the apply method of the function to explicitly set this attribute and pass the parameter array to call this function. The parameters (if any) are obtained through the arguments array. Unfortunately, arguments is not a real array, so you have to use the apply method again to call the Slice Method of the array.
Finally, the Swiss method is used.
Function.method('swiss', function (parent) { for (var i = 1; i < arguments.length; i += 1) { var name = arguments[i]; this.prototype[name] = parent.prototype[name]; } return this;});
The Swiss method traverses the arguments parameter. For each name attribute, copy the prototype from the parent prototype to the prototype of the new class.
Conclusion
Although javascript can be used like class inheritance, it still has some very unique features. We have elaborated on class inheritance, Swiss inheritance, parasitic inheritance, class enhancement, and object enhancement. However, many reuse modes come from a language that is smaller and simpler than Java.
Class inheritance is stiff. The only way to add new members to a "hard object" is to create a new class. However, objects in JavaScript are "soft", and new members can be simply added by assigning values.
Because the objects in Javascript have such powerful scalability, you may want to think about class inheritance. A deep inheritance structure is usually not suitable. A shallow inheritance structure is more effective and powerful.
I have been writing javascript programs for eight years, but I have never found that uber functions are needed. The parent class is very important in the class mode, but it is dispensable in the prototype and function mode. Now I think it is an error to imitate the class model in JavaScript.