Object, prototype, prototype chain, inheritance topic
Object, prototype
To understand prototypes, we start with objects.
For objects, ecMA-262 defines objects as an unordered collection of attributes that can contain base values, objects, or functions.
So how do you create an object?
- Literal or new Object:
-
Var psrson = {name:'smile', age:18, sayName:function(){ console.log(this.name) }} // new Object var person = new Object(); person.name = 'zhou'; person.age = 18; person.sayName = function(){ console.log(this.name)}Copy the code
There are major disadvantages to both approaches: if I were to create 100 objects this way, I would generate a lot of repetitive code.
2. Factory pattern creates objects to solve repetitive code problems
function createPerson(name,age,sex){
var obj = new Object();
obj.name = name;
obj.age = age;
obj.sex = sex;
}Copy the code
Advantages: Solved the code duplication problem
Cons: If two different objects, such as Person and Animal, are created this way. We can’t tell which type they belong to (because they are created with Object).
3. Constructor pattern
function Person(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
this.sayName = function(){
console.log(this.name)
}
}
var person1 = new Person('smile', 19,'male');
var person2 = new Person('zhou', 19,'female')Copy the code
When creating the Perosn instance, we use the new operator. So what does the new operator do?
- Create a new object;
- Assign the constructor’s scope to the new object (pointing this to the new object);
- Execute the code in the constructor (add attributes for the new object);
- Return a new object
The specific process is demonstrated by code:
// There is a bug that does not take into account the case that the constructor returns a value and is an objectfunction objectFactory(){ var obj = {}; Constrcutor = [].shift.call(arguments); Constrcutor.apply(obj,arguments); // Obj can access the constructor attribute obj.__prototype__ = constrcutor. prototypereturn obj
}Copy the code
But there are still problems with using constructors directly like this
- Even if each instance has the same method, however, when you create the instance, you will recreate each method, i.e. the sayName in person1 and person2 are not instances of the same Function. Because functions are objects in JS, you define a Function that is equivalent to new Function();
So to solve this problem, you can do this:
function Person(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
this.sayName = sayName
}
function sayName = function(){
console.log(this.name)
}Copy the code
This allows all instances to share the external sayName function.
If there are too many methods on an object, there will be too many global functions, which will be difficult to maintain. Moreover, such functions only serve the object, not the global service, so there are too many limitations of this method. Is there a way for all instances to share properties and methods?
4. Prototyping
Next, it’s time for our hero.
There are a few points to note when creating functions:
- Each function has a prototype attribute.
- Prototype lets all object instances share its contained objects and properties.
function Person() {}; Person.prototype.name ='smile'; Person.prototype.sayName = function(){console.log(this.name)};Copy the code
How do we access the prototype properties when we instantiate an object?
Let’s look at it step by step:
- When you instantiate an object, it contains a pointer to the constructor’s prototype object. We’ll call this pointer [[prototype]]. [[prototype]] ====> person.prototype
- When an attribute of an instance is accessed, it occurs:
- Accesses whether the property or method is present in the instance. Where do instance properties or methods come from? Remember what happened with the new operation? willThe object that comes out of newTo add a property or method on the constructor.
- If not, it searches up for properties or methods on the prototype object pointed to by [[prototype]].
- If the method or property exists on both the instance and the prototype object pointed to by [[Prototype]], the method or property on the instance is accessed.
- Each stereotype object has a constructor property that points to the associated constructor. (important)
In most browsers [[prototype]] is called __proto__
We use diagrams to show the relationship between __proto__, Prototype, and the constructor.
There are a few other things to note about prototype objects:
- How do you know if a property or method is on an instance or a prototype object?
- In operator: Returns true whether this property is on instance or stereotype.
- The getOwnProperty() method returns true only if the property exists on the instance
- So we conclude that as long as the property returns true with the IN operator and false with the getOwnProperty() method, we know that the property is on the prototype object.
function hasProtypeProperty(object,name){ return! object.getOwnProperty(name) && (namein object)}Copy the code
Of course, there is a drawback to this pattern: all instances get the same attribute value by default. But what if we want to have both our own properties and our own public properties?
5. Use in combination
Use constructors and stereotype patterns to create an object
function Person(name,age,job){
this.name = name;
this.job = job;
}
Person.prototype.sayName = function (){console.log('hello')}Copy the code
Two. Prototype chain, inheritance
In javascript, it’s inheritance, it’s more delegate.
Because inheritance means copying operations, JavaScript by default does not copy the properties of an object. Instead, JavaScript simply creates an association between two objects so that one object can access the properties and functions of the other through delegation, so it is more accurate to call it delegation than inheritance.
So what do we do to create an association between two objects?
The answer is the prototype chain.
What is a prototype chain? If we make a stereotype object equal to an instance of another type. The stereotype object will then contain a pointer to another stereotype object. This, in turn, forms a chain of prototypes.
So we can implement inheritance like this:
function Person(){
this.property = true
}
Person.prototype.getPersonName = 'person';
function Men(){
this.myProperty = falsePrototype = new Person(); Men.prototype.getMyName ='men';
var men = new Men()
console.log(men.getPersonName) // personCopy the code
Note: When defining a subclass method, be sure to write it after replacing the stereotype. If you write it before, it overwrites the method already written.
There are two problems with using the prototype chain directly to implement inheritance:
- The attributes of the Person constructor are shared among all instances of Men. Changes to this property in one instance can affect other instances.
- When creating subclass instances, you cannot pass parameters to the superclass without affecting all instances
So, we started reinventing
1. Borrow constructors
Directly on the code:
function SuperType(color){
this.color = color
}
function subType(){
SuperType.call(this,'blue')}Copy the code
Advantage:
- Each instance can have its own attributes
- You can pass arguments to subclasses in the subclass constructor.
Disadvantages:
- Methods are defined in constructors and cannot be reused
- Methods defined on the stereotype of a supertype are not visible to subtypes.
2. Combinatorial inheritance
Code implementation:
function SuperType(name){
this.name = name;
this.color = ['blue'.'green']
}
SuperType.prototype.sayName = function(){
console.log(this.name)
}
function SubType(name,age){
// Inherit attributes
SuperType.call(this,name) // Call this.age = age the second time
}
// First call
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
var instance = new SubType('smile'.18)
console.log(instance)
Copy the code
This inheritance allows instances to have their own properties and to use common methods.
Disadvantages: SuperType is called twice, the first time it is called, the name and color properties are generated on the SubType prototype. The second call generates the name and color properties on the instance of SubType.
3. Improve composite inheritance
function SuperType(name){
this.name = name;
this.color = ['blue'.'green']
}
SuperType.prototype.sayName = function(){
console.log(this.name)
}
functionSubType(name,age){// Inherit attribute supertype. call(this,name) // call this.age = age for the second time} // Call subtype. prototype for the first time SuperType.prototype; var instance = new SubType('smile',18)
console.log(instance)Copy the code
Improved fix: Produce name and color attributes only on instances.
Disadvantages: There is no way to know whether an object is subclassed or instantiated by a superclass, since both the superclass and subclass point to the same stereotype.
Parasitic combinatorial inheritance
function SuperType(name){
this.name = name;
this.color = ['blue'.'green']
}
SuperType.prototype.sayName = function(){
console.log(this.name)
}
functionSubType(name,age){// Inherit attribute supertype. call(this,name) // call this.age = age for the second time} // Call subtype. prototype for the first time Object.create(SuperType.prototype); SubType.prototype.constructor = SubTypevar instance = new SubType('smile',18)
console.log(instance)Copy the code
The emphasis here is object.create (obj)
- He’s going to create a new object, and the prototype of the new object is OBj
Equivalent to the following function:
function object(o){
function F() {}; F.prototype = o;return new F();
}Copy the code