The concept of prototype in JavaScript aptly reflects the meaning of the word, and we cannot interpret it as a prototype concept of C + +.
All of the function-type objects of JavaScript have a prototype attribute. The prototype property itself is an object type, so we can also add arbitrary properties and methods to the prototype object. Since prototype is the "archetype" of an object, the object constructed by the function should have the "archetype" attribute. In fact, all the properties and methods defined on the prototype of the constructor are directly accessible and invoked through the objects it constructs. It is also possible to say that prototype provides a mechanism for sharing properties and methods for a group of similar objects.
Let's take a look at the following code:
function person (name)
{
THIS.name = name; Set object properties, each object a property data
};
Person.prototype.SayHello = function ()//To add the SayHello method to the prototype of the person function.
{
Alert ("Hello, I ' m" + this.name);
}
var billgates = new Person ("Bill Gates"); Creating BillGates Objects
var stevejobs = new Person ("Steve Jobs"); Creating Stevejobs Objects
Billgates.sayhello (); Called directly to the SayHello method via the BillGates object
Stevejobs.sayhello (); Called directly to the SayHello method via the Stevejobs object
Alert (Billgates.sayhello = = Stevejobs.sayhello); Because two objects are sayhello of shared prototype, display: TRUE
The results of the program's operation indicate that the method defined on the prototype of the constructor can indeed be called directly through the object, and that the code is shared. Obviously, the way to set the method to prototype is more elegant, although the form of the call has not changed, but the logic reflects the relationship between methods and classes, relative to the previous wording, easier to understand and organize the code.
So what about the constructors for the multi-level types?
Let's take another look at the following code:
1 function person (name)//base class constructor
2 {
3 this.name = name;
4};
5
6 Person.prototype.SayHello = function ()//prototype Add method to the base class constructor
7 {
8 Alert ("Hello, I ' m" + this.name);
9};
10
One function Employee (name, salary)//subclass Constructor
12 {
Person.call (this, name); Call base class constructor
This.salary = salary;
15};
16
Employee.prototype = new Person (); It's interesting to build a base class object as a prototype of a subclass prototype.
18
Employee.prototype.ShowMeTheMoney = function ()//prototype Add method to subclass constructor
20 {
Alert (THIS.name + "$" + this.salary);
22};
23
var billgates = new Person ("Bill Gates"); Create a BillGates object for the base class person
var stevejobs = new Employee ("Steve Jobs", 1234); To create a Stevejobs object for child class employee
26
Billgates.sayhello (); A method called directly to prototype through an object
Stevejobs.sayhello (); Call the base class prototype method directly through the subclass object, pay attention!
Stevejobs.showmethemoney (); A method of directly calling subclass prototype by subclass Object
30
To alert (Billgates.sayhello = = Stevejobs.sayhello); Display: True to indicate that the method of prototype is shared
The 17th line of the code, which constructs a base class object and sets it to the prototype of the subclass constructor, is interesting. The purpose of this is to line 28th, which can also invoke the method of the base class prototype directly through the subclass object. Why is this possible?
It turns out that in JavaScript, prototype not only allows objects to share their wealth, but prototype also have the instinct to ask their ancestors, so that their legacy can be inherited from generation to generations. When you read a property from an object or call a method, if the object itself does not exist such a property or method, it will go to its own associated prototype object to look for, if prototype not, will go to prototype their associated predecessors prototype there, Until it is found or traced back to the end of the process.
Within JavaScript, the object's properties and method traceability mechanisms are implemented through so-called prototype chains. When an object is constructed with the new operator, the prototype object of the constructor is also assigned to the newly created object and becomes the prototype object built into the object. The prototype object built into the object should be externally invisible, although some browsers (such as Firefox) can let us access the built-in prototype object, but this is not recommended. The built-in prototype object itself is also an object and has its own associated prototype object, thus forming the so-called prototype chain.
At the very end of the prototype chain is the prototype object that the object constructor prototype attribute points to. This archetypal object is the oldest ancestor of all objects, and this ancestor realizes the innate method of all objects such as ToString. Other built-in constructors, such as function, Boolean, String, date, and RegExp, are inherited from this ancestor, but they each define their own attributes and methods, so that their descendants show those characteristics of their respective clans.
Isn't that "inheritance"? Yes, this is "inheritance", a JavaScript-specific "prototype inheritance."
"Archetype inheritance" is kind and stern. The archetypal object has selflessly contributed to the children's use of their own attributes and methods, and does not compel them to obey them, allowing some naughty children to act independently of their interests and hobbies. From this point of view, the prototype object is a kindly mother. However, although any child can go his own way, he cannot move the property of the archetypal object, because it may affect the interests of other children. From this point of view, the archetypal object is like a stern father. Let's take a look at the following code to understand the meaning:
function person (name)
{
THIS.name = name;
};
Person.prototype.company = "Microsoft"; Properties of the prototype
Person.prototype.SayHello = function ()//prototype method
{
Alert ("Hello, I ' m" + this.name + "of" + This.company);
};
var billgates = new Person ("Bill Gates");
Billgates.sayhello (); As the thing that inherits the prototype, the orderly output: Hello, I ' m Bill Gates
var stevejobs = new Person ("Steve Jobs");
Stevejobs.company = "Apple"; Set up your own company attribute to obscure the company attribute of the prototype
Stevejobs.sayhello = function ()//implements its own SayHello method, masking the SayHello method of the prototype
{
Alert ("Hi," + THIS.name + "like" + This.company + ", ha ha Ha");
};
Stevejobs.sayhello (); Are the properties and methods of their own coverage, output: Hi, Steve Jobs like Apple, ha ha ha
Billgates.sayhello (); The stevejobs overlay does not affect the prototype object, and BillGates is still exported as usual.
Objects can obscure the properties and methods of the prototype object, and a constructor prototype object can conceal the existing properties and methods of the upper constructor prototype object. The cover-up is simply creating new properties and methods on the object itself, except that these attributes and methods have the same name as those of the prototype object. JavaScript is to use this simple masking mechanism to achieve the object "polymorphism", and static object language virtual function and overload (override) concept coincide.
However, what is more magical than static object language is that we can dynamically add new properties and methods to the prototype object, thus dynamically extending the functional characteristics of the base class. This is hard to imagine in the static object language. Let's look at the following code:
function person (name)
{
THIS.name = name;
};
Person.prototype.SayHello = function ()/the method defined before the object is established
{
Alert ("Hello, I ' m" + this.name);
};
var billgates = new Person ("Bill Gates"); Building objects
Billgates.sayhello ();
Person.prototype.Retire = function ()//the method of dynamically extending the prototype after establishing the object
{
Alert ("Poor" + THIS.name + ", bye bye!");
};
Billgates.retire (); Dynamically extended methods can be immediately invoked by the previously established object
Ami, archetypal inheritance can play with such spells!
Prototype extension
Presumably, you would think that if you add new methods and properties to the prototype of functions such as object and function, which are built into JavaScript, can you extend the functionality of JavaScript?
Well, congratulations, you got it!
With the rapid development of Ajax technology, the JavaScript runtime of many successful AJAX projects has expanded the prototype function of the built-in functions massively. Microsoft's ASP.net AJAX, for example, adds a lot of new features to these built-in functions and their prototype, which enhances the functionality of JavaScript.
Let's take a look at the code excerpt from MicrosoftAjax.debug.js:
String.prototype.trim = function String$trim () {
if (arguments.length!== 0) throw Error.parameterCount ();
Return This.replace (/^\s+|\s+$/g, "");
}
This code extends a trim method to the prototype of the built-in string function, so all the string objects have the trim method. With this extension, the future to remove the two paragraphs of white space, you do not have to deal with separately, because any string has this extension function, as long as the call can be really convenient.
Of course, very few people are going to add a method to the object's prototype, because that affects all objects, unless in your architecture this method is indeed required by all objects.
In the first two years, Microsoft used a technology called "closures" (closure) to simulate "classes" in the early stages of designing an Ajax class library. The approximate model is as follows:
function person (firstName, lastName, age)
{
Private variable:
var _firstname = FirstName;
var _lastname = LastName;
Public variables:
This.age = age;
Method:
This.getname = function ()
{
Return (FirstName + "" + lastName);
};
This. SayHello = function ()
{
Alert ("Hello, I ' m" + firstName + "" + lastName);
};
};
var billgates = new Person ("Bill", "Gates", 53);
var stevejobs = new Person ("Steve", "Jobs", 53);
Billgates.sayhello ();
Stevejobs.sayhello ();
Alert (Billgates.getname () + "" + billgates.age);
alert (billgates.firstname); Private variables cannot be accessed here
Obviously, the class description of this model is particularly elegant as the description of the C # language, which in turn defines private members, public properties, and available methods in a constructor. In particular, the "closure" mechanism can simulate the protection of private members of the mechanism, do very beautiful.
The so-called "closure" is defined as a method function in the constructor body that defines another function as the target object, and the method function of the object in turn refers to the temporary variable in the outer outer function body. This makes it possible to indirectly maintain the value of the temporary variables used by the original constructor body as long as the target object retains its method throughout its lifetime. Although the first constructor call has ended, the name of the temporary variable disappears, but the value of the variable is always referenced within the target object's method, and the value can only be accessed through this method. Even if you call the same constructor again, but only new objects and methods are generated, the new temporary variable only corresponds to the new value, and the last time the call was separate. Very ingenious indeed!
But as we've said before, it's a huge waste to set up a method for each object. Also, the mechanism of "closure", which indirectly retains variable values, often creates problems for Javasript's garbage collector. Especially when the complex circular references between objects are encountered, the judgment logic of garbage collection is very complicated. Coincidentally, earlier versions of IE browsers did have a memory leak problem with javasript garbage collection. Coupled with the "closure" model in performance testing poor performance, Microsoft finally abandoned the "closure" model, and instead of "prototype" model. It is the so-called "gain must be lost."
The prototype model requires a constructor to define the members of the object, but the method is attached to the constructor's prototype. The general wording is as follows:
Defining constructors
function person (name)
{
THIS.name = name; To define a member in a constructor
};
method is defined on the prototype of the constructor
Person.prototype.SayHello = function ()
{
Alert ("Hello, I ' m" + this.name);
};
Child class constructor
function Employee (name, salary)
{
Person.call (this, name); Calling the top-level constructor
This.salary = salary; Extended Members
};
The subclass constructor first needs to use the upper constructor to establish the prototype object and implement the concept of inheritance.
Employee.prototype = new Person ()//only needs its prototype method, the members of this object have no meaning!
The subclass method is also defined above the constructor
Employee.prototype.ShowMeTheMoney = function ()
{
Alert (THIS.name + "$" + this.salary);
};
var billgates = new Person ("Bill Gates");
Billgates.sayhello ();
var stevejobs = new Employee ("Steve Jobs", 1234);
Stevejobs.sayhello ();
Stevejobs.showmethemoney ();
Although the prototype class model can not simulate the real private variables, but also to define the class in two parts, it appears not "elegant". However, the methods between objects are shared, do not encounter garbage collection issues, and performance is superior to the "closure" model. The so-called "there is a loss will be a win."
In the prototype model, in order to implement class inheritance, you must first set the prototype of the subclass constructor to an object instance of a parent class. The purpose of creating this parent object instance is to form a prototype chain that acts as a shared upper-level prototyping method. However, when this instance object is created, the upper constructor also sets the object members to it, which is meaningless for inheritance. Although we did not pass arguments to the constructor, we did create a few useless members, even though the value is undefined, which is a waste.
Alas! There is no perfect thing in the world!
The essence of a prototype
Just as we feel, a red light flashed through the sky, and the goddess of Guanyin appeared in the Xiangyun. I saw her holding jade net bottle, brushed cui willow branches, sprinkle a few drops of dew, immediately let JavaScript add new aura.
The nectar of Guanyin is condensed into a block in the JavaScript world, becoming a kind of thing called "the Nectar of the grammar". This kind of syntax nectar allows us to write code that looks more like an object language.
If you want to know what this "grammatical nectar" is, please listen carefully.
Before we understand the nectar of these grammars, we need to revisit the process of JavaScript construction objects.
We already know that the process of creating an object in the form of var anobject = new Afunction () can actually be divided into three steps: The first step is to create a new object; the second step is to set the prototype object built into the object as the prototype object that the constructor prototype references The third step is to call the constructor as the This parameter, complete the initialization of the member settings, and so on. After an object is established, any access and operation on the object is related only to the object itself and the string of objects on its prototype chain, which is not related to the constructor. In other words, the constructor only acts as an introduction to the prototype object and the initialization object in the creation of the object two.
So can we define an object ourselves as a prototype, describe the class on the prototype, and then set the stereotype to the newly created object as the object's class? Can we use a method in this prototype as a constructor to initialize the new object? For example, we define such a prototype object:
var person =//Define an object as a prototype class
{
Create:function (name, age)//This when constructor
{
THIS.name = name;
This.age = age;
},
Sayhello:function ()//Definition method
{
Alert ("Hello, I ' m" + this.name);
},
Howold:function ()//Definition method
{
Alert (THIS.name + "is" + This.age + "years old.");
}
};
How this JSON form is written is like a C # Class! There are both constructors and various methods. If you could create an object in some form and set the built-in prototype of the object to the "Class" object above, wouldn't it be equivalent to creating an object of that class?
Unfortunately, we can hardly access the prototype properties built into the object! Although some browsers have access to the built-in prototypes of objects, doing so can only limit the browsers that users must use. This is hardly a good line to be.
So, can we use a function object to do the media, using the function object's prototype attribute to relay this prototype, and the new operator to pass to the newly created object?
In fact, code like this can achieve this goal:
function Anyfunc () {}; Define a function shell
Anyfunc.prototype = person; Put the prototype object into the staging prototype
var billgates = new Anyfunc (); The built-in prototype for the new object will be the prototype object we expect
However, the Anyfunc function is just a shell, and it becomes superfluous after it has been used, and it's no different from using the constructor directly to create the object.
However, if we write the code as a generic function, and that function shell becomes a function within the function, does the intrinsic function automatically die out after the outer function exits the scope? Also, we can take the prototype object as a generic function parameter, and let the generic function return the object that was created. All we need is the following form:
function New (AClass, Aparams)//Universal creation functions
{
function New_ ()//definition of temporary relay functions Shell
{
AClass.Create.apply (this, aparams); Invoke the constructor defined in the prototype, relay the construction logic and construct the parameters
};
New_.prototype = AClass; Preparing to relay prototype objects
return new New_ (); Returns the object that was eventually established
};
var person =//defined class
{
Create:function (name, age)
{
THIS.name = name;
This.age = age;
},
Sayhello:function ()
{
Alert ("Hello, I ' m" + this.name);
},
Howold:function ()
{
Alert (THIS.name + "is" + This.age + "years old.");
}
};
var billgates = New (person, ["Bill Gates", 53]); Call a common function to create an object and pass the construction parameter as an array
Billgates.sayhello ();
Billgates.howold ();
Alert (Billgates.constructor = = Object); Output: True
Here's a generic function new () is a "grammar nectar"! This grammatical nectar not only relays the prototype object, but also relays the constructor logic and construction parameters.
Interestingly, the temporary New_ function object is automatically freed each time the object is created to exit the new function scope. Because the prototype property of New_ is set to the new prototype object, the reference chain has been unwrapped between the original prototype object and the New_, and the temporary function and its original prototype object will be properly recycled. The last sentence of the above code proves that the constructor property of the newly created object returns the Object function. In fact, the new object itself and its prototype does not have the constructor attribute, that returns only the topmost prototype object's constructor, that is, object.
With the new syntax nectar, the definition of a class is much like that of the static object language of C #, and how quiet and elegant the code looks!
Of course, this code only shows the concept of "the Nectar of grammar". We need some more syntax nectar to achieve a simple and elegant code writing class hierarchy and its inheritance relationship. Well, let's look at a richer example:
The nectar of the grammar:
The var object =//Defines the lowercase object base class, which is used to implement the most basic methods, etc.
{
Isa:function (Atype)//A basic method of determining the relationship between classes and classes and between objects and classes
{
var self = this;
while (self)
{
if (self = = atype)
return true;
Self = self. Type;
};
return false;
}
};
function Class (Abaseclass, Aclassdefine)//Create class functions for declaring classes and inheritance relationships
{
function Class_ ()///create temporary functions Shell for class
{
This. Type = Abaseclass; We give each class A type attribute that references its inherited class
For (var member in Aclassdefine)
This[member] = Aclassdefine[member]; Copy all definitions of a class to the currently created class
};
Class_.prototype = Abaseclass;
return new Class_ ();
};
function New (AClass, Aparams)//Create object functions for object creation of any class
{
function New_ ()///create temporary functions shell of object
{
This. Type = AClass; We also give each object a type attribute that allows access to the class to which the object belongs
if (aclass.create)
AClass.Create.apply (this, aparams); We agreed that all classes of constructors are called create, which is similar to Delphi
};
New_.prototype = AClass;
return new New_ ();
};
The application effect of the grammar dew:
var person = Class (object,//derived to the object base class
{
Create:function (name, age)
{
THIS.name = name;
This.age = age;
},
Sayhello:function ()
{
Alert ("Hello, I ' m" + THIS.name + "," + This.age + "years old.");
}
});
is the var Employee = Class (person,//) derived to the person class, similar to the generic object language?
{
Create:function (name, age, salary)
{
Person.Create.call (this, name, age); Calling the constructor of a base class
This.salary = salary;
},
Showmethemoney:function ()
{
Alert (THIS.name + "$" + this.salary);
}
});
var billgates = New (person, ["Bill Gates", 53]);
var stevejobs = New (Employee, ["Steve Jobs", 53, 1234]);
Billgates.sayhello ();
Stevejobs.sayhello ();
Stevejobs.showmethemoney ();
var Littlebill = New (Billgates.type, ["Little Bill", 6]); Create a Littlebill based on the type of billgate
Littlebill.sayhello ();
Alert (Billgates.isa (person)); True
Alert (Billgates.isa (Employee)); False
Alert (Stevejobs.isa (person)); True
Alert (Person.isa (Employee)); False
Alert (Employee.isa (person)); True
"Grammar dew" does not need too much, as long as a little bit, can change the readability and fluency of the entire code, so that the code looks more elegant. With these grammar nectar, JavaScript is very much like the General object language, the writing code feel much better!
Happily, the JavaScript programs that are nourished by these nectar are more efficient. Because there is no useful object-level members in its prototype object, and there is no constructor attribute body, there is less association with the constructor function, but the method is still shared. This gives JavaScript a lot less time to trace back to the prototype chain and search properties and methods.
Let's call this form the "Nectar model"! In fact, this "nectar model" of the prototype usage is consistent with the prototype concept of the original meaning of the JavaScript prototype!
Presumably Microsoft's design AJAX architecture engineers see this dew model, must regret not earlier to move the Ajax department from the United States to our China Guanyin Temple, missed the Guanyin Bodhisattva's attunement. Of course, we can only be in the code example, Bill Gates as an object to play, really let him give up God to convert to my Buddha is certainly not easy, the opportunity has not come ah! If one day you in Microsoft's new Ajax class library to see this mannose model, that is the true fate!
The Joy of programming
In the rapid development of the software industry today, a variety of programming languages emerge, the emergence of new languages, the evolution of the old language, seems to have dazzled us. In order to adapt to the trend of object-oriented programming, JavaScript language is also in the direction of fully object-oriented, the new JavaScript standards have expanded the semantics of many new object-oriented elements. In contrast, many static object languages are also being developed in a concise and elegant way to JavaScript. For example, the new version of the C # language absorbs simple representations like JSON, as well as some other forms of JavaScript features.
We should see that with the development and popularization of RIA (strong interconnection applications), Ajax technology will gradually fade out of the lake, JavaScript will eventually disappear or evolve into other forms of language. However, no matter how the programming language evolves and evolves, the world of programming will always keep infinite vitality in the countless entanglement of "data" and "code". As long as we can see through this, we can easily learn and understand the various new things in the software world. Whether it's already familiar with procedural programming, evolving functional programming, and large-scale parallel programming of quantum entanglement in the future, we have enough mana to solve all the complex problems.
The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion;
products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the
content of the page makes you feel confusing, please write us an email, we will handle the problem
within 5 days after receiving your email.
If you find any instances of plagiarism from the community, please send an email to:
info-contact@alibabacloud.com
and provide relevant evidence. A staff member will contact you within 5 working days.