Do prototypes really work

A lot of guys are saying that prototypes are important, so why don’t I use them?

The reasons are as follows:

  1. Framework heavy userOur current mainstream front-end business is almost all usedvueTo react,Wechat appletsIn development. These frameworks are so well packaged that we hardly need to do themAdditional packaging“Even if you have a need, go in disguise, ask for help online, and have a bunch of creepy people waiting to teach you.
  2. Basic knowledge ofStill no homeAre in useThe frameworkDoing business, there is no time to in-depth study of technical principles, and no ability to sealLoading of rolling.
  3. I have changed jobs too little, and I have not been abused by the interviewer. I have not experienced the pleasure of building an aircraft carrier during the interview and turning the screws at work.

So, since it is not used, it is not necessary to learn, start from the self, refused to volume. Understand full marks…

However, the cruel truth is that only technology can be truly controlled by themselves, fate is still in their hands.

The truth

I just wanted to roll up my sleeves and take a look at this. “Forget it, get on.”

Below, I will tease out the relationship between ESE5 and prototype in the most straightforward and concise way possible.

When do YOU need a prototype

Encapsulate!! This is used when we want to abstract some common business for easy reuse or to make the structure clearer. Three characteristics of object orientation:

  1. encapsulation
  2. Inheritance (I also classify inheritance in encapsulation)
  3. polymorphism

Let’s say we want to create one

  • Rounded div tag
  • If you click on yourself, you get bigger and smaller

Think of rounded corners and pinch and zoom as common business.

We’ll write it like this


If we want to create a picture label at this time, also rounded corners, also can click to zoom in and out

Write directly

So we can see that we’re essentially copying the code once

    const div = document.querySelector("div");
    div.onclick = function () {
      this.classList.add("scale");
    }

    // Bind events to images as well
    const img = document.querySelector("img");
    img.onclick = function () {
      this.classList.add("scale");
    }
Copy the code

The above code does not represent encapsulation. And it’s fragmented, the code is mixed with the business. (For some simple business, this is fine, as simple as possible.)

Use the encapsulated writing method

    // instantiate div
    new CreateCurveElement("div");

    // instantiate the image
    new CreateCurveElement("img", { src: "images/1.png" });


    // constructor
    function CreateCurveElement(elementName, option) {
      const element = document.createElement(elementName);
      element.onclick = function () {
        element.classList.add("scale");
      }
      option && Object.keys(option).forEach(key= > element.setAttribute(key, option[key]));
      document.body.appendChild(element)
    }
Copy the code

As you can see, if you want to create a curved element with a border, just go new. It has the following advantages

  1. Reuse common code, such ascreateElement.onclickclassList.add
  2. Implementation details are hidden, allowing the caller to focus on the business itself, such as creating an element new CreateCurveElement

What about the prototype

The above code, too, has its drawbacks. For example, the code function is highly coupled, and if we try to extend any function, it will have a destructive effect on the code structure. Therefore, we think more about code:

  • Can be used
  • Performance is good
  • Convenient and reuse

Based on the above requirements, we need to learn the prototype.

How objects are created

literal

In JS, if you want to create objects for temporary use, just use the literal method. Such as

    const person = {
      name: 'luffy'.skill: "Get bigger and smaller"
    }
Copy the code

The factory function

But if we want to create multiple objects with similar structures, the literal approach is not easy to maintain. Such as

    const person1 = {
      name: 'luffy'.skill: "Get bigger and smaller"
    }
    const person2 = {
      name: The Staff.skill: "Make it thicker and longer."
    }
    const person3 = {
      name: 'Lava Monster'.skill: "Grow strong and firm."
    }
Copy the code

If you want to change the attribute name to username, you need to change it one by one.

So we can use the factory function:

    const person1 = createPerson('luffy'."Get bigger and smaller")

    const person2 = createPerson(The Staff."Make it thicker and longer.")

    const person3 = createPerson('Lava Monster'."Grow strong and firm.")

    // Factory function
    function createPerson(name, skill) {
      return {
        name,
        skill
      }
    }
Copy the code

In this case, when we want to modify the name property, we can simply modify the createPerson function, cleanly.

The constructor

Although the above factory function solves the problem of modifying attributes of multiple objects in batches, it also has disadvantages. Please look at the print below.

In javascript, everything is an object

    function createPerson(name, skill) {
      return {
        name,
        skill
      }
    }

    // Create a normal object
    const person1 = createPerson('luffy'."Get bigger and smaller");
    console.log(person1);


    // Print the literal
    console.log({ name: "Spring roll".skill: In the "volume" });


    // Create a date object
    const date = new Date(a);console.log(date);

    // Create an array object
    const array = new Array(a);console.log(array);
Copy the code

As you can see, js built-in objects are clearly identified. Such as Date or Array, these identifiers are obvious when we look at them. It’s a date and an array.

However, the two objects we created are obvious, with only one Object, and the others are not obvious. The reason is simple

  1. Date, Array.Function.Regex.StringThe Number,BooleanAre alljsPro.
  2. Our self-created objects are wild, so they don’t have names!

I don’t care. I want it, too.

The constructor solves this problem.

    function SuperPerson(name, skill) {
      this.name = name;
      this.skill = skill;
    }

    // Create a normal object
    const person1 = new SuperPerson('luffy'."Get bigger and smaller");
    console.log(person1);
Copy the code

Constructor parsing

  1. A constructor is also a function
  2. The constructor is meant to benew
  3. Inside the constructorthisIs equal to the followingperson1
  4. Not needed inside the constructorreturnThe default isreturn this ;
  5. everynewOnce, a new space is created in memory.

Disadvantages of constructors

Look at the code

    function SuperPerson(name) {
      this.name = name;
      this.say = function () {
        console.log("Reject inner roll from" + this.name + "Start"); }}const p1 = new SuperPerson("The road");

    const p2 = new SuperPerson("Joe,");

    console.log(p1 === p2); // false 

    console.log(p1.name === p2.name);   // false

    console.log(p1.say === p2.say); // false
Copy the code

As we know, the key to data type comparison is

  1. Simple type comparison value comparison luffy ≠ Joba

  2. Comparison of complex types references address comparison

    1. p1p2
    2. p1.sayp2.say
  3. As is shown in

Extracting public functions

It’s easy to understand that the names of different objects are different, but their behavior — the method -say — should be the same. That is, it should be able to be shared, which will save more memory. Anyway, we want to implement

p1.say = p2.say
Copy the code

That’s easy to do. Let’s see

    function say() {
      console.log(this.name);
    }

    function SuperPerson(name) {
      this.name = name;
      // Point to external say
      this.say = say;
    }

    const p1 = new SuperPerson("The road");

    const p2 = new SuperPerson("Joe,");

    console.log(p1.say === p2.say); // true
Copy the code

The principle is shown as follows:

The say method in both objects refers to the same object

Constructor – Prototype

As the above code shows, although it solves the problem of different objects sharing a function, the structure of the code is too ugly.

  1. A function is divided into two entrancessaySuperPerson
  2. sayMethods also lead to global pollution
    function say() {  // The name "say" is yours exclusively
      console.log(this.name);
    }

    function SuperPerson(name) {
      this.name = name;
      // Point to external say
      this.say = say;
    }
Copy the code

So we use prototypes to solve prototype

function SuperPerson(name) { this.name = name; } / / define methods on prototype SuperPerson. Prototype. Say = function () {the console. The log (enclosing name); } const p1 = new SuperPerson(" person "); Const p2 = new SuperPerson(" joba "); console.log(p1.say === p2.say); // trueCopy the code

So the guys should know that there’s no problem writing it this way. But for the underlying reason, we’re going to talk about the prototype in a general way

A colloquial explanation of the prototype

In JavaScript, any object has a prototype, just like everyone has a dad 👨. Next, for the convenience of explanation, we will unify the technical terms

  1. SuperPersonReferred to asThe constructor
  2. p1.p2Referred to asThe instance
  3. prototypeReferred to asA prototype object

Among them

  1. The constructorSuperPersonFather (mother is ok)
  2. p1.p2Understood as aThe child
  3. theprototypeIs understood as the father to teach the childDNA

Whenever the father gives birth to a child, the child must have a piece of DNA, and the child must have access to any property or method claimed by the father on the DNA.

    function SuperPerson(name) {
      this.name = name;
    }

    // Define attributes on DNA
    SuperPerson.prototype.say = function () {
      console.log(this.name);
    }
    SuperPerson.prototype.jump = function () {
      console.log("you jump I jump ");
    }

    const p1 = new SuperPerson("The road");

    // Children can get it
    console.log(p1.say);
    console.log(p1.jump);
Copy the code

In-depth explanation of the prototype

The string methods, array methods, date methods, and re methods we use are all derived from prototypes.

Let’s take an example from arrays

    const list = [1.2.3.4];
    console.log(list);
Copy the code

You can see a lot of our usual methods stored in the __protp__ property of the array.

A quick explanation of what __proto__(four underscores) is.

  1. __proto__Also called a prototype.
  2. It is nonstandard and exists on instances.
  3. Its purpose is to facilitate us to view the prototype in the browser, we do not do anything with it, only to see, not touch.
  4. The constructor’s prototype is equal to the instance’sproto

In short, the ancestor of JavaScript can be traced from the bottom up through Prototype and __proto__.

The constructor’s prototype is equal to the instance’sproto

    // SuperPerson is the constructor
    function SuperPerson() {}const p1 = new SuperPerson();// p1 is an example

    console.log(p1.__proto__ === SuperPerson.prototype); // true
Copy the code

Any constructor is an instance of Function

As long as the prototype of the conditional constructor is equal to the proto of the instance, we can follow through and find the ancestor

    const array = new Array(a);// Array is the constructor
    console.log(Array.__proto__ === Function.prototype); // true

    const date = new Date(a);// Date is a construction drama
    console.log(Date.__proto__ === Function.prototype); // true

    function SuperPerson() {}const p1 = new SuperPerson();// SuperPerson is the constructor
    console.log(SuperPerson.__proto__ === Function.prototype); // true
Copy the code

Function and Object

A lot of guys can’t get past this layer, looking for a direct link. Here need to be clear, the two have no direct contact!!

What about indirect connections

Keep in mind that the constructor’s prototype is equal to the instance’s proto

A Function prototype is an instance of an Object prototype

console.log(Function.prototype.__proto__ === Object.prototype); // true
Copy the code

Object’s prototype is directly related to NULL

Keep in mind that the constructor’s prototype is equal to the instance’s proto

console.log(Object.prototype.__proto__ === null);
Copy the code

Connect the above figures in series

The icing on the cake

Any constructor is an instance of Function

    // Object is a constructor
    const obj = new Object(a);console.log(Object.__proto__ === Function.prototype);
Copy the code

Pictured above,

summary

These are the most feared prototype chains in JavaScript

The key to our determination of constructor and instance immediacy is one sentence

Any constructor is an instance of Function

Above you can draw have not

Prototype application

Learning principles is to make it easier to use technology.

Let’s modify the original example of creating rounded elements

<! DOCTYPEhtml>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
  <title>Document</title>
  <style>
    div {

      width: 100px;
      height: 100px;
      background-color: aqua;
      margin: 100px auto;
    }

    .rds {
      border-radius: 50%;
    }

    @keyframes scale {
      to {
        transform: scale(2); }}.scale {
      animation: scale 1s linear infinite alternate;
    }
  </style>
</head>

<body>
  <script>

    // constructor
    function CreateCurveElement(elementName) {
      const element = document.createElement(elementName);
      this.element = element;
      this.addClass("rds");
    }

    // Specify where to insert the element
    CreateCurveElement.prototype.appendTo = function (parent) {
      document.querySelector(parent).appendChild(this.element);
    }

    // Bind events
    CreateCurveElement.prototype.on = function (eventName, cb) {
      this.element.addEventListener(eventName, cb.bind(this));
    }
    CreateCurveElement.prototype.addClass = function (clsName) {
      this.element.classList.add(clsName);
    }

    const div = new CreateCurveElement("div");
    div.appendTo("body");
    div.on("click".function () {
      this.addClass("scale");
    })

  </script>
</body>

</html>
Copy the code

Inheritance of archetype

Archetypal inheritance is achieved by modifying archetypal objects!

We create a new child constructor to inherit the functionality of the parent constructor.

    // create a child constructor that passes only the image path, passing the rest to the parent constructor
    function CreateCurveImg(src) {
      // Call the parent constructor to help set the value for this
      CreateCurveElement.call(this."img");
      this.element.src = src;
    }

    // The function of the child constructor or the prototype of the parent constructor (has drawbacks)
    CreateCurveImg.prototype = CreateCurveElement.prototype;
    const img1 = new CreateCurveImg("images/1.png");
    img1.appendTo("body");
    img1.on("click".function(){
      this.addClass("scale");
    })
Copy the code

<! DOCTYPEhtml>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
  <title>Document</title>
  <style>
    div {

      width: 100px;
      height: 100px;
      background-color: aqua;
      margin: 100px auto;
    }

    .rds {
      border-radius: 50%;
    }

    @keyframes scale {
      to {
        transform: scale(2); }}.scale {
      animation: scale 1s linear infinite alternate;
    }
  </style>
</head>

<body>
  <script>

    function CreateCurveElement(elementName) {
      const element = document.createElement(elementName);
      this.element = element;
      this.addClass("rds");
    }

    CreateCurveElement.prototype.appendTo = function (parent) {
      document.querySelector(parent).appendChild(this.element);
    }

    CreateCurveElement.prototype.on = function (eventName, cb) {
      this.element.addEventListener(eventName, cb.bind(this));
    }
    CreateCurveElement.prototype.addClass = function (clsName) {
      this.element.classList.add(clsName);
    }


    // create a child constructor that passes only the image path, passing the rest to the parent constructor
    function CreateCurveImg(src) {
      // Call the parent constructor to help set the value for this
      CreateCurveElement.call(this."img");
      this.element.src = src;
    }

    // The function of the child constructor or the prototype of the parent constructor (has drawbacks)
    CreateCurveImg.prototype = new CreateCurveElement();
    const img1 = new CreateCurveImg("images/1.png");
    img1.appendTo("body");
    img1.on("click".function(){
      this.addClass("scale");
    })

  </script>
</body>

</html>
Copy the code

Complement and expand

  1. To determine the relationship between instances and constructors, use the operator instanceof

        // Array is an instance of Function
        console.log(Array instanceof Function); // true
    Copy the code
  2. At present, it is basically using ES6 class instead of ES5 prototype.

    1. A class is called a class. Responsible for wrapping all the code that defines the object together

    2. Extend indicates who to inherit from. Equivalent to

      CreateCurveImg.prototype = new CreateCurveElement();
      Copy the code
    3. Super calls the superclass constructor

      CreateCurveElement.call(this."img");
      Copy the code
    <! DOCTYPEhtml>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
      <title>Document</title>
      <style>
        div {
          border-radius: 50%;
          width: 100px;
          height: 100px;
          background-color: aqua;
          margin: 100px auto;
        }
    
        @keyframes scale {
          to {
            transform: scale(2); }}.rds {
          border-radius: 50%;
        }
    
        .scale {
          animation: scale 1s linear infinite alternate;
        }
      </style>
    </head>
    
    <body>
      <script>
    
    
        class CreateCurveElement {
          constructor(elementName) {
            const element = document.createElement(elementName);
            this.element = element;
            this.addClass("rds");
          }
          appendTo(parent) {
            document.querySelector(parent).appendChild(this.element);
          }
          on(eventName, cb) { this.element.addEventListener(eventName, cb.bind(this)); }
          addClass(clsName) {
            this.element.classList.add(clsName); }}// const div = new CreateCurveElement("div");
        // div.appendTo("body");
        // div.on("click", function () {
        // console.log(" That night ~");
        // })
    
        class CreateCurveImg extends CreateCurveElement {
          constructor(src) {
            super("img");
            this.element.src = src; }}const img1 = new CreateCurveImg("images/1.png");
        img1.appendTo("body");
        img1.on("click".function () {
          this.addClass("scale");
        })
      </script>
    </body>
    
    </html>
    Copy the code

Material information

Wechat account of friends

Add big brother wechat and thousands of peers to enhance technical communication life

hsian_

The last

The code word is not easy and your clicks and likes are my best motivators