Introduction to Object Orientation
What is an object
Everything is object
What an object really is can be understood at two levels.
(1) An object is an abstraction of a single thing.
A book, a car, a person can all be objects, as can a database, a web page, a connection to a remote server. When objects are abstracted into objects, the relationship between objects becomes the relationship between objects, so that the real situation can be simulated and the object can be programmed.
(2) An object is a container that encapsulates properties and methods.
Properties are the state of the object, and methods are the behavior of the object (to accomplish something). For example, we can abstract an animal as an animal object, using “attributes” to record which animal it is, and “methods” to represent certain behaviors of the animal (running, hunting, resting, etc.).
In real development, an object is an abstract concept that can be understood simply as a data set or a feature set.
Ecmascript-262 defines an object as an unordered collection of properties that can contain base values, objects, or functions. Strictly speaking, this is equivalent to saying that an object is a set of values in no particular order. Each property or method of an object has a name, and each name maps to a value.
Tip: Each object is created based on a reference type, which can be either a built-in native type or a developer custom type.
What is object orientation
Object orientation is not a new thing, it is a high encapsulation of procedural code, to improve the efficiency of code development and maintainability.
Object Oriented Programming, OOP for short, is a Programming development idea. It abstracts all kinds of complex relationships in the real world into objects, and then completes the simulation of the real world through the division of labor and cooperation between objects.
In the idea of object-oriented program development, every object is a function center, with a clear division of labor, can complete the task of receiving information, processing data, sending information. Therefore, object-oriented programming is flexible, reusable, highly modular and easy to maintain and develop. Compared with traditional procedural programming composed of a series of functions or instructions, it is more suitable for large-scale software projects with multiple people.
Object oriented and process oriented:
- Facing the process is to do everything personally, in every detail, in every aspect, step by step, orderly
- Object orientation is to take an object and dictate the result
- Object orientation transforms the actor into the leader
- Object orientation is not a process – oriented replacement, but a process – oriented encapsulation
Object-oriented features:
- encapsulation
- inheritance
- [Polymorphism] abstraction
Answer master zhihu found the answer about facing objects for your in-depth understanding:
- Zhihu: How to explain in one sentence what is object oriented thinking?
- Zhihu: What is the idea of object-oriented programming?
Program in the object – oriented basic embodiment
In JavaScript, all data types can be treated as objects, although you can also customize objects. A custom object data type is the concept of a Class in object orientation.
Let’s use an example to illustrate the difference between process orientation and object orientation in program flow.
Suppose we want to process a student’s grade table. To represent a student’s grade, a process-oriented program can be represented by an object:
var std1 = { name: 'Michael'.score: 98 }
var std2 = { name: 'Bob'.score: 81 }
Copy the code
Student scores can be processed by functions, such as printing student scores:
function printScore (student) {
console.log('Name:' + student.name + ' ' + 'Result:' + student.score)
}
Copy the code
In object-oriented programming, the first thing we should think about is not the execution flow of the program, but the data type Student should be treated as an object, which has two properties: name and Score. If you want to print a student’s score, you must first create an object corresponding to the student, and then send a printScore message to the object to print out its own data.
Abstract Data Behavior Template (Class) :
function Student(name, score) {
this.name = name;
this.score = score;
this.printScore = function() {
console.log('Name:' + this.name + ' ' + 'Result:' + this.score); }}Copy the code
Create a concrete Instance object from a template:
var std1 = new Student('Michael'.98)
var std2 = new Student('Bob'.81)
Copy the code
Instance objects have their own concrete behavior (sending messages to objects) :
std1.printScore() // => Name: Michael Grade: 98
std2.printScore() // => Name: Bob grade 81
Copy the code
The idea of object-oriented design comes from nature, where the concepts of classes and instances are natural. Class is an abstract concept. For example, Class — Student is defined to refer to the concept of a Student, while Instance is a concrete Student. For example, Michael and Bob are two concrete students.
Therefore, the idea of object-oriented design is:
- Abstract the Class(constructor)
- Create Instance based on Class(constructor)
- Command the result of Instance
Object-oriented is also more abstract than functions, because a Class contains both data and methods to manipulate it.
Create an object
A simple way
We can create it directly with new Object() :
var person = new Object()
person.name = 'Jack'
person.age = 18
person.sayName = function () {
console.log(this.name)
}
Copy the code
New Object() is cumbersome to create each time, so it can be created using its short form Object literal:
var person = {
name: 'Jack'.age: 18.sayName: function () {
console.log(this.name)
}
}
Copy the code
That’s fine, but what if we wanted to generate two Person instances?
var person1 = {
name: 'Jack'.age: 18.sayName: function () {
console.log(this.name)
}
}
var person2 = {
name: 'Mike'.age: 16.sayName: function () {
console.log(this.name)
}
}
Copy the code
It is not difficult to see from the above code that the code is too redundant and repetitive.
Easy way to improve: factory functions
We can write a function to solve the code duplication problem:
function createPerson (name, age) {
return {
name: name,
age: age,
sayName: function () {
console.log(this.name)
}
}
}
Copy the code
Then generate the instance object:
var p1 = createPerson('Jack'.18)
var p2 = createPerson('Mike'.18)
Copy the code
This encapsulation is much better. With the factory pattern, we solve the problem of creating multiple similar objects with code redundancy, but we don’t solve the problem of object recognition (how to know the type of an object).
The constructor
We have introduced constructors to solve these problems, and constructors are the most common way to create objects.
More elegant factory functions: constructors
A more elegant factory function looks like this:
function Person (name, age) {
this.name = name
this.age = age
this.sayName = function () {
console.log(this.name)
}
}
var p1 = new Person('Jack'.18)
p1.sayName() // => Jack
var p2 = new Person('Mike'.23)
p2.sayName() // => Mike
Copy the code
The difference between constructors and factory functions
In the above example, the Person() function replaces the createPerson() function, but the implementation is the same. Why is that?
We notice the following differences between the code in Person() and createPerson() :
- Create object not displayed
- Assigning properties and methods directly to
this
object - There is no
return
statements - The function name is uppercase
Person
To create a Person instance, you must use the new operator. Calling the constructor in this way goes through four steps:
- Create a new object
- Assign the constructor’s scope to the new object (so this refers to the new object)
- Execute the code in the constructor
- Return a new object
Here is the specific pseudocode:
function Person (name, age) {
When Person() is called with the new operator, an object is actually created first
// var instance = {}
// Then make the inner this point to the instance object
// this = instance
// All subsequent operations on this actually operate on instance
this.name = name
this.age = age
this.sayName = function () {
console.log(this.name)
}
// This is returned at the end of the function, which is instance
// return this
}
Copy the code
The relationship between constructors and instance objects
The advantage of using constructors is not only the simplicity of the code, but also the fact that we can identify the specific type of the object. Within each instance object there is also a constructor property that points to the constructor that created the instance:
console.log(p1.constructor === Person) // => true
console.log(p2.constructor === Person) // => true
console.log(p1.constructor === p2.constructor) // => true
Copy the code
The constructor property of an object is originally used to identify the type of the object, but it is more reliable to use the instanceof operator if you want to detect the type of the object:
console.log(p1 instanceof Person) // => true
console.log(p2 instanceof Person) // => true
Copy the code
Conclusion:
- Constructors are abstract templates abstracted from concrete objects
- An instance object is a concrete instance object derived from an abstract constructor template
- Each instance object has one
constructor
Property pointing to the constructor that created the instance
Constructor problem
The biggest benefit of using constructors is that they make it easier to create objects, but there is a problem of wasting memory:
function Person (name, age) {
this.name = name
this.age = age
this.type = 'human'
this.sayHello = function () {
console.log('hello ' + this.name)
}
}
var p1 = new Person('Tom'.18)
var p2 = new Person('Jack'.16)
Copy the code
In this example, while on the surface there seems to be nothing wrong, there is a big downside to doing so. For each instance object, type and sayHello are the same, and each instance must consume more memory for duplicate content. If there are many instance objects, there will be a huge waste of memory.
console.log(p1.sayHello === p2.sayHello) // => false
Copy the code
To solve this problem, we can define functions that need to be shared outside the constructor:
function sayHello = function () {
console.log('hello ' + this.name)
}
function Person (name, age) {
this.name = name
this.age = age
this.type = 'human'
this.sayHello = sayHello
}
var p1 = new Person('Top'.18)
var p2 = new Person('Jack'.16)
console.log(p1.sayHello === p2.sayHello) // => true
Copy the code
So we introduced prototypes
The prototype
A better solution:prototype
JavaScript states that each constructor has a Prototype property that points to another object. All properties and methods of this object are owned by the constructor.
This means that we can define properties and methods that all object instances need to share directly on the Prototype object.
function Person (name, age) {
this.name = name
this.age = age
}
console.log(Person.prototype)
Person.prototype.type = 'human'
Person.prototype.sayName = function () {
console.log(this.name)
}
var p1 = new Person(...)
var p2 = new Person(...)
console.log(p1.sayName === p2.sayName) // => true
Copy the code
The sayName() method and the Type attribute of all instances refer to the same memory address, pointing to the Prototype object, thus making the operation more efficient.
The relationship between constructors, instances, and stereotypes
Any function has a Prototype property, which is an object.
function F () {}
console.log(F.prototype) // => object
F.prototype.sayHi = function () {
console.log('hi! ')}Copy the code
The prototype object of a constructor default has a constructor attribute pointing to the function of the Prototype object.
console.log(F.prototype.constructor === F) // => true
Copy the code
Constructor instance objects contain a pointer to the constructor’s prototype object __proto__.
var instance = new F()
console.log(instance.__proto__ === F.prototype) // => true
Copy the code
__proto__ is a nonstandard attribute.
Instance objects have direct access to prototype object members.
instance.sayHi() // => hi!
Copy the code
Conclusion:
- Any function has one
prototype
Property, which is an object - constructional
prototype
Objects have one by defaultconstructor
Property, pointing toprototype
Object function - An instance object derived from a constructor contains an internal reference to the constructor
prototype
Object pointer__proto__
- All instances inherit directly or indirectly from members of the prototype object
The search principle for attribute members: prototype chain
Now that we understand the construction-instance-stereotype relationship, let’s explain why instance objects can access members in stereotype objects.
Every time the code reads an attribute of an object, a search is performed for the attribute with the given name
- The search starts with the object instance itself
- If an attribute with the given name is found in the instance, the value of that attribute is returned
- If not, search continues for the prototype object to which the pointer points, looking for the property with the given name in the prototype object
- If the property is found in the stereotype object, the value of the property is returned
That is, when we call person1.sayname (), we perform two searches:
- First, the parser asks, “Does instance person1 have the sayName attribute?” A: “No.
- “It then searches again and asks,” Does the person1 prototype have the sayName attribute?” A: “Yes.
- “It then reads the function stored in the prototype object.
- When we call person2.sayname (), the same search process is repeated, with the same results.
This is the rationale for multiple object instances sharing the properties and methods saved by the stereotype. The prototype chain is shown as follows:
Simpler prototype syntax
Notice that in the previous example we typed Person.prototype every time we added a property and method. To reduce unnecessary input, it is more common to rewrite the entire prototype object with an object literal containing all properties and methods:
function Person (name, age) {
this.name = name
this.age = age
}
Person.prototype = {
type: 'human'.sayHello: function () {
console.log('my name is' + this.name + 'I am this year' + this.age + 'old')}}Copy the code
In this example, we reset Person.Prototype to a new object. This has the advantage of being easy to add members to Person.prototype, but it also introduces the problem of the prototype object missing its constructor member.
So, to keep constructor pointing correctly, we recommend writing:
function Person (name, age) {
this.name = name
this.age = age
}
Person.prototype = {
constructor: Person, // => Manually point constructor to the correct constructor
type: 'human'.sayHello: function () {
console.log('my name is' + this.name + 'I am this year' + this.age + 'old')}}Copy the code
A prototype of a native object
All functions have a Prototype property object.
- Object.prototype
- Function.prototype
- Array.prototype
- String.prototype
- Number.prototype
- Date.prototype
- .
Suggestions for using prototype objects
- Private members (usually non-function members) are put into constructors
- Shared members (typically functions) are placed in the prototype object
- If I reset it
prototype
Remember to correctconstructor
The point to