The source of this article: "Object-oriented JavaScript" by Stoyan Stefanov
Source: Original translation of red Shi Junyu
Copyright Disclaimer: If you are the original author of the original text and do not want this article to be published, you can contact the author to delete it. This translation is compiled by Shi Junyu , you can use it for learning purposes, but it is forbidden to reprint .
Fifth prototype model (PROTOTYPE)
In this section you will learn to use the prototype properties in the function object. Understanding the workings of prototype is an important part of JavaScript's learning process. After all, JavaScript is categorized as a language based on the prototype model object model. In fact, the prototype model is not difficult, but it is a new concept and often takes some time to understand. It's part of JavaScript (closures are another part), and once you "get" them, they become easy to understand and meaningful. In the remainder of this book, it is strongly recommended that you try these examples more than a dozen. That would make it easier to learn and remember these ideas.
The following topics are discussed in this chapter:
- Each function has a prototype property, and it contains an object.
- Adds an attribute to prototype.
- Use the attributes that are added to the prototype.
- The difference between the function's own properties and the prototype properties .
- Each object is saved in a private link in the prototype- __proto__-.
- Method: isPrototypeOf() hasOwnProperty(),, propertyIsEnumerable().
- How to strengthen built-in objects, such as arrays (array) and Strings (string).
Prototype properties
Functions in JavaScript are objects, and methods and properties are included. Include some of our common methods, like,apply()call()etc., common attributes, likelength,constructoretc. There is one more attributeprototype.
Once you have defined a simple functionfoo(), you can directly access the properties of the function like any other object:
>>> function foo(a, b){return a * b;}
>>> foo.length
2
>>> foo.constructor
Function()
prototypeThis property is created when you define a function. His initial value is an empty object.
>>> typeof foo.prototype
"object"
You can use properties and methods to augment this empty object. They do notfoo()have any effect on the function itself. They will only be used when you are using itfoo()as a constructor.
Adding methods and properties using prototype mode
In the previous chapters, you have learned how to define a constructor to use when building a new object. The main idea is to access the variable when called in the function,newthiswhich contains the object returned by the build function. Expansion (Add methods and properties)thisobjects are a way to add functionality when an object is created.
Let's take a look at an example,Gadget()using the constructor method tothisadd two properties and a method to the object it creates.
function Gadget(name, color){
this.name = name;
this.color = color;
this.whatAreYou = function(){
return ‘I am a ‘ + this.color + ‘ ‘ + this.name;
}
}
prototypeadding methods and properties to a constructor is another way to add functionality to an object when the object is created. Next, add two propertiespriceandratingagetInfo()method. Becauseprototypeit contains an object, you can add it like this:
Gadget.prototype.price = 100;
Gadget.prototype.rating = 3;
Gadget.prototype.getInfo = function(){
return ‘Rating: ‘ + this.rating + ‘, Price: ‘ + this.price;
};
You can also achieve the same goal in another way by completely overwriting the prototype attribute and replacing it with the object of your choice:
Gadget.prototype = {
price: 100,
rating: 3,
getInfo: function() {
return `Rating: ` + this.rating + ‘, Price:‘ + this.price;
}
};
Methods and properties for using prototype properties
All of the methods and properties that you add to the constructor's prototype property are directly available after you have constructed the new object using this constructor. For example, if you use theGadget()build function to create annewtoyobject, you can directly access all the methods and properties that have been defined.
>>> var newtoy = new Gadget(‘webcam‘, ‘black‘);
>>> newtoy.name;
"webcam"
>>> newtoy.color;
"black"
>>> newtoy.whatAreYou();
"I am a black webcam"
>>> newtoy.price;
100
>>> newtoy.rating;
3
>>> newtoy.getInfo();
"Rating:3, Price: 100"
It is important to note that the prototype attribute is "live" and that the object is passed through a reference in JavaScript. For this reason, the prototype type is not copied directly into the new object. What does that mean? This means that we can modify the prototype properties of any object at any time (even if you can modify it after you create the object), and they are all in effect.
Let's continue to look at an example, adding the following method to the prototype attribute:
Gadget.prototype.get = function(what){
return this[what];
};
Although weget()have already generated the object before defining the methodnewtoy, wenewtoycan still access the new method:
>>> newtoy.get(‘price‘);
100
>>> newtoy.get(‘color‘);
"black"
Comparison of "function itself property" and "Prototype attribute"
In thegetInfo()example above, it is usedthisto point from the inside to the object itself, whichGadget.prototypecan be used to achieve the same purpose:
Gadget.prototype.getInfo = function(){
return ‘Rating: ‘ + Gadget.prototype.rating + ‘, Price: ‘ + Gadget.prototype.price;
};
What's so different about that? Before you answer this question, let's test it to see how the prototype properties work.
Let's take ournewtoyobject again:
>>> var newtoy = new Gadget(‘webcam‘, ‘black‘);
When you try to accessnewtoya property that uses an expressionnewtoy.name, the JavaScript engine will browse through all the properties of the object, look for a callname, and if it finds it, its value will be returned.
>>> newtoy.name‘webcam‘
What the? Do you want to try to access theratingproperties? The JavaScript engine checksnewtoyall the properties in, and then does not find a callrating. The scripting engine then identifies that the prototype property in the constructor has tried to create the object (as you used itnewtoy.constructor.prototype). If the attribute is found in the prototype attribute, the attribute in the prototype attribute is used.
>>> newtoy.rating3
This is the same as your direct access to the prototype properties. Each object has a property of a constructor, which is a reference to the constructor used to create the object. So, in this case:
>>> newtoy.constructor
Gadget(name, color)
>>> newtoy.constructor.prototype.rating
3
Now, let's take a look at the first step, where each object has a constructor. The prototype property is an object, so it should also have a constructor. And then its constructor has a prototype property ...
>>> newtoy.constructor.prototype.constructor
Gadget(name, color)
>>> newtoy.constructor.prototype.constructor.prototype
Object price=100 rating=3
This cycle will continue, depending on how long the stereotype's attribute chain is. But in the end, it ends up in a built-inObject()object. It is the outermost parent class. In this case, if you try to usenewtoy.toString()it, andnewtoyhe doesn't have a method of his own,toString()and it doesn't have a prototype Property object, he will always look up and end up calling the object'stoString()method.
>>> newtoy.toString()
"[object Object]"
Overriding the properties of a prototype property by using the properties of the function itself
As shown above, if your object does not have an exact property of its own, you can use an object on the upper level of a prototype chain. If the object and the prototype attribute have properties with the same name, their properties will be used preferentially.
Next, let's simulate an attribute that exists both in its own property and in its prototype properties:
function Gadget(name){
this.name = name;
}
>>> Gadget.prototype.name = ‘foo‘;
"foo"
Create a new object, access itsnameproperties, and it will give you the properties of the object itselfname.
>>> var toy = new Gadget(‘camera‘);
>>> toy.name;
"camera"
If you delete this attribute, then the attribute with the same name in the prototype attribute will "show":
>>> delete toy.name;
true
>>> toy.name;
"foo"
Of course, you can recreate its own properties:
>>> toy.name = ‘camera‘;
>>> toy.name;
"camera"
Traverse Properties
If you want to list all the properties of an object, you can use afor-inloop. In the second section, you learned how to iterate through all the elements in an array:
var a = [1, 2, 3];
for (var i in a)
{
console.log(a[i]);
}
An array is an object, so you can deducefor-inthe time to traverse the object:
var o = {p1: 1, p2: 2};
for (var i in o) {
console.log(i + ‘=‘ + o[i]);
}
This will produce:
p1=1p2=2
A few details to know:
- Not all properties are displayed in thefor-inloop. For example, arrayslength, andconstructorattributes, are not displayed. The properties that are displayed are called Enumerable . You can use the methods that each object can providepropertyIsEnumerable()to check whether a property is enumerable.
- The prototype attribute in the prototype chain is also displayed if it is enumerable. You can usehasOwnProperty()methods to check whether a property is a property of itself or a prototype property.
- propertyIsEnumerable()will return the properties in all prototype propertiesfalse, although they will appear in thefor-inloop and are enumerable.
To see the effects of these functions, we use a simplified version ofGadget():
function Gadget(name, color)
{
this.name = name;
this.color = color;
this.someMethod = function(){
return 1;
}
}
Gadget.prototype.price = 100;
Gadget.prototype.rating = 3;
To create a new object:
var newtoy = new Gadget(‘webcam‘, ‘black‘);
If you usefor-inloops, you can see all the properties of the object, including those of the prototype properties:
for (var prop in newtoy){
console.log(prop + ‘ = ‘ + newtoy[prop];
}
This result also contains the method of the object (that is because the method is the exact type of the function's property):
name = webcam
color = black
someMethod = function(){ return 1;}
price = 100
rating = 3
If you want to differentiate between the properties of an object's own properties and the properties of a prototype property, usehasOwnProperty()this:
>>> newtoy.hasOwnProperty(‘name‘)
true
>>> newtoy.hasOwnProperty(‘price‘)
false
Let's loop it again, but this time it only shows its own properties:
for (var prop in newtoy){
if (newtoy.hasOwnProperty(prop)){
console.log(prop + ‘=‘ + newtoy[prop]);
}
}
Results:
name=webcamcolor=blacksomeMethod=function(){return 1;}
Let's try it nextpropertyIsEnumerable(). If the property is not a built-in property, the function returnstrue:
>>> newtoy.propertyIsEnumerable(‘name‘)
true
>>> newtoy.propertyIsEnumerable(‘constructor‘)
false
Any attributes that are from the prototype chain are not enumerable:
>>> newtoy.propertyIsEnumerable(‘price‘)false
Note that although if you get the object contained in the prototype property and call itpropertyIsEnumerable(), this property can be enumerated.
>>> newtoy.constructor.prototype.propertyIsEnumberable(‘price‘)true
isPrototypeOf()
Each object has aisPrototypeOf()method. This method will tell you who is the prototype property of the specified object.
Let's start by writing a simple objectmonkey:
var monkey = {
hair: true,
feeds: ‘bananas‘,
breathes: ‘air‘
};
Next, let's create aHuman()constructor and then set its properties toprototypepoint tomonkey.
function Human(name){
this.name = name;
}
Human.prototype = monkey;
If you create an object calledgeorgeHuman, then ask it: "monkeyisgeorgethe prototype attribute?" "And you'll get ittrue."
>>> var george = new Human(‘George‘);
>>> monkey.isPrototypeOf(george)
true
Secret of__proto__Link
As you know, when you try to access a property that does not exist with the current object, it queries the properties of the prototype property.
Let's continue usingmonkeythe object asHuman()the prototype property of the constructor.
var monkey = {
feeds: ‘bananas‘,
breathes: ‘air‘
};
function Human() {}
Human.prototype = monkey;
Next, create andeveloperobject and give him some properties:
var developer = new Human();
developer.feeds = ‘pizza‘;
developer.hacks = ‘JavaScript‘;
Now, let's make some inquiries.hacksisdeveloperthe property of:
>>> developer.hacks"JavaScript"
feedsCan be found in the object:
>>> developer.feeds"pizza"
breathesDoes not existdeveloperin the object, because there is a secret link to the prototype type object, the prototype type is found instead.
>>> developer.breathes"air"
Can youdeveloperget the prototype Property object from the object? Sure, you can. Usedconstructoras an intermediate object, just likedeveloper.constructor.prototypepointingmonkey. But it's not very reliable. Becauseconstructormost of the time it is used to provide information, and it can be overwritten and modified at any time. You can even overwrite it with something that is not an object. This does not affect the functionality of the prototype chain in the slightest.
Let's look at some of the string's construction properties:
>>> developer.constructor = ‘junk‘"junk"
It looks like itprototype's been mess:
>>> typeof developer.constructor.prototype"undefined"
But this is not the case, as the developer still breathes the "air" (developerthebreathesproperties are stillair):
>>> developer.breathes"air"
This indicates that the secret link to the prototype attribute still exists. The secret link that is exposed in Firefox is the__proto__attribute (each of the proto is preceded by two underscores).
>>> developer._proto__Object feeds = bananas breathes=air
You can use this secret link in the learning process, but it is not recommended in the actual code. Because it does not exist in Internet Explorer, your code will become difficult to port. For example, if you usemonkeya bunch of objects created, and you want to change something in all of the objects now. You can modifymonkey, and all instances inherit these changes.
>>> monkey.test = 11>>> developer.test1
__proto__is not equivalent toprototype.__proto__is a property of an instance,prototypealthough it is a property of the constructor.
>>> typeof developer.__proto__"object">>> typeof developer.prototype"undefined"
Again, you can use it in Debug or learning__proto__, and not at other times.
Expand Built-in objects
Some of the built-in objects like constructorsArray,Stringand evenObjectandFunction()all can be augmented by their prototype properties. For example, you canArrayadd new methods to the prototype properties, and they can be used in all arrays. Let's try it.
In PHP, there is a function calledin_array(), which tells you if there is a value in the array. In JavaScript, there is noinArray()such function, so we can implement it and add it toArray.prototypethe.
Array.prototype.inArray = function(needle) {
for (var i = 0, len = this.length; i < len; i++) {
if (this[i] === needle) {
return true;
}
}
return false;
}
Now, all the arrays have new methods. Let me try:
>>> var a = [‘red‘, ‘green‘, ‘blue‘];
>>> a.inArray(‘red‘);
true
>>> a.inArray(‘yellow‘);
false
It's simple and fast! Let me do one more. Imagine your program may often need to reverse the string, perhaps you would think that the string object should have a built-inreverse()method, after all, the array hasreverse()methods. You can easily addreverse()methods toStringthe prototype properties. BrowseArray.prototype.reverse()(This is similar to the practice at the end of the fourth chapter).
String.prototype.reverse = function() {
return Array.prototype.reverse.apply(this.split(‘‘)).join(‘‘);
}
This code usessplit()a string to generate an array, and then calls the method on the array,reverse()generating a reversed array. It then usesjoin()the inverted array to revert back to the string. Let's try a new approach:
>>> "Stoyan".reverse();"nayotS"
Expanding built-in objects--discussion
Extending the built-in object through the prototype attribute is a powerful technique, and you can use it to shape JavaScript into the way you want it to be. Before you use this powerful method, you must thoroughly think clearly about your thoughts.
Look at a JavaScript library called prototype, whose author loves this method so much that even the name of the library is called this. Using this library, you can use some JavaScript methods to make JavaScript as flexible as the ruby language.
The YUI (Yahoo user interface) Library is another popular JavaScript library. Its author is explicitly opposed to this field. They do not change the built-in objects in any way. No matter what library you use, modifying the core object will only confuse the user of the library and cause unexpected errors.
The fact is that JavaScript has changed and the browser has brought new versions that support more functionality. Now you think that the missing feature that needs to be extended to the prototype attribute may become a built-in method tomorrow. So your approach may not be needed. But if you have written a lot of code using this method and your method is somewhat different from the built-in implementation of the new built-in?
At the very least, what you can do is to check if it exists before implementing a method. Our last example should look like this:
if (!String.prototype.reverse) {
String.prototype.reverse = function() {
return Array.prototype.reverse.apply(this.split(‘‘)).join(‘‘);
}
}
Pitfalls of some prototype properties
These two phenomena need to be taken into account when dealing with the properties of the prototype:
-
- prototype.constructoris unreliable.
Create a simple build function and two objects:
>>> function Dog(){ this.tail = true; }
>>> var benji = new Dog();
>>> var rusty = new Dog();
Even after you have created an object, you can still add properties to the prototype property, and the object will use the new property. Let's insert the methodsay():
>>> Dog.prototype.say = function(){ return ‘Woof!‘;}
Two objects will use the new method:
>>> benji.say();
"Woof!"
>>> rusty.say();
"Woof!"
So far, if you ask your objects what they are used to create their build function, they will also report correctly:
>>> benji.constructor;
Dog();
>>> rusty.constructor;
Dog();
An interesting phenomenon is that if you ask what the constructor of the prototype attribute is, you will still getDog()that he is not too accurate. The prototype property isObject()a normal object created. UseDog()constructed objects that do not contain any attributes.
>>> benji.constructor.prototype.constructor
Dog()
>>> typeof benji.constructor.prototype.tail
"undefined"
Now we completely overwrite the prototype Property object with an entirely new object:
>>> Dog.prototype = {paws: 4, hair: true};
This proves that our old object cannot access the properties of the new prototype property. They still keep a secret link to the old prototype Property object.
>>> typeof benji.paws
"undefined"
>>> benji.say()
"Woof!"
>>> typeof benji.__proto__.say
"function"
>>> typeof benji.__proto__.paws
"undefined"
Once you create a new object, you will use the updated prototype properties:
>>> var lucy = new Dog();
>>> lucy.say()
TypeError: lucy.say is not a function
>>> lucy.paws
4
Private links to new prototype properties__proto__:
>>> typeof lucy.__proto__.say
"undefined"
>>> typeof lucy.__proto__.paws
"number"
The build function properties of the new object are no longer reported correctly. It was supposedDog()to point, but it pointedObject().
>>> lucy.constructor
Object()
>>> benji.constructor
Dog()
The hardest part to differentiate is when you look for the prototype property of a constructor:
>>> typeof lucy.constructor.prototype.paws
"undefined"
>>> typeof benji.constructor.prototype.paws
"number"
The following statement will fix all of the above unexpected symptoms:
>>> Dog.prototype = {paws: 4, hair: true};
>>> Dog.prototype.constructor = Dog;
When you override the Stereotype property, it is recommended to reset theconstructorproperty.
Summarize
Let's summarize some of the key points in this chapter.
- All functions have a property called, which, in theprototypeinitial case, contains a blank object.
- You can add properties and methods to the prototype properties. You can even replace it completely with the object you choose.
- When you use a constructor to wear an object (usingnew), the object will have a secret link to its prototype property, and the properties of the prototype attribute can be used as its own.
- Properties with the same name have a higher priority than the properties of the prototype property.
- UsehasOwnProperty()methods to differentiate properties of their own and prototype properties.
- There is a prototype chain: If your objectfoohas no attributesbar, when you usefoo.barit, JavaScript will look for properties from its prototype propertiesbar. If it is not found, it will continue to be found in the prototype properties of the prototype attribute, and then the prototype property of the prototype attribute, and then step-by-step up to the highest level of the parent classObject.
- You can augment the built-in constructors. All objects can be applied to your extensions. DeclareArray.prototype.flipthat all arrays will now have aflip()method. [1,2,3].flip (). Before you extend the methods and properties, check to see if they exist and add future guarantees to your code.
Object-oriented "-5 in"javascript. Prototype mode