What's the prototype?
A Function type has a property prototype, which translates directly into a prototype. This property is a pointer to an object that contains properties and methods that are shared by all instances (objects) generated by the current function.
This sentence according to the preceding, carefully pondering down, you can get the following code:
function person () {
...
}
Person.prototype = {
country: ' In ',
sayname:function () {
...
}
}
You first create an instance person of a Function type, and then the person's method prototype is an object, and the declaration points to an object. The properties and methods inside this object are shared by instances generated by the current person function. Other words:
Person1 = new Person ();
Person2 = new Person ();
Person1 and Person2 are examples of instances of the Function type of person, which both have common attribute country and method Sayname, because they all have a pointer (__proto__) that directly points to the PERSON.P The object to which the Rototype points. However, note that __proto__ this pointer is not standard, only chrome and Firefox and other browsers themselves defined, in practice, it will not use this attribute, but as an understanding prototype to use:
As for the use of prototypes, the following will be more specific.
Creating Patterns for objects
Below, let's look at the methods and common patterns of creating objects and their pros and cons.
1. Factory mode
Like a factory, the process of creating a specific object is abstracted, using functions to encapsulate the details of creating an object with a specific interface. The code is as follows by using a function instead of a partial duplication of work:
function Createperson (name, age, Job) {
var o = new Object ();
O.name = name;
O.age = age;
O.job = job;
O.sayname = function () {
alert (this.name);
};
return o;
}
var person1 = Createperson ("Jiangshui", "All", "engineer");
This creates a person, the factory pattern solves multiple duplicate creation problems of similar objects, but does not solve object recognition problems. Simply creating an object, whether it was created from a human template or an animal template, cannot distinguish between the object's type.
2. Constructor pattern
Create a custom constructor that defines the properties and methods of the custom object type.
function person (name, age, Job) {
this.name = name;
This.age = age;
This.job = JPB;
This.sayname = function () {
alert (this.name);
}
;}; var person1 = new Person (...);
3. The difference between the constructor pattern and the factory pattern:
- There is no explicit creation of an object.
- Assign properties and methods directly to the This object.
- There is no return statement.
The person is the object of the function type, and after new, it continues to produce an object, but the newly generated object, which is passed into the function and assigned to the this pointer, becomes the property or method of the newly generated object.
constructor defaults are capitalized, and the code above executes the following steps:
- Create a new object
- Assign a constructor scope to a new object
- Executing code in a constructor
- return new Object
In such a generated instance, the default contains a constructor property that points to the constructor, for example:
Alert (Person1.constructor = = person);
So with a constructor pattern, there is a type of distinction that can identify its instance as a specific type.
In addition, the constructor is a normal function, because the new object is to be fed back, so it is invoked in new. If not, direct execution is the same as a normal function, for example, the execution of Person.sayname () pops up window.name because the function is executed under window, so this points to window.
The constructor pattern is also flawed, and the method inside the constructor pattern is recreated on each instance, so the functions of the same name on different instances are not equal. For example:
Person1.sayname = = Person2.sayname; False
That is, each object instance generated by the constructor, properties, and methods are unique and are replicated. Attributes are unique because they are different places between objects, but many of the methods and code are the same, duplicating multiple times and obviously wasting resources.
So we can put the function outside, then in the constructor, with the pointer to the function, then the generated instance, the method store is a pointer to a function, also share a function:
function person (name, age) {
this.name = name;
This.age = age;
This.sayname = Sayname;
}
function Sayname () {
alert (this.name);
}
But in this way, this function becomes a global function and is not associated with the person constructor and is not encapsulated.
Here is the prototype model.
Prototype mode
Some of the basics of prototyping have been introduced earlier. Simply put, each function has a prototype attribute, pointing to an object (a prototype object) in which a property or method can be placed. Then the instance generated by this function will have an irregular attribute (__proto__) pointing to the prototype.
From that point of view, you should be able to understand that the properties and methods generated by prototype are shared by all instances.
This solves the problem of common use of functions in the above constructor pattern. For example, the following code:
function person () {
...
}
Person.prototype.name = "Jiangshui";
Person.prototype.sayName = function () {
alert (this.name);
};
var person1 = new Person ();
Person1.sayname (); Jiangshui
Or
Person.prototype = {
Constructor:person,
name: "Jiangshui",
sayname:function () {
alert ( this.name);
}
;
The second method overrides the entire prototype object, so you need to manually specify the constructor property, which points to the constructor or points to object.
To comb their relationship:
- Person.prototype-A prototype object that can define attributes or parameters that are shared by all instances.
- Person.prototype.constructor = = person-The prototype object has a default attribute constructor point to the constructor to which the prototype object belongs (Note that another method overrides this property and needs to be specified again).
- Person1 = new Person ()-constructor generates an instance that contains the contents of the constructor and the contents of the prototype object.
- Person1.__proto__-"point to the prototype object that created this instance (not canonical, not used)."
Use isPrototypeOf () to determine the relationship between objects. For example:
Person.prototype.isPrototypeOf (Person1);
A search is performed when the code reads a property of an object. Starts with the current object, and if not, searches for the prototype object that the pointer points to without searching for the constructor. Object instances can access but cannot override the values of a prototype object. If a property with the same name as a prototype object is set in the instance, the search process ends in the instance without accessing the prototype object, so the overriding purpose is achieved. Therefore, even if this property is set to NULL, it means that the property already exists in the instance, without canceling the property, so that the prototype corresponding property can be accessed.
So you need to use the delete operator to completely remove the instance properties so that you can access the prototype again.
The prototype is dynamic, and any modifications made to the prototype object are immediately reflected from the instance. The reason is the loose link between the instance and the prototype, and each time the property method of the instance is invoked, a query is made, and if the prototype changes, the query result is changed.
After we understand the prototype, we can also add new methods or properties to the native object. Native reference types such as Object, Array, String, and similar to the constructor above, we can extend their methods with prototype. For example:
String.prototype.startsWith = function (text) {return
this.indexof (text) = 0;
};
var msg = "Hello World";
Msg.startswith ("Hello");
This code, which is the native reference type of string, adds a StartsWith method, and the function is to pass in a parameter to see if the string being tested starts with a parameter. Because of the dynamic nature of the prototype, all string-type variables have been obtained with this method as long as they are executed.
But this method is not recommended, if used too much, too much code, will cause maintenance difficulties, code confusion and so on. In general, a native reference type is inherited before it is created on a newly custom type. About inheritance, which is summarized later.
The prototype model is not omnipotent, and all the properties and methods in the prototype are shared by all instances, so it is appropriate for the function, and some conflicts occur for attributes that contain reference types. For example:
function person () {}
Person.prototype = {
Constructor:person,
friends: ["Greg", "Jack"]
};
var person1 = new Person ();
var person2 = new Person ();
Person1.friends.push ("Tom");
Console.log (Person2.friends);
You will see in the console that Person2 's friends is one more Tom, which is not what I wanted, but for Person1 to define his friends, it did affect the example Person2.
So we're going to use the stereotype pattern and the constructor pattern.
Combining constructor patterns with prototype patterns
This is the most commonly used pattern, which is used to define instance properties, to implement customizations by passing parameters, to define methods, or to require properties shared by all instances. In this way, both the customization and the sharing are ensured, and the problem is avoided.
function person (name, age, Job) {
this.name = name;
This.age = age;
This.job = job;
This.friends = ["Greg", "Jack"];
}
Person.prototype = {
Constructor:person,
sayname:function () {
alert (this.name);
}
};
var Jiangshui = new Person ("Jiangshui", "the", "engineer");
Actual application examples
OK, when you get here, you'll probably understand what the prototype is and how to create it, but what's the use of that? Indeed, my previous work, has been to use JQuery to write some code, it can not use the encapsulation and then generate object implementation functions. What's the use of these?
This development method is mainly used for modularization and the development of the Organization. For example, you often use the window function, you can of course the window on the code, paste copy each time, and then modify it can be used in the project. A better choice is to put your window-function code, abstracted into such a component, so that when you need to use the window, only pass parameters to generate a window instance, you can call.
Prototype object and prototype chain
In JavaScript, everything is an object, but there are also differences between objects, which can be roughly divided into two categories: ordinary Objects (object) and Function objects (functions).
In general, the object generated by the new function is the function object, and the other objects are ordinary objects.
An example is provided:
Function F1 () {
//todo
}
var F2 = function () {
//todo
};
var F3 = new Function (' x ', ' Console.log (x) ');
var O1 = {};
var O2 = new Object ();
var O3 = new F1 ();
Console.log (
typeof f1,//function
typeof f2,//function
typeof f3,//function
typeof O1,//object
typeof O2,//object
typeof O3//object
);
>> function function is Object object
F1 is a function of the declaration, the most common way to define the function, F2 is actually an anonymous function, the anonymous function assigned to the F2, belong to the function expression, F3 uncommon, but also a function object.
Function is the object of JS, f1,f2 when created, JS automatically through the new function () the way to build these objects, so the three objects are created by the new function ().
There are two ways to create objects in JavaScript: Object literals and the use of new expressions, the creation of O1 and O2 corresponds to the two ways, focusing on the O3, if understood in Java and C #, O3 is the F1 instance object, O3 and F1 are the same type, At least I used to think so.
So how do you understand it? It's easy to see if O3 is created by the new function, obviously not, since it's not a function object, it's a normal object.
With a simple understanding of the function object and the normal object, let's take a look at the prototype and prototype chain in javascript:
In JS, when you create a function object F1, some properties are built into the object, including prototype and __PROTO__, prototype the prototype object, which records some of the F1 properties and methods.
It should be noted that prototype is not visible to F1, that is, F1 does not look for properties and methods in prototype.
function f () {}
F.prototype.foo = "abc";
Console.log (F.foo); Undefined
So, what's the use of prototype? In fact, the main role of prototype is to inherit. In layman's terms, the properties and methods defined in prototype are reserved for their descendants, so subclasses can fully access the properties and methods in prototype.
Want to know how F1 left prototype to "offspring", we need to understand JS in the prototype chain, at this time, JS in the __proto__ admission, this guy is very strange, hidden also very deep, so that you often see it, but it in the ordinary objects and function objects exist, Its role is to save the prototype object of the parent class, JS in the new expression to create an object, usually the parent class prototype assigned to the new object of the __proto__ attributes, so that the formation of a generation of inheritance ...
function f () {}
F.prototype.foo = "abc";
var obj = new F ();
Console.log (Obj.foo); Abc
Now we know that the __proto__ in obj is the prototype of F, so what is stored in the __proto__ of the prototype of F? Look at the picture below:
As shown in the figure, the __proto__ in the F.prototype contains __proto__ in the Object.prototype,object.prototype object, and from the output view, object.prototype.__ PROTO__ is null, representing the end of the Obj object prototype chain. As shown in the following illustration:
The Obj object has such a prototype chain, and when Obj.foo executes, obj finds out if it has the attribute, but does not find its own prototype, and when Foo is not found, obj looks in sequence along the prototype chain ...
In the above example, we defined the Foo attribute on the prototype of F, at which point obj would find the attribute and execute it on the prototype chain.