Writing in the front
In the last article, we summarized the first three chapters of the book
Click here for the previous article: 👉
This article will wrap up the last three chapters of the book and give us a thorough understanding of JavaScript object orientation. Here’s the full mind map:
Chapter 4 constructors and prototype objects
4.1 Constructors
Constructors are the functions we call when we create objects with new, such as Object, Array, Function, etc. Constructors are defined in the same way as functions, but constructors should be capitalized like this:
function Person() {
/ /...
}
var person = new Person(); // Can pass the parameter writing method
or
var person = new Person; // You can write this without passing the parameter
// Check if person is of type Person (instanceof is recommended)
console.log(person instanceof Person); // true
Copy the code
An object created automatically from a constructor has constructor properties that point to the constructor that created it
console.log(person.constructor === Person); // true
Copy the code
The purpose of creating a constructor is to create many objects that have the same properties and methods.
- to
this
Add attributes
function Person (name) {
this.name = name;
this.sayName = function() {
return this.name;
}
}
var person1 = new Person('the bear big');
var person2 = new Person('the bear two');
console.log(person1.name, person1.sayName()); // 'xiong Da' 'Xiong Da'
console.log(person2.name, person2.sayName()); // 'bear 2'
Copy the code
Object.defineProperty()
methods
function Person(name) {
Object.defineProperty(this."name", {
get: function() {
return name;
},
set: function(value) {
name = value;
},
/ /... Some configuration properties
});
this.sayName = function() {
return this.name;
}
}
var person = new Person('the bear big');
console.log(person.sayName()); / / big bear
Copy the code
Constructors do not eliminate code redundancy.
4.2 Prototype Object
Almost all functions have a prototype property, which is a prototype object used to create a new object instance. All created object instances share the stereotype object, and these object instances have access to the properties of the stereotype object. Like the toString() method
var obj = {
name: 'the bear big'
}
console.log("name" in obj); // true
console.log(obj.hasOwnProperty("name")); // true
console.log("toString" in obj); // true
console.log(obj.hasOwnProperty("toString")); // false
console.log(Object.prototype.hasOwnProperty("toString")); // true
Copy the code
We concluded in the previous chapter that the in operator checks for its own and stereotype properties, while object.hasownProperty () only checks for its own properties, so we can write a method that checks if a property is a stereotype:
/ * *
* @params object {object} name {string}
* @descriptionReturns true if it is a stereotype property, false otherwise
* @returns boolean
* /
function isProto(object, name) {
return name in object&&!object.hasOwnProperty(name);
}
var object = {
name: 'the bear big'
}
console.log(isProto(object."name")); // false
console.log(isProto(object."age")); // false
console.log(isProto(object."toString")); // true
Copy the code
2 [[Prototype]] attribute
When we create a new object with new, the constructor’s Prototype object is assigned to that object’s [[Prototype]] property
We can use
Object.getPrototypeOf()
Methods read
[[Prototype]]
Property, can be used
isPrototypeOf()
Method to check whether an object is a prototype of another object
var obj = {};
var obj1 = {};
var val = Object.getPrototypeOf(obj);
console.log(val === Object.prototype); // true
console.log(Object.prototype.isPrototypeOf(obj)); // true
console.log(Object.prototype.isPrototypeOf(obj1)); // true
Copy the code
When we read an object’s properties, we first look for the object’s own properties, return the value if it is found, then look for the object’s prototype properties if it is not found, return the value if it is not found, and finally return undefined.
var person = {
name: 'the bear big'
}
console.log(person.name); // 'bear big'
console.log(person.toString()); // [object object]
console.log(person.age); // undefined
Copy the code
The delete operator only applies to the stereotype property, which is overridden by its own property.
4.2.2 Using prototype objects in constructors
Because prototype objects can be shared, we can define methods for all objects at once. It’s a good idea to put a method in a prototype object and access it with this.
function Person(name) {
this.name = name;
}
Person.prototype.sayName = function() {
return this.name;
}
var person = new Person('the bear big');
console.log(person.name); // 'bear big'
console.log(person.sayName()); // 'bear big'
Copy the code
Because of the shareable nature of the stereotype object, defining attributes on the stereotype can occur in the following ways
function Person(name) {
this.name = name;
}
Person.prototype.sayName = function() {
return this.name;
}
var person1 = new Person('the bear big');
var person2 = new Person('the bear two');
Person.prototype.arr = [];
person1.arr.push('front end');
person2.arr.push('Java');
console.log(person1.arr); / / the front-end Java
console.log(person2.arr); / / the front-end Java
Copy the code
Therefore, we should be careful about defining attributes on the prototype !!!!
We can replace the prototype object directly with its literal form
function Person(name) {
this.name = name;
}
Person.prototype = {
sayName: function() {
return this.name;
},
arr: [].
}
Copy the code
But doing so changes the properties of the constructor so that it points to Object instead of the constructor,
var person = new Person('the bear big');
console.log(person instanceof Person); // true
console.log(person.constructor === Person); // false
console.log(person.constructor === Object); // true
Copy the code
The constructor attribute is specific to Object. So to avoid this, we need to set the constructor property manually
function Person(name) {
this.name = name;
}
Person.prototype = {
constructor: Person,
sayName: function() {
return this.name
}
}
var person = new Person('the bear big');
console.log(person instanceof Person); // true
console.log(person.constructor === Person); // true
console.log(person.constructor === Object); // false
Copy the code
4.2.3 Changing the prototype object
We add a property to the prototype, because of the shareability of the prototype, when we create multiple object instances, this property is owned by each object instance.
It is also interesting to note that when we seal or freeze an object, we cannot add or change its own properties, but we can still extend the instance with the prototype object
4.2.4 Prototype objects for built-in objects
All built-in functions have constructors, and we can also change their prototype objects, as in the following example:
Array.prototype.sum = function() {
return this.reduce(function(prev, curr) {
return prev + curr
})
}
var arr = [1.2.3.4.5.6];
console.log(arr.sum()); / / 21
Copy the code
Chapter V Succession
5.1 Prototype Object chain and Object.prototype
The built-in inheritance method in JS is called prototype object chain, also known as prototype object inheritance. All objects inherit from Object.Prototype
5.1.1 Methods inherited from Object.prototype
Lists methods that can be inherited by all objects
methods | role |
---|---|
hasOwnProperty() |
Detects the existence of an object’s own properties |
propertyIsEnumerable() |
Checks whether a proprietary property is enumerable |
isPropertyOf() |
Checks whether an object is a prototype of another object |
*valueOf() |
Returns the value representation of an object |
*toString() |
Returns a string representation of an object |
The valueOf method is called every time an operator is applied to an object, which returns the object instance itself. The toString() method is called when valueOf returns a reference instead of the original value
5.1.2 modify the Object. The prototype
We know that all objects inherit from Object.prototype. If we change this, it will affect all objects. Therefore, we should not modify object.prototype ().
5.2 Object Inheritance
Object inheritance is the simplest type of inheritance. All we need to do is specify which Object is the [[prototype]] of the new Object. We can specify Object implicitly using the literal form of the Object or explicitly using object.create ().
Two arguments to the object.create () method
- First parameter: the one that needs to be set to the new object
[[prototype]]
object - Second argument: Optional argument. Property describes the object.
var person = {
name: 'the bear big'
}
var person = Object.create(Object.prototype, {
name: {
configurable: true.
enumerable: true.
value: 'the bear big'.
writable: true.
}
})
Copy the code
The first method automatically inherits Object.prototype, which is configurable, enumerable, and writable by default. The second way is to define which object to inherit from. Next, use the second way to inherit from another object.
var person = {
name: 'the bear big'.
age: 11.
sayName: function() {
return this.name;
}
}
var person1 = Object.create(person, {
name: {
configurable: true.
enumerable: true.
value: 'the bear two'.
writable: true.
}
})
console.log(person.sayName()); // "bear big"
console.log(person1.sayName()); // "Bear 2"
console.log(person.hasOwnProperty("age")); // true
console.log(person.isPrototypeOf(person1)); // true
console.log(person1.hasOwnProperty("age")); // false
Copy the code
We can also create a very “clean” Object with object.create ()
var obj = Object.create(null);
console.log("toString" in obj); // false
Copy the code
5.3 Constructor inheritance
All functions have a Prototype property that can be modified or replaced. The Prototype property is set to a new generic Object that inherits from Object.prototype and has its own constructor property
function Func(){
// ...
}
Func.prototype = Object.create(Object.prototype, {
constructor: {
configurable: true.
enumerable: true.
value: Func,
writable: true.
}
})
Copy the code
We can also change the prototype object chain
function Rectabgle(length, width) {
this.length = length;
this.width = width;
}
Rectabgle.prototype.getArea = function() {
return this.length * this.width;
}
function Square(size){
this.length = size;
this.width = size;
}
Square.prototype = new Rectabgle();
Square.prototype.constructor = Square;
console.log(new Rectabgle(5.10).getArea()); / / 50
console.log(new Square(6).getArea()); / / 36
Copy the code
5.4 Constructor theft
If we need to call the parent constructor in the subclass constructor, we need to call the parent constructor with call() and apply() in the constructor and pass in the new object, essentially stealing the parent constructor with our own object.
function Rectangle(length, width) {
this.length = length;
this.width = width;
}
Rectangle.prototype.getArea = function() {
return this.length * this.width;
}
function Square(size){
Rectangle.call(this, size, size)
}
Square.prototype = new Rectangle();
Square.prototype.constructor = Square;
Square.prototype = Object.create(Rectangle.prototype, {
name: {
configurable: true.
enumerable: true.
value: Square,
writable: true.
}
})
console.log(new Square(6).getArea()); / / 36
Copy the code
In the example above, the Square() method calls the Rectangle constructor, passing this and size twice. The purpose of this is to create the Length and width properties on the new object. This avoids the need to redefine the properties you wish to inherit in the constructor. We can add new attributes or overwrite existing ones after calling the parent class’s constructor, which is often called pseudo-class inheritance.
5.5 Accessing superclass Methods
How should we access the methods of the parent class,
function Person() {
this.name = 'the bear big'
}
Person.prototype.sayName = function () {
return this.name;
}
function Person1() {
this.name = 'the bear two';
}
Person1.prototype.sayName = function() {
return Person.prototype.sayName.call(this);
}
var person = new Person();
var person1 = new Person1();
console.log(person1.sayName()); // 'bear 2'
Copy the code
This method is the only way to access a superclass method
Chapter 6 Object mode
6.1 Private and Privileged Members
All properties of JavaScript objects are public, and there is no explicit way to specify that a property cannot be accessed by external objects. There may be times when we want this attribute to be private, and we can solve this problem with a naming convention such as this._name. There are a few other methods, listed below
6.1.1 Module Mode
It is a pattern for creating single-room objects with private data. The idea is to express an object using a standup function (whose syntax is to execute an anonymous function immediately, which exists only at the moment it is called and is then destroyed).
This modular pattern allows us to use common variables as non-public object attributes.
var obj = (function(){
var name = 'the bear big';
return {
name,
getName: function() {
return name;
},
setName: function() {
name = 'the bear two';
}
};
} ());
console.log(obj.name); // "bear big"
console.log(obj.getName()); // "bear big"
obj.name = 'the bear two';
console.log(obj.name); // "Bear 2"
console.log(obj.getName()); // "bear big"
obj.setName();
console.log(obj.name); // "Bear 2"
console.log(obj.getName()); // "Bear 2"
Copy the code
In the above code, name is a private property and cannot be accessed directly by the outside world. It can be operated by object methods. HetName () and setName() are privileged methods.
A variation of the module pattern: exposed module pattern.
var obj = (function() {
var name = 'the bear big';
function getName() {
return name;
}
function setName() {
name = 'the bear two';
}
return {
name,
getName,
setName,
}
} ())
Copy the code
The exposed module mode, the properties Name, getName, and setName are all IIFE native objects, and they are all set to the returned object, exposing itself to the outside world.
6.1.2 Private member of the constructor
You can also use the module pattern to define private properties in constructors
function Person(name){
this.name = name;
var age = 11;
this.getAge = function() {
return age;
}
this.setAge = function() {
return age = 22;
}
}
var person = new Person('the bear big');
console.log(person.name); // 'bear big'
console.log(person.getAge()); / / 11
person.age = 12;
console.log(person.getAge()); / / 11
person.setAge();
console.log(person.getAge()); / / 22
Copy the code
If we need all instances to share private data, we can combine module patterns with constructors
var PersonFather = (function() {
var age = 11;
function Person(name) {
this.name = name;
}
Person.prototype.getAge = function() {
return age;
}
Person.prototype.setAge = function() {
age = 22;
}
return Person;
} ())
var person = new PersonFather('the bear big');
var person1 = new PersonFather('the bear two');
console.log(person.name); // 'bear big'
console.log(person.getAge()); / / 11
console.log(person1.getAge()); / / 11
person.age = 22;
console.log(person.getAge()); / / 11
console.log(person1.getAge()); / / 11
person.setAge();
console.log(person.getAge()); / / 22
console.log(person1.getAge()); / / 22
Copy the code
Above, all instances of the PersonFather function successfully share the age variable.
6.2 with
Mixin is a method of pseudo-inheritance in which an object acquirement properties of another object without changing the chain of prototyped objects.
Traditional function implementation
/ / shallow copy
function mixin(receiver, supplier) {
for(var property in supplier) {
if(object.hasOwnProperty(property)) {
receiver[property] = supplier[property]
}
}
return receiver;
}
Copy the code
We can write a function that supports both ECMAScript5 and ECMAScript3 versions
function mixin(receiver, supplier) {
if(Object.getOwnPropertyDescriptor) {
Object.keys(supplier).forEach(function(property) {
var descriptor = Object.getOwnPropertyDescriptor(supplier, property);
Object.defineProperty(receiver, property, descriptor);
})
} else {
for(var property in supplier) {
if(object.hasOwnProperty(property)) {
receiver[property] = supplier[property]
}
}
}
return receiver;
}
Copy the code
6.3 Scope-safe constructors
When we use a constructor, we throw an error if we do not use the new operator. Here is a scope-safe way to write a constructor
function Person(name) {
if(this instanceof Person) {
this.name = name
} else {
return new Person(name)
}
}
// After that, we do not use the new operator and do not throw an error
var person = new Person('the bear big');
var person1 = Person('the bear two');
console.log(person instanceof Person); // true
console.log(person1 instanceof Person); // true
Copy the code
Recommended reading
Implement the new operator by hand
conclusion
At this point, “JavaScript object-oriented essentials” this book has been concluded, there is a summary of the bad place, but also hope that you point out, let us make progress together ~
Finally, share my personal public number “Web front-end diary”, welcome to come to pay attention to ~