“This is the first day of my participation in the First Challenge 2022. For details: First Challenge 2022”

The interviewer asks, what are the characteristics of object orientation? Interviewer: Gone? Can you tell me how it works? What can they do? Interviewer: Er…

This article will take you through the three main features of object orientation with a combination of self-drawn graphics and browser runtime screenshots, as well as scopes. With part of this pointing to the knowledge.

encapsulation

Encapsulation is the creation of an object that centrally stores the properties and functions of an object in the real world. Encapsulate scattered data into object structure, which is extremely convenient for the management and maintenance of a large number of data. As long as the use of object-oriented development, the first step is to encapsulate a variety of object structures for use.

There are three ways to encapsulate objects

1. Use curly braces

Using {} directly is short for new Object()

const xiaoming = {
  name: 'Ming'.getName: function () {
    console.log(this.name)
  }
}

xiaoming.age = 18
Copy the code

Name = this.name = this.name = this.name = this.name = this.name = this.name = this.name = this.name = this.name Why does this refer to Xiaoming instead of window, and we’ll leave that for later

2. Use New Object()

const xiaoming = new Object({
  name: 'Ming'.getName: function() {
    console.log(this.name)
  }
})
​
xiaoming.age = 18
Copy the code

3. Use constructors

Creating multiple objects of the same structure using the above two methods creates a lot of repetitive code.

const xiaoming = {
  name: 'Ming'.getName: function() {
    console.log(this.name)
  }
}

const xiaoguang = {
  name: 'light'.getName: function() {
    console.log(this.name)
  }
}

 / /...
Copy the code

Use constructors to solve this problem.

function Person(name) {
  this.name = name
  this.getName = function() {
    console.log(this.name)
  }
}
​
const xiaoming = new Person('Ming')
const xiaoguang = new Person('light')
​
xiaoming.age = 18
xiaoming.getName() / / xiao Ming
console.log(xiaoming.age) / / 18
​
xiaoguang.getName() / / light
console.log(xiaoguang.age) // undefined
Copy the code

The benefit of constructors is code reuse. This approach has been used in many frameworks, such as Fiber created in React

Object to access internal properties

Why can’t an object directly access its own internal properties

Let’s start with our first question — why can’t we use XXX to access our own properties from within an object? Why isn’t this referring to window

Let’s take this as an example:

const xiaoming = {
  name: 'Ming'.getName: function () {
    console.log(name)
  }
}
​
xiaoming.getName() // undefined
Copy the code

The first is when you create an object, The value of getName is a function, so you need to call new Function to create a function Object 0x5693 that contains the code to execute this function

We then call xiaoming. GetName () to create a temporary scope object that is empty and has no name attribute at all. If you look up the scope chain, you can’t find the property with name, so you have to call undefined.

Const xiaoming = {… const xiaoming = {… }, so there is no direct access to its own properties inside the object. This explains why you can’t use name directly, and why this doesn’t refer to window.

See this article about scoping

Access by object reference

As you can see in the figure above, we can access the reference to Xiaoming in the window inside getName, so we can access its own properties inside xiaoming. Name, but this approach is tightly coupled and is not a good solution.

Through this

We can query the object itself using the this keyword

So, what is this?

  • Built-in to each function
  • Refers specifically to the current function being called.objects beforeThe keyword of.

What does new do when it calls the constructor?

function Person(name) {
  this.name = name
  this.getName = function() {
    console.log(this.name)
  }
}
const xiaoming = new Person('Ming')
Copy the code

On the surface, it’s two things

  1. Call the Person argument with new"Xiao Ming"To a parameter inside the constructornameVariable, and then passthis.name.
  2. And then finally to the objectxiaoming.

But actually, New did four things

  1. Create a new empty object to wait

  1. First keep, behind the design to this knowledge point, will review these four steps

  2. Call the constructor:

    A. Point this in the constructor to the newly created object

B. Add attributes and methods to the new object by forcing an assignment inside the constructor

In the previous section we said that this refers specifically to the keyword of the object before the. That is calling the current function. But where did we get this…?

This is because new will connect this to the newly created object, which is the second case of this.

  1. The last step of course is to return the address of the new object and store it in the variable Xiaoming

Summary:

New does four things

  • Create a new empty object to wait
  • ?
  • Point this in the constructor to the newly created object and add the specified properties and methods to it
  • Returns the address of the new object, stored to the left of = in the variable

At present, we know two situations of this

  • Obj.fun () : This in fun refers to the object before
  • New Fun() This in Fun refers to the new object created by new

inheritance

Inheritance is used to solve the problem of duplicate creation

There is a problem in the execution diagram when we pass the above new constructor. The problem is that every time I call new Person, I execute new Function to create the getName method in the constructor. However, the Function of the getName method is always the same, which causes duplicate creation.

So we’re going to use inheritance to solve this problem

JS inheritance is implemented using prototype objects

First of all, we need to know that JS inheritance is achieved through the prototype object, the prototype object is the parent object for all child objects to centrally store the common property values and methods.

The prototype object does not need to be created by itself. When defining the constructor, the program automatically creates a prototype object and mounts it to the constructor

This way we can put our getName directly onto the prototype so we don’t have to create it again

function Person(name) {
  this.name = name
}
​
Person.prototype.getName = function() {
  console.log(this.name)
}
​
const xiaoming = new Person('Ming')
xiaoming.getName() // "xiaoming"
Copy the code

Let’s try it out

__proto__ = Person. Prototype Xiaoming. GetName is obtained by accessing Person.prototype.

This is the third case of this in getName, but we see that this refers to this. The preceding objects are exactly the same! So this is xiaoming

The [[Prototype]] property in the console for Xiaoming is __proto__

Summary:

Using inheritance prevents the same method from being created twice and taking up memory.

Inheritance in JS is implemented by prototype objects. The prototype object is mounted as the property Prototype when the function is defined. When the constructor is called, the __proto__ of the empty object created points to the function’s prototype.

Fun.prototype.xxx = function () {} to add methods to the prototype, then instance objects can go directly to instance. XXX to find XXX through __proto__

So the second of the four steps of new has been completed, so let’s go over these four steps again

  • (purple) Create a new empty object wait
  • (Blue) Make this new object inherit the constructor’s prototype object (__proto__ attributes point to the constructor’s prototype object)
  • (green) points this in the constructor to the new object and adds the specified attributes to the new object
  • Yellow returns the address of the new object

At the same time there are three cases of this:

  • Obj.fun () : This in fun refers to the object before
  • New Fun() This in Fun refers to the new object created by new
  • In the constructor prototype, as in the first, you don’t look at the definition, just the call

polymorphism

The same method shows different states under different circumstances. In JavaScript, polymorphism is implemented based on prototype chains.

Prototype chain

Let’s start with such a piece of code (Person is still the constructor of the above example)

const obj = { a: 1 }, xiaoming = new Person('Ming')

obj.toString()      // '[object Object]'
xiaoming.toString() // '[object Object]'
Copy the code

Object Object is delivered with __proto__, but Person is delivered without toString.

The answer is the prototype chain, and the toString called here is found by the prototype chain.

Our Person returns an object, and behind that object is the new object. Let’s graph toString in Xiaoming

  1. The first is inxiaomingWas not found on this objecttoStringMethod, but with a __proto__ connectionPerson.prototypeObject, then goPerson.prototypeLooking up
  2. Arrived at thePerson.prototypeAnd I didn’t find ittoStringMethod, but with a __proto__ connectionObject.prototypeObject, and then ran toObject.prototypeLooking up
  3. Finally, at lastObject.prototypeFound on thetoStringMethod to call.

To summarize what a prototype chain is: A prototype chain is a chain structure formed by successive hierarchies of parent objects. It holds all the properties and methods available to an object, and controls the order in which they are used — the nearest rule (child before parent, layer by layer).

You might be wondering, prototype chains what does that have to do with the polymorphism we’re talking about? Don’t worry, let’s look at one more piece of code

const obj = { a: 1 }, date = new Date(a)typeof obj      // 'object'
typeof date     // 'object'

obj.toString()  // '[object Object]'
date.toString() // 'Fri Jan 28 2022 16:18:23 GMT+0800 '
Copy the code

We found that the same object, both call toString method is not the same result, after the above understanding about the prototype chain and the prototype chain lookup rules, we should understand that the two toStrings are not the same. Take the actual operation result as proof.

obj.toString === xiaoming.toString  // ture
obj.toString === date.toString      // false
Copy the code

This shows that the toString method is redefined in date’s prototype object so that the resulting toString method is different from obj.tostring.

Hence the initial statement — in JavaScript, polymorphism is implemented based on prototype chains.

Our Person could also write a toString on Prototype to “override” the original method itself

Summary:

In JavaScript, polymorphism is implemented based on look-up rules for prototype chains. Because the search sequence in JavaScript is to start from their own search, if they do not have their own prototype to find, if they have not found their own prototype, then go to their prototype to find….

  • If found, the result is returned and used by the calling object
  • If it does not, it looks up until the prototype of Object points to NULL

This lookup process is similar to that of a scope chain

conclusion

encapsulation

Encapsulating an object and storing its scattered properties and functions can facilitate the management and maintenance of large amounts of data.

There are three ways to encapsulate objects:

  • Use {} directly
  • Use the new Object ()
  • Using constructors

For data that requires multiple uses of the same structure, using constructors can avoid code redundancy

inheritance

Inheritance prevents the same method from being created twice and taking up memory.

Inheritance in JS is implemented by prototype objects. The prototype object is mounted as the property Prototype when the function is defined. When the constructor is called, the __proto__ of the empty object created points to the function’s prototype.

Fun.prototype.xxx = function () {} to add methods to the prototype, then instance objects can go directly to instance. XXX to find XXX through __proto__

polymorphism

Polymorphism is implemented based on the search rules of the prototype chain, starting from the instance itself, and then looking on the prototype above, if found, the search is terminated and returned to the instance call. If the prototype of Object is found to point to NULL, the search fails.

Four things new does

  • Create a new empty object to wait
  • Make this new object inherit from the constructor’s prototype (__proto__ attributes point to the constructor’s prototype)
  • Point this in the constructor to the new object and add the specified properties to the new object
  • Returns the new object address

OK, the three main features of object-oriented are basically finished. If you think it is helpful, please click “like” 👍. If you think there is any bad writing, or have any suggestions or questions, welcome to give me feedback in the message area, thank you ~

Finally, 2022, come on!