introduce
Any programming proposes code reuse. Otherwise, if you need to write a new program every time you develop a new program or write a new function, then it will be a waste. However, code reuse is also good or bad. In the next two articles, we will discuss code reuse. The first article avoids the use of these patterns as much as possible, because it brings some problems to a greater or lesser extent; the second row is the recommendation, which refers to the recommended pattern that everyone uses, and there will generally be no problems.
Mode 1: Default Mode
There is often a problem with code reuse of the default mode commonly used by everyone. This mode uses Parent()'s constructor to create an object and assign the object to the Child() prototype. Let's look at the code:
The code copy is as follows:
function inherit(C, P) {
C.prototype = new P();
}
// Parent constructor
function Parent(name) {
this.name = name || 'Adam';
}
// Add say function to the prototype
Parent.prototype.say = function () {
return this.name;
};
// Child constructor is empty
function Child(name) {
}
// Execute inheritance
inherit(Child, Parent);
var kid = new Child();
console.log(kid.say()); // "Adam"
var kiddo = new Child();
kiddo.name = "Patrick";
console.log(kiddo.say()); // "Patrick"
// Disadvantages: You cannot pass parameters into the Child constructor
var s = new Child('Seth');
console.log(s.say()); // "Adam"
The disadvantage of this mode is that Child cannot pass parameters, which is basically useless.
Pattern 2: Borrowing constructor
This pattern is that Child borrows Parent's constructor to apply, and then passes child's this and parameters to the apply method:
The code copy is as follows:
// Parent constructor
function Parent(name) {
this.name = name || 'Adam';
}
// Add say function to the prototype
Parent.prototype.say = function () {
return this.name;
};
// Child constructor
function Child(name) {
Parent.apply(this, arguments);
}
var kid = new Child("Patrick");
console.log(kid.name); // "Patrick"
// Disadvantages: The say method is not inherited from the constructor
console.log(typeof kid.say); // "undefined"
The disadvantage is also obvious, and the say method is not available because it has not been inherited.
Pattern 3: Borrow the constructor and set the prototype
The above two modes have their own shortcomings, so how to remove the shortcomings of both? Let’s try:
The code copy is as follows:
// Parent constructor
function Parent(name) {
this.name = name || 'Adam';
}
// Add say function to the prototype
Parent.prototype.say = function () {
return this.name;
};
// Child constructor
function Child(name) {
Parent.apply(this, arguments);
}
Child.prototype = new Parent();
var kid = new Child("Patrick");
console.log(kid.name); // "Patrick"
console.log(typeof kid.say); // function
console.log(kid.say()); // Patrick
console.dir(kid);
delete kid.name;
console.log(kid.say()); // "Adam"
When it runs, everything is normal, but have you noticed that the Parent constructor was executed twice, so although the program is available, it is very inefficient.
Mode 4: Shared Prototype
Shared prototype means that Child and Parent use the same prototype, the code is as follows:
The code copy is as follows:
function inherit(C, P) {
C.prototype = P.prototype;
}
// Parent constructor
function Parent(name) {
this.name = name || 'Adam';
}
// Add say function to the prototype
Parent.prototype.say = function () {
return this.name;
};
// Child constructor
function Child(name) {
}
inherit(Child, Parent);
var kid = new Child('Patrick');
console.log(kid.name); // undefined
console.log(typeof kid.say); // function
kid.name = 'Patrick';
console.log(kid.say()); // Patrick
console.dir(kid);
It is certain that the same is true, Child's parameters are not received correctly.
Pattern 5: Temporary constructor
First, borrow the constructor, then set the Child prototype to an instance of the borrowed constructor, and finally restore the constructor of the Child prototype. The code is as follows:
The code copy is as follows:
/* Closure*/
var inherit = (function () {
var F = function () {
};
return function (C, P) {
F.prototype = P.prototype;
C.prototype = new F();
C.uber = P.prototype;
C.prototype.constructor = C;
}
} ());
function Parent(name) {
this.name = name || 'Adam';
}
// Add say function to the prototype
Parent.prototype.say = function () {
return this.name;
};
// Child constructor
function Child(name) {
}
inherit(Child, Parent);
var kid = new Child();
console.log(kid.name); // undefined
console.log(typeof kid.say); // function
kid.name = 'Patrick';
console.log(kid.say()); // Patrick
var kid2 = new Child("Tom");
console.log(kid.say());
console.log(kid.constructor.name); // Child
console.log(kid.constructor === Parent); // false
The problem is still the same, Child cannot receive parameters normally.
Mode 6: klass
Let's start with the code for this pattern:
The code copy is as follows:
var klass = function (Parent, props) {
var Child, F, i;
// 1.
// New constructor
Child = function () {
if (Child.uber && Child.uber.hasOwnProperty("__construct")) {
Child.uber.__construct.apply(this, arguments);
}
if (Child.prototype.hasOwnProperty("__construct")) {
Child.prototype.__construct.apply(this, arguments);
}
};
// 2.
// Inheritance
Parent = Parent || Object;
F = function () {
};
F.prototype = Parent.prototype;
Child.prototype = new F();
Child.uber = Parent.prototype;
Child.prototype.constructor = Child;
// 3.
// Add implementation method
for (i in props) {
if (props.hasOwnProperty(i)) {
Child.prototype[i] = props[i];
}
}
// return the "class"
return Child;
};
var Man = klass(null, {
__construct: function (what) {
console.log("Man's constructor");
this.name = what;
},
getName: function () {
return this.name;
}
});
var first = new Man('Adam'); // logs "Man's constructor"
first.getName(); // "Adam"
var SuperMan = klass(Man, {
__construct: function (what) {
console.log("SuperMan's constructor");
},
getName: function () {
var name = SuperMan.uber.getName.call(this);
return "I am " + name;
}
});
var clark = new SuperMan('Clark Kent');
clark.getName(); // "I am Clark Kent"
console.log(clark instanceof Man); // true
console.log(clark instanceof SuperMan); // true
How about it? Is it a little dizzy to see? To be nice, the grammar and specification of this pattern are the same as other languages. Are you willing to use it? cough. . .
Summarize
Although the above six modes implement certain functions in certain special circumstances, they all have their own shortcomings, so in general, everyone should avoid using them.