First, the package
Original link: http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_encapsulation.html
1.1 Original Model
var Cat = {//prototype name: "",
Color: ""}
var cat1 = {};//instance
Cat1.name = "Floret";
Cat1.color = "Flower";
var cat2 = {};//instance
Cat2.name = "small Black";
Cat2.name = "BLACK";
This is the simplest package, encapsulating two attributes in an object, but this package has two drawbacks
1, if write multiple instances will be very troublesome
2. There is no relationship between instances and prototypes
1.2 Improvement of the original model
Write a function to solve the code duplication problem
function Cat (name,color) {
return {
Name:name,
Color:color
}
var cat1 = Cat ("Floret", "Flower");
var cat2 = Cat ("Small Black", "Black");
Problems: There is no intrinsic relationship between CAT1 and Cat2, and it is not possible to see them as instances of the same archetype
1.3 Constructor Mode
To solve the problem of generating instances from prototype objects, JS provides a constructor pattern.
The so-called constructor is a normal function, using the This object internally, you can use the new operator inside the constructor to generate an instance, and the this variable is bound on the instance object
var Cat = function (Name,color) {
THIS.name = name;
This.color = color;
}
var cat1 = new Cat ("Floret", "Flower");
var cat2 = new Cat ("Small Black", "Black");
JS provides a instanceof operator that validates the relationship between a prototype object and an instance object
Alert (cat1 instanceof Cat);//ture
Alert (cat2 instanceof Cat);//true
Problem: If there is an immutable property or method, such as var Cat = function (name,color) { this.name = name;
This.color = color;
This.style = "Cat Family"
This.eat = function () {
Alert ("Eat Mouse");
}
}
var cat1 = new Cat ("Small Black", "Black");
var cat2 = new Cat ("Floret", "Flower");
alert (cat1.style);//Cat family
Cat1.eat ();//Eat mice
alert (cat2.style);//Cat family
Cat2.eat ();//Eat mice
For each instance object, the type and eat are the same content, and each time an instance is generated, it must be duplicated, with more memory, less environmentally friendly and less efficient.
Workaround: Prototype mode
Each constructor has a prototype property that points to the prototype object, and all properties and methods of the object are inherited by the instance of the constructor
This means that we can define the invariant properties and methods directly on the prototype.
var Cat = function (Name,color) {
THIS.name = name;
}
Cat.prototype = {
Constructor:cat,
Style: "Cat family",
Eat:function () {
Alert ("Eat Mouse");
}
}
var cat1 = new Cat ("Small Black", "Black");
Cat1.eat ();
alert (Cat1.style);
var cat2 = new Cat ("Floret", "Flower");
alert (Cat2.style);
Cat2.eat ();
Prototype Verification method
The isPrototypeOf method determines the relationship between a prototype object and an instance
Alert (Cat.prototype isprototypeof (CAT1));//true
Alert (Cat.prototype isprototypeof (CAT2));//true
instanceof Determining the relationship between an instance and a parent class
Alert (cat1 instanceof Cat);//true
Alert (cat2 instanceof Cat);//true
Each instance object has a hasOwnProperty () method that determines whether the property is a local property or an inherited prototype property
Alert (cat1 hasownproperty (name));//true as local property
Alert (CAT1 hasownproperty (Eat));//false is an inherited property
The in operator is used to determine whether an instance has a property, whether it is a local property or an inherited property
Alert ("name" in CAT1);//true
Alert ("Age" in CAT1);//false
In can also be variable for all properties in an object
For (Var pro in cat1) {
Alert (the "+pro +" attribute value of "CAT1" is: "+cat1[pro]);
}
Ii. inheritance
Method One, inheritance of constructor function
function Animal () {
This.species = "Animal";
}
function Cat (name,color) {
THIS.name = name;
This.color = color;
}
How can a cat inherit an animal?
Method One: Constructor binding
function Animal () {
This.species = "Animal";
}
function Cat (name,color) {
Animal.apply (this,arguments);
THIS.name = name;
This.color = color;
}
var cat1 = new Cat ("Small Black", "Black");
alert (cat1.species);//"Animal"
Method Two: Prototype mode
If Cat's prototype becomes an instance of animal, cat can inherit animal
Cat.prototype = new Animal (); Cat.prototype.constructor = Cat;var CAT1 = new Cat (); alert (cat1.species);//"Animal"
The prototype object of any one constructor has a constructor property, which points to the constructor.
when there is no Cat.prototype = new Animal (); , Cat.prototype.constructor points to the Cat, but after inheriting the Animal, Cat.prototype.constructor = Animal;
so to make corrections, Cat.prototype.constructor = Cat;
More importantly, the instance also has the constructor property, which points to the constructor property of the constructor prototype object
Alert (Cat1.constructor = = Cat.prototype.constructor);//true
So when Cat.prototype = new Animal (); cat1.constructor = ANIMAL,CAT1 is generated using the constructor cat, but this is Animal, causing confusion in the prototype chain, So to manually correct constructor,
Cat.prototype.constructor = Cat
Method Three: Direct inheritance prototype
Method Three is the improvement of method two: Because of the animal object, the invariant property can be written directly to Animal.prototype. So, we can also let cat () skip Animal () and inherit Animal.prototype directly. function Animal () {}
Animal.prototype.species = "Animal";
Then point the cat's prototype to Animal.prototype
Cat.prototype = Animal.prototype;
Cat.prototype.constructor = Cat;
var cat1 = new Cat ("Small Black", "Black");
alert (cat1.species);//animal
The advantage of doing this compared to the previous method is that it is more efficient (without having to execute and establish an instance of animal) and saves memory. The disadvantage is that Cat.prototype and Animal.prototype now point to the same object, so any changes to the Cat.prototype will be reflected in the Animal.prototype.
So, the above piece of code is actually problematic. Take a look at the second line
Cat.prototype.constructor = Cat;
This sentence actually changed the constructor attribute of the Animal.prototype object too!
alert (Animal.prototype.constructor); Cat
Method four: Using an empty object as an intermediary
var F = function () {};
F.prototype = Animal.prototype;
Cat.prototype = new F ()
Cat.prototype.constructor = Cat;
F as an empty object, almost no memory, at this time modify the cat's prototype object, will not modify the animal prototype object.
Wrap the above method into a function for ease of use
function Extend (child,parent) {
var F = function () {};
F.prototype = Parent.prototype;
Child.prototype = new F ();
Child.prototype.constructor = child;
Child.uber = Parent.prototype;
}
Extend (Cat,animal);
var cat1 = new Cat ();
alert (cat1.species);//animal
This is Yui library implementation of the method of inheritance
Also, note that the last line of the function body
Child.uber = Parent.prototype;
It means setting an Uber property for the sub-object, which points directly to the parent object's prototype property. (Uber is a German word that means "up", "up".) )
This is equivalent to opening a channel on a child object that can call the parent object's method directly. This line is put here, just to achieve the completeness of inheritance, is purely an alternative nature.
Method Five: Copy inheritance
Copies all the properties and methods of the parent object to the child object
function Animal () {}
Anima.prototype.species = "Animal";
function Extend2 (child,parent) {
var p = parent.prototype;
var c = Child,prototype;
for (var i in P) {
C[i] = P[i];
}
}
Extend2 (Cat,animal);
var cat1 = new Cat ("Floret", "Flower");
alert (cat1.species);//animal
Third, the inheritance of the non-constructor function
var Chines = {
Nation: "China"
};
var Doctor = {
Career: "Doctor";
}
Let doctors inherit China and become Chinese doctors.
Method One: The object () method
Function object (parent) {
var F = function () {};
F.prototype = parent;
return new F ();
}
var Doctor = object (Chinese);
Doctor.career = "Doctor";
alert (doctor.nation);//China
Method Two: Shallow copy
function Extend3 (p) {
var c = {};
for (var i in P) {
C[i] = P[i];
}
C.uber = p;
return C;
}
var Doctor = Extend3 (Chines);
Doctor.career = "Doctor";
alert (doctor.nation);//China
However, there is a problem with such a copy. That is, if the parent object's property is equal to an array or another object, then actually the child object obtains only one memory address, not a real copy, so there is a possibility that the parent object will be tampered with.
See, now add a "birthplace" property to Chinese, whose value is an array.
chinese.birthplaces = [' Beijing ', ' Shanghai ', ' Hong Kong '];
With the Extendcopy () function, doctor inherits the Chinese.
var Doctor = extendcopy (Chinese);
We then add a city to the birthplace of doctor:
Doctor.birthPlaces.push (' Xiamen ');
What happened? Chinese's "birthplace" was also changed!
alert (doctor.birthplaces); BEIJING, Shanghai, Hong Kong, Xiamen
alert (chinese.birthplaces); BEIJING, Shanghai, Hong Kong, Xiamen
So, extendcopy () just copies the basic types of data, and we call this copy "shallow copy." This is how early jquery implements inheritance.
Method Three: Deep copy
function Deepcopy (parent,c) {
var c = C | | {};
for (var i in parent) {
if (typeof (parent[i] = = "Object")) {
C[i] = (Parent[i].constructor = = Array)? [] : {};
Deepcopy (Parent[i], c[i]);
}else{
C[i] = Parent[i];
}
}
return C;
}
var Doctor = deepcopy (Chinese);
Doctor.carrer = "Doctor";
Chinese.brithplace = ["Shanghai", "Beijing", "Nanjing"]
alert (doctor.nation);//"China"
Doctor.brithPlace.push ("Inner Mongolia");
alert (doctor.brithplace);//["Shanghai", "Beijing", "Nanjing", "Inner Mongolia"]
The current jquery library is using this method of inheritance
JS Object-oriented