In a typical object-oriented language, such as java, there is the concept of class. Class is the template of an object and an object is an instance of a class. However, in the Javascript language system, there is no concept of class. Javascript is not based on 'class', but is implemented through constructors and prototype chains. However, ES6 provides a writing method that is closer to traditional languages, introducing the concept of Class (class) as an object template. Through the class keyword, you can define a class. Basically, ES6's class can be regarded as just a syntax sugar. Most of its functions can be achieved by ES5. The new class writing method only makes the prototype object written clearer and more like the object-oriented programming syntax.
According to my habit, I will give the article directory before writing it.
The following content will be divided into the following subsections:
1. A brief introduction to constructors
2. Cons of constructors
3. The role of prototype attribute
4. Prototype chain
5.constructor attribute
5.1: The role of constructor attribute
6. Instanceof operator
1. A brief introduction to constructors
In my article on the close relationship between constructors and new commands in Javascript, the concept and characteristics of constructors, the principles and usage of new commands, etc., are introduced in detail. If you are not familiar with constructors, you can go and savor them carefully. Here is a simple review.
The so-called constructor is a function that provides a template for generating an object and describes the basic structure of the object. A constructor can generate multiple objects, each with the same structure. In general, a constructor is a template for an object, and an object is an instance of a constructor.
The characteristics of the constructor are:
a: The first letter of the function name of the constructor must be capitalized.
b: Use this object internally to point to the object instance to be generated.
c: Use the new operator to call the constructor and return the object instance.
Let’s see the simplest example.
function Person(){ this.name = 'keith';} var boy = new Person();console.log(boy.name); //'keith'2. Cons of constructors
All instance objects can inherit properties and methods in the constructor. However, properties cannot be shared between the same object instances.
function Person(name,height){ this.name=name; this.height=height; this.hobby=function(){ return 'watching movies';} } var boy=new Person('keith',180); var girl=new Person('rascal',153); console.log(boy.name); //'keith' console.log(girl.name); //'rascal' console.log(boy.hobby===girl.hobby); //falseIn the above code, a constructor Person generates two object instances boy and girl, and has two properties and a method. However, their hobby method is different. That is to say, whenever you use new to call the constructor to put it back an object instance, a hobby method will be created. This is neither necessary nor a waste of resources, because all hobby methods are childish behaviors and can be completely shared by two object instances.
Therefore, the disadvantage of constructors is that properties or methods cannot be shared between object instances of the same constructor.
3. The role of prototype attribute
To solve the disadvantage of not being able to share properties between object instances of constructors, js provides prototype attributes.
Each data type in js is an object (except null and undefined), and each object inherits from another object, the latter is called a "prototype" object, except for null, which does not have its own prototype object.
All properties and methods on the prototype object will be shared by the object instance.
When an object instance is generated through a constructor, the prototype of the object instance is pointed to the prototype property of the constructor. Each constructor has a prototype attribute, which is the prototype object of the object instance.
function Person(name,height){ this.name=name; this.height=height; } Person.prototype.hobby=function(){ return 'watching movies'; } var boy=new Person('keith',180); var girl=new Person('rascal',153); console.log(boy.name); //'keith' console.log(girl.name); //'rascal' console.log(boy.hobby===girl.hobby); //trueIn the above code, if the hobby method is placed on the prototype object, then both instance objects share the same method. I hope everyone can understand that for constructors, prototype is a property as a constructor; for object instances, prototype is a prototype object of object instances. Therefore, prototype is a property and an object.
Prototype objects are not properties of object instances. The attributes of an object instance are attributes inherited from the constructor's definition, because there is a keyword inside the constructor to point to the object instance to be generated. The properties of an object instance are actually attributes defined internally by the constructor. As long as the properties and methods on the prototype object are modified, the changes will be immediately reflected in all object instances.
Person.prototype.hobby=function(){ return 'swimming'; } console.log(boy.hobby===girl.hobby); //true console.log(boy.hobby()); //'swimming'console.log(girl.hobby()); //'swimming'In the above code, after modifying the hobby method of the prototype object, both object instances have changed. This is because object instances actually do not have hobby methods, they are all hobby methods that read prototype objects. That is to say, when an object instance does not have the property and method, it will search on the prototype object. If the instance object itself has a certain property or method, it will not be searched on the prototype object.
boy.hobby=function(){ return 'play basketball'; } console.log(boy.hobby()); //'play basketball' console.log(girl.hobby()); //'swimming'In the above code, when the hobby method of the boy object instance is modified, the hobby method on the prototype object will not be inherited. However, girl will still inherit the method of the prototype object.
To summarize:
a: The function of a prototype object is to define the properties and methods shared by all object instances.
b: prototype, for constructors, it is a property; for object instances, it is a prototype object.
4. Prototype chains
The properties and methods of an object may be defined in itself or in its prototype object. Since the prototype object itself is an object to object instances and it also has its own prototype, a prototype chain is formed. For example, object a is the prototype of object b, object b is the prototype of object c, and so on. The top of the prototype of all objects is the object.prototype, that is, the object pointed to by the prototype property of the Object constructor.
Of course, the Object.prototype object also has its own prototype object, that is, a null object without any attributes and methods, and the null object does not have its own prototype.
1 console.log(Object.getPrototypeOf(Object.prototype)); //null
2 console.log(Person.prototype.isPrototypeOf(boy)) //true
The characteristics of prototype chains are:
a: When reading a certain property of an object, the JavaScript engine first looks for the property of the object itself. If it cannot be found, it will go to its prototype. If it still cannot be found, it will go to the prototype of the prototype. If the Object.prototype at the top level is still not found, undefined is returned.
b: If the object itself and its prototype define an attribute of the same name, then the object itself's attributes are read first, which is called "overriding".
c: Looking for a certain attribute in the prototype chain level upward has an impact on performance. The higher the level of the prototype object you are looking for, the greater the impact on performance. If you look for a non-existent property, it will traverse the entire prototype chain.
It may be obscure to look at the concept, let’s take an example. But it is really important to understand the concept.
var arr=[1,2,3]; console.log(arr.length); //3console.log(arr.valueOf()) //[1,2,3]console.log(arr.join('|')) //1|2|3In the above code, an array arr is defined, with three elements in the array. We did not add any attributes or methods to the array, but we did not report an error when calling length, join(), and valueOf().
The length attribute is inherited from Array.prototype and belongs to a property on the prototype object. The join method is also inherited from Array.prototype and belongs to a method on the prototype object. These two methods are shared by all arrays. When there is no length attribute on the instance object, the prototype object will be searched.
The valueOf method is inherited from Object.prototype. First of all, the arr array does not have a valueOf method, so look up the prototype object Array.prototype. Then, I found that there is no valueOf method on the Array.prototype object. Finally, look up the Object.prototype object.
Let’s take a look at the properties and methods of the Array.prototype object and the Object.prototype object respectively.
console.log(Object.getOwnPropertyNames(Array.prototype))//["length", "toSource", "toString", "toLocaleString", "join", "reverse", "sort", "push", "pop", "shift", "unshift", "splice", "concat", "slice", "lastIndexOf", "indexOf", "forEach", "map", "filter", "reduceRight", "some", "every", "find", "findIndex", "copyWithin", "fill", "entries", "keys", "keys", "values", "includes", "constructor", "$set", "$remove"] console.log(Object.getOwnPropertyNames(Object.prototype)) // ["toSource", "toString", "toLocaleString", "valueOf", "watch", "unwatch", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable", "__defineGetter__", "__defineSetter__", "__lookupGetter__", "__lookupSetter__", "__proto__", "constructor"]
I believe that when you see this, you still have a very slight understanding of prototype. This is normal. After all, it is a more important and abstract concept in JS. It is impossible to master it so quickly. If you ate a few more articles, you may master the essence. In a certain way, there is a living example, which may also be a problem that everyone will encounter. You can take a look at js constructor and prototype objects.
5.constructor attribute
The prototype object has a constructor attribute that points to the constructor function where the prototype object is located by default.
function A(){}; console.log(A.prototype.constructor===A) //trueIt should be noted that prototype is the property of the constructor, and constructor is the object pointed to by the prototype property of the constructor, that is, the property of the prototype object. Be careful not to confuse.
console.log(A.hasOwnProperty('prototype')); //true console.log(A.prototype.hasOwnProperty('constructor')); //trueSince the constructor attribute is defined on the prototype object, it means it can be inherited by all instance objects.
function A(){}; var a=new A(); console.log(a.constructor); //A()console.log(a.constructor===A.prototype.constructor);//trueIn the above code, a is an instance object of constructor A, but a itself does not have a constructor attribute, which is actually reading the prototype chain.
A.prototype.constructor property.
5.1: The role of constructor attribute
a: Determine which constructor function is the prototype object belonging to
function A(){}; var a=new A(); console.log(a.constructor===A) //true console.log(a.constructor===Array) //falseThe above code means that using the constructor property, it is determined that the constructor function of the instance object a is A, not Array.
b: Create another instance from the instance
function A() {}; var a = new A();var b = new a.constructor();console.log(b instanceof A); //trueIn the above code, a is an instance object of constructor A, and the constructor can be indirectly called from a.constructor.
c: It is possible to call its own constructor
A.prototype.hello = function() { return new this.constructor(); }d: Provides a pattern of inheriting another constructor from a constructor
function Father() {} function Son() {Son.height.constructor.call(this); } Son.height = new Father();In the above code, Father and Son are both constructors. Calling Father on this inside Son will form the effect of Son inheriting Father.
e: Since the constructor attribute is a relationship between a prototype object and a constructor, when modifying the prototype object, you must pay attention to the constructor's pointing problem.
There are two solutions: either point the constructor attribute to the original constructor function, or just add properties and methods to the prototype object to avoid instanceof distortion.
6. Instanceof operator
The instanceof operator returns a Boolean value indicating whether the specified object is an instance of a constructor.
function A() {};var a = new A();console.log(a instanceof A); //trueBecause instanceof is valid for objects on the entire prototype chain, the same instance object may return true for multiple constructors.
function A() {}; var a = new A(); console.log(a instanceof A); //trueconsole.log(a instanceof Object); //trueNote that instanceof objects can only be used for complex data types (arrays, objects, etc.) and cannot be used for simple data types (boolean values, numbers, strings, etc.).
var x = [1]; var o = {}; var b = true; var c = 'string'; console.log(x instanceof Array); //trueconsole.log(o instanceof Object); //true console.log(b instanceof Boolean); //falseconsole.log(c instanceof String); //falseAlso, neither null nor undefined are objects, so instanceof always returns false.
console.log(null instanceof Object); //false console.log(undefined instanceof Object); //false
Using the instanceof operator, you can also cleverly solve the problem of forgetting to add new command when calling the constructor.
function Keith(name,height) { if (! this instanceof Keith) { return new Keith(name,height); } this.name = name; this.height = height;}In the above code, the instanceof operator is used to determine whether the keyword in the function body points to an instance of the constructor Keith. If not, it means that the new command is forgotten. At this time, the constructor will return an object instance to avoid unexpected results.
Due to space limitations, I will introduce it here for the time being.
In my next share, I will talk about some native methods of prototype objects, such as Object.getPrototypeOf(), Object.setPrototypeOf(), etc., and introduce a comparison of methods for obtaining native objects.
The above is the detailed explanation of the prototype attribute (recommended) in Javascript introduced to you by the editor. I hope it will be helpful to you.