classical inheritance in JavaScript。
Crockford is the most well-known authority in the JavaScript development community and is JSON、 JSLint、 JsminAnd AdsafeFather, is the author of "Javascript:the Good Parts".
Yahoo is now a senior JavaScript architect, to participate in the design and development of Yui. Here is an article ArticlesThe life and works of Crockford are introduced in detail.
Of course, Crockford is also the object of my junior worship.
Call mode
Let's first look at the invocation method using Crockford Inheritance:
Note: The method, inherits, and Uber are all custom objects in the code, and we'll explain them later in the code analysis.
Defines the person class
function person (name) {
this.name = name;
}
Defines the prototype method
Person.method ("GetName", function () {return
this.name;
});
Defines the Employee class
function employee (name, EmployeeID) {
this.name = name;
This.employeeid = EmployeeID;
}
Specifies that the Employee class inherits Employee.inherits (person) from the person class
;
Defines an Employee's prototype method
Employee.method ("Getemployeeid", function () {return
This.employeeid;
});
Employee.method ("GetName", function () {
//Note that the prototype method of the parent class can be invoked in a subclass return
"Employee name:" + this.uber ("GetName" );
});
Instantiate Subclass
var Zhang = new Employee ("Zhangsan", "1234");
Console.log (Zhang.getname ()); "Employee Name:zhangsan"
There are several mishap that have to be raised:
- The code that the subclass inherits from the parent class must be done after the subclass and the parent class have been defined, and must precede the subclass prototype method definition.
- Although a method of the parent class can be invoked in a subclass method body, the constructor of a subclass cannot invoke the constructor of the parent class.
- Code writing is not elegant, such as the definition of a prototype method and the method of invoking the parent class (not intuitive).
Of course the implementation of Crockford also supports methods in subclasses to invoke parent-class methods with parameters, as follows:
function person (name) {
this.name = name;
}
Person.method ("GetName", function (prefix) {return
prefix + this.name;
});
function Employee (name, EmployeeID) {
this.name = name;
This.employeeid = EmployeeID;
}
Employee.inherits (person);
Employee.method ("GetName", function () {
//note, the first parameter of Uber is the name of the function to invoke the parent class, and the following argument is the parameter of this function.
Personally feel this way less intuitive than this invocation: This.uber ("Employee Name:") return
this.uber ("GetName", "Employee Name:");
});
var Zhang = new Employee ("Zhangsan", "1234");
Console.log (Zhang.getname ()); "Employee Name:zhangsan"
Code Analysis
First, the definition of a method function is simple:
Function.prototype.method = function (name, func) {
//This points to the current function, which is typeof (this) = = "function"
This.prototype[name] = func;
return this;
};
Pay special attention to the point here. When we see this, we can't just focus on the current function, but we should think about how the current function is called. For example, the method in this example is not invoked in the new way, so this is the current function.
The definition of the inherits function is somewhat complicated:
Function.method (' Inherits ', function (parent) {//key is this paragraph: this.prototype = new parent (), where the prototype is implemented in reference to var d =
{}, p = (This.prototype = new parent ()); Add the Uber method only for prototypes of subclasses, where the closure is to know the prototype of the parent class of the current class (that is, the variable-V) this.method (' Uber ', function uber (name) {/ /Here Consider if name is a function name that exists in Object.prototype, such as "toString" in {} = = = = True if (!) (
Name in D)) {//by D[name] count, does not understand the specific meaning 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 {//personally feel that this code is a bit cumbersome, since the meaning of Uber is the function of the parent class, then f directly points to v[name] can be f = p[name];
if (f = = This[name]) {f = v[name];
} D[name] + + + 1; Executes the function name in the parent class, but this point in the function points to the current object//While noting that arguments is truncated using Array.prototype.slice.apply (because arguments is not a standard array, no slicemethod) R = f.apply (this, Array.prototype.slice.apply (arguments, [1]));
D[name]-= 1;
return R;
});
return this;
});Note that there is also a small bug in the inherits function that does not have the point of redefining constructor, so the following error occurs:
var Zhang = new Employee ("Zhangsan", "1234");
Console.log (Zhang.getname ()); "Employee Name:zhangsan"
console.log (Zhang.constructor = = employee); False
console.log (zhang.constructor = = person); True
Improvement recommendations
According to the previous analysis, the individual felt that the method function is not necessary, but it is easy to confuse sight. And the Inherits method can do some slimming (because Crockford may consider more cases, the text introduces several ways to use inherits, and we focus on one of them) and fix the constructor pointing error.
Function.prototype.inherits = function (parent) {
This.prototype = new parent ();
This.prototype.constructor = this;
This.prototype.uber = function (name) {
f = parent.prototype[name];
Return f.apply (this, Array.prototype.slice.call (arguments, 1));
Call Mode:
function person (name) {
this.name = name;
}
Person.prototype.getName = function (prefix) {return
prefix + this.name;
};
function Employee (name, EmployeeID) {
this.name = name;
This.employeeid = EmployeeID;
}
Employee.inherits (person);
Employee.prototype.getName = function () {return
this.uber ("GetName", "Employee Name:");
var Zhang = new Employee ("Zhangsan", "1234");
Console.log (Zhang.getname ()); "Employee Name:zhangsan"
console.log (Zhang.constructor = = employee); True
It's kind of interesting.
At the end of the article, Crockford actually released such words:
I have been writing JavaScript for 8 years now, and I have never the once found to the use a need function. The super idea are fairly important in the classical pattern, but it appears to being unnecessary in the Prototypal and Functi Onal patterns. I now am early attempts to support the classical model in JavaScript as a mistake.
Visible Crockford does not agree with object-oriented programming in JavaScript and claims that JavaScript should be programmed according to the prototype and function patterns (the Prototypal and functional patterns).
But personally, it's much easier to have object-oriented mechanisms in complex scenarios.
But who can guarantee that even projects like the jquery UI don't work for inheritance, and on the other hand, like ExtJS and Qooxdoo, they strongly advocate for object-oriented JavaScript. Even the cappuccino project has invented a Objective-j language to practice object-oriented JavaScript.