Javascript Object-oriented programming (i): encapsulation
Nanyi
JavaScript is an object-based (object-based) language, and everything you encounter is almost always an object. However, it is not a true object-oriented programming (OOP) language because it has no syntax class
(class).
So, what should we do if we want to encapsulate the property and method as an object and even generate an instance object from the prototype object?
First, generate the original mode of the instance object
Suppose we think of a cat as an object that has two properties of "name" and "Color".
var Cat = {
Name: ",
Color: '
}
Now we need to generate two instance objects based on the schema of the prototype object.
var cat1 = {}; Create an empty object
Cat1.name = "Mao"; Assigning values according to the properties of the prototype object
Cat1.color = "Yellow";
var cat2 = {};
Cat2.name = "Er mao";
Cat2.color = "BLACK";
Well, this is the simplest package, encapsulating two attributes in an object. However, there are two shortcomings in this writing, one is that if you generate several instances, it is very troublesome to write, and the other is that there is no way between the example and the prototype, and we can see what the connection is.
Ii. improvement of the original model
We can write a function that solves the problem of code duplication.
function Cat (name,color) {
return {
Name:name,
Color:color
}
}
Then generate the instance object, which is equivalent to calling the function:
var cat1 = Cat ("Da Mao", "Yellow");
var cat2 = Cat ("Er Mao", "Black");
The problem with this approach remains that cat1
cat2
there is no intrinsic connection between them and that they are instances of the same prototype object.
Third, the structural function mode
To solve the problem of generating instances from prototype objects, JavaScript provides a constructor (Constructor) pattern.
The so-called "constructor", in fact, is a normal function, but the internal use of this
variables. Using an operator on a constructor new
enables you to generate an instance, and the this
variable is bound to the instance object.
For example, a cat's prototype object can now be written like this,
function Cat (name,color) {
This.name=name;
This.color=color;
}
We can now build the instance object.
var cat1 = new Cat ("Da Mao", "Yellow");
var cat2 = new Cat ("Er Mao", "Black");
alert (cat1.name); Da Mao
alert (Cat1.color); Yellow
At this point cat1
cat2
, it automatically contains a constructor
property that points to their constructor.
Alert (Cat1.constructor = = Cat); True
Alert (Cat2.constructor = = Cat); True
JavaScript also provides an instanceof
operator that validates the relationship between a prototype object and an instance object.
Alert (cat1 instanceof Cat); True
Alert (cat2 instanceof Cat); True
Four, the problem of the structure function pattern
The constructor method works well, but there is a problem of wasting memory.
See, let's add a constant Cat
property type
(kind) to the object, and add a method eat
(eat). Then the prototype object Cat
becomes the following:
function Cat (name,color) {
THIS.name = name;
This.color = color;
This.type = "Cat animal";
This.eat = function () {alert ("Eat Mouse");
}
The same approach is used to generate an instance:
var cat1 = new Cat ("Da Mao", "Yellow");
var cat2 = new Cat ("Er Mao", "Black");
alert (Cat1.type); Cat Animals
Cat1.eat (); Eat mice
There seems to be no problem on the surface, but there is a big drawback in actually doing so. That is, for each instance object, the type
properties and methods are exactly eat()
the same, and each time an instance is generated, it must be a duplicate of the content and occupy more memory. This is neither environmentally friendly nor inefficient.
Alert (cat1.eat = = cat2.eat); False
Can the type
properties and eat()
methods be generated only once in memory, and then all instances point to that memory address? The answer is yes.
Five, prototype mode
JavaScript specifies that each constructor has a prototype
property that points to another object. All properties and methods of this object are inherited by an instance of the constructor.
This means that we can define the invariant properties and methods directly prototype
on the object.
function Cat (name,color) {
THIS.name = name;
This.color = color;
}
Cat.prototype.type = "Cat animal";
Cat.prototype.eat = function () {alert ("Eat Mouse")};
Then, build the instance.
var cat1 = new Cat ("Da Mao", "Yellow");
var cat2 = new Cat ("Er Mao", "Black");
alert (Cat1.type); Cat Animals
Cat1.eat (); Eat mice
At this point, all instances of the type
properties and methods, in fact, are the eat()
same memory address, pointing prototype
to the object, thus improving the efficiency of the operation.
Alert (cat1.eat = = cat2.eat); True
Six, the verification method of prototype mode
To match prototype
the attributes, JavaScript defines some helper methods that help us to use it. ,
6.1 isprototypeof ()
This method is used to determine the proptotype
relationship between an object and an instance.
Alert (Cat.prototype.isPrototypeOf (CAT1)); True
Alert (Cat.prototype.isPrototypeOf (CAT2)); True
6.2 hasOwnProperty ()
Each instance object has a hasOwnProperty()
method that is used to determine whether a property is a local property or a property inherited from an prototype
object.
Alert (Cat1.hasownproperty ("name")); True
Alert (Cat1.hasownproperty ("type")); False
6.3 In operator
in
The operator can be used to determine whether an instance contains a property, whether it is a local property or not.
Alert ("name" in CAT1); True
Alert ("type" in CAT1); True
in
Operators can also be used to traverse all properties of an object.
For (Var prop in cat1) {alert ("cat1[" +prop+ "]=" +cat1[prop]);}
Please continue reading the second part of the series, "Inheritance of constructors" and Part III, "Inheritance of non-constructors".
Finish
JavaScript Object-oriented Programming (II): Inheritance of constructors
Nanyi
Date: May 23, 2010
The first part of the series focuses on how to "encapsulate" data and methods, and how to generate instances from prototype objects.
Today's introduction is about five ways to "inherit" between objects.
For example, there is now a constructor for an "animal" object.
function Animal () {
This.species = "Animal";
}
There is also a constructor for the "Cat" object.
function Cat (name,color) {
THIS.name = name;
This.color = color;
}
How to make "cat" Inherit "animal"?
First, constructor binding
The first method is also the simplest method, using the call or Apply method to bind the parent object's constructor to a child object, adding a line to the child object constructor:
function Cat (name,color) {
Animal.apply (this, arguments);
THIS.name = name;
This.color = color;
}
var cat1 = new Cat ("Da Mao", "Yellow");
alert (cat1.species); Animals
Second, prototype mode
The second method is more common, using the prototype property.
If the prototype object of "cat" points to an instance of animal, then all instances of "cat" can inherit animal.
Cat.prototype = new Animal ();
Cat.prototype.constructor = Cat;
var cat1 = new Cat ("Da Mao", "Yellow");
alert (cat1.species); Animals
In the first line of the code, we point the cat's prototype object to an instance of animal.
Cat.prototype = new Animal ();
It is equivalent to completely removing the original value of the prototype object and then assigning a new value. But what does the second line mean?
Cat.prototype.constructor = Cat;
It turns out that any prototype object has a constructor property that points to its constructor. If there is no "Cat.prototype = new Animal ();" In this line, Cat.prototype.constructor is pointing to Cat, and after adding this line, Cat.prototype.constructor points to animal.
Alert (Cat.prototype.constructor = = Animal); True
More importantly, each instance also has a constructor property, which calls the prototype object's constructor property by default.
Alert (Cat1.constructor = = Cat.prototype.constructor); True
Therefore, in the run "Cat.prototype = new Animal ();" After this line, Cat1.constructor also points to animal!
Alert (Cat1.constructor = = Animal); True
This obviously leads to an inheritance chain disorder (CAT1 is obviously generated with the constructor cat), so we have to manually correct the constructor value of the Cat.prototype object to Cat. This is the meaning of the second line.
This is an important point to be sure to follow when programming. This is followed by the following, that is, if you replace the prototype object,
O.prototype = {};
The next step, then, must be to add the constructor property to the new prototype object and refer to this property back to the original constructor.
O.prototype.constructor = O;
Third, direct succession prototype
The third method is the improvement of the second method. 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.
Now, we'll first rewrite the animal object:
function Animal () {}
Animal.prototype.species = "Animal";
Then, the cat's prototype object is then pointed to the animal prototype object, which completes the inheritance.
Cat.prototype = Animal.prototype;
Cat.prototype.constructor = Cat;
var cat1 = new Cat ("Da Mao", "Yellow");
alert (cat1.species); Animals
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
Iv. use of empty objects as intermediaries
Since the "Direct inheritance prototype" has the disadvantages mentioned above, there is a fourth method, using an empty object as the intermediary.
var F = function () {};
F.prototype = Animal.prototype;
Cat.prototype = new F ();
Cat.prototype.constructor = Cat;
F is an empty object, so it hardly accounts for memory. At this point, modifying the cat's prototype object does not affect the animal prototype object.
alert (Animal.prototype.constructor); Animal
We encapsulate the above method into a function that is easy to use.
function extend (child, Parent) {
var F = function () {};
F.prototype = Parent.prototype;
Child.prototype = new F ();
Child.prototype.constructor = child;
Child.uber = Parent.prototype;
}
When used, the method is as follows
Extend (Cat,animal);
var cat1 = new Cat ("Da Mao", "Yellow");
alert (cat1.species); Animals
This extend function, is how Yui Library implements the method of inheriting.
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.
V. Copy inheritance
Above is the use of prototype objects, implementation of inheritance. We can also change a way of thinking, purely using the "copy" method to achieve inheritance. Simply put, if you copy all the properties and methods of the parent object into the sub-object, can you also implement inheritance? So we have a fifth method.
First, all the invariant properties of animal are placed on its prototype object.
function Animal () {}
Animal.prototype.species = "Animal";
Then, write a function that implements the purpose of the property copy.
function Extend2 (Child, Parent) {
var p = parent.prototype;
var c = Child.prototype;
for (var i in P) {
C[i] = P[i];
}
C.uber = p;
}
This function is to copy the attributes from the parent object's prototype object to the prototype object of the child object. One by one
When used, write this:
Extend2 (Cat, Animal);
var cat1 = new Cat ("Da Mao", "Yellow");
alert (cat1.species); Animals
(This series is not finished, please read the third section, "Inheritance of non-constructors".) )
JavaScript Object-oriented programming (c): Inheritance of non-constructors
Nanyi
Date: May 24, 2010
The first part of this series describes "encapsulation", and the second section describes using constructors to implement "inheritance."
Today is the last section, which describes the implementation of "inheritance" without using constructors.
First, what is the "non-constructor" inheritance?
For example, there is now an object called "Chinese".
var Chinese = {
Nation: ' China '
};
There is also an object called "Doctor".
var Doctor ={
Career: ' Doctor '
}
How can I let "Doctor" to Inherit "Chinese", that is, how can I generate a "Chinese doctor" object?
It is important to note that both objects are ordinary objects, not constructors, and cannot be implemented using constructor methods for "inheritance."
Second, the object () method
The inventor of the JSON format, Douglas Crockford, presents an object () function that can do this.
function Object (o) {
function F () {}
F.prototype = O;
return new F ();
}
This object () function, in fact, only do one thing, is the prototype property of the object, pointing to the parent object, so that the child object and the parent object together.
When used, the first step is to create a child object based on the parent object:
var Doctor = object (Chinese);
Then, add the properties of the child object itself:
Doctor.career = ' Doctor ';
At this point, the child object has inherited the properties of the parent object.
alert (doctor.nation); China
Three, shallow copy
In addition to using the "prototype chain", there is another way of thinking: The Parent object's properties, all copied to the child object, can also implement inheritance.
The following function is making a copy:
function Extendcopy (p) {
var c = {};
for (var i in P) {
C[i] = P[i];
}
C.uber = p;
return C;
}
When used, write this:
var Doctor = extendcopy (Chinese);
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.
Four, deep copy
The so-called "deep copy" is the ability to make real-world copies of arrays and objects. Its implementation is not difficult, as long as the recursive call "shallow copy" on the line.
function Deepcopy (p, c) {
var c = C | | {};
for (var i in P) {
if (typeof p[i] = = = ' object ') {
C[i] = (P[i].constructor = = = = Array)? [] : {};
Deepcopy (P[i], c[i]);
} else {
C[i] = P[i];
}
}
return C;
}
Use this to write:
var Doctor = deepcopy (Chinese);
Now, add an attribute to the parent object, and the value is an array. Then, modify this property on the child object:
chinese.birthplaces = [' Beijing ', ' Shanghai ', ' Hong Kong '];
Doctor.birthPlaces.push (' Xiamen ');
At this point, the parent object will not be affected.
alert (doctor.birthplaces); BEIJING, Shanghai, Hong Kong, Xiamen
alert (chinese.birthplaces); BEIJING, Shanghai, Hong Kong
Currently, the jquery library is using this method of inheritance.
JavaScript Object-oriented (encapsulation, inheritance)