This is the 27th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021

Relearn the Front End -JavaScript(3)

1. What is a prototype?

Archetypes are the products of natural human thinking. In Chinese, there is an idiom “imitate the cat and draw a tiger”. The cat here looks like the prototype of the tiger, so we can see that the method of describing objects with prototypes is ancient

The most successful genre is the use of “classes” to describe objects, giving rise to popular programming languages such as C++ and Java. This school is called class-based programming languages.

Then there are prototype-based programming languages, which use stereotypes to describe objects. Our JavaScript is one of them. Prototype – based object-oriented systems create new objects by “copying”

2. Prototype of JavaScript

  • If all objects have private fields [[prototype]], that is the prototype of the object. Read a property,
  • If the object itself does not exist, access to the object’s prototype continues until the prototype is empty or found.

This model hasn’t changed much in various historical versions of ES, but since ES6, JavaScript has provided a series of built-in functions for more direct access to manipulation prototypes. The three methods are as follows:

Create creates a new Object based on the specified prototype. The prototype can be null.

Object.getprototypeof Gets the prototype of an Object.

3, Object.setPrototypeOf Sets the prototype of an Object.

With these three approaches, we can abandon class thinking altogether and use prototypes for abstraction and reuse. I use the following code to show an example of abstracting a cat and a tiger with a prototype.


var cat = {
    say(){
        console.log("meow~");
    },
    jump(){
        console.log("jump"); }}var tiger = Object.create(cat,  {
    say: {writable:true.configurable:true.enumerable:true.value:function(){
            console.log("roar!"); }}})var anotherCat = Object.create(cat);

anotherCat.say();

var anotherTiger = Object.create(tiger);

anotherTiger.say();

Copy the code

Given that infrastructure such as the New and Prototype attributes are still in place today and are used by a lot of code, and that learning about them can help us understand how prototypes work at runtime, let’s take a look back to the early days of JavaScript with stereotypes and classes.

3. Classes and prototypes in earlier versions

In earlier versions of JavaScript, the definition of a “class” was a private attribute [[class]], and the language standard specified a [[class]] attribute for built-in types such as Number, String, Date, and so on to represent their classes. The only language users can access the attributes of the [[class]] is the Object. The prototype. ToString.

The following code shows all objects with built-in class attributes:

    var o = new Object;
    var n = new Number;
    var s = new String;
    var b = new Boolean;
    var d = new Date;
    var arg = function(){ return arguments} ();var r = new RegExp;
    var f = new Function;
    var arr = new Array;
    var e = new Error;
    console.log([o, n, s, b, d, arg, r, f, arr, e].map(v= > Object.prototype.toString.call(v))); 
Copy the code

Starting with ES5, the [[class]] private attribute is replaced by symbol.toStringTag,

    var o = { [Symbol.toStringTag]: "MyObject" }
    console.log(o + "");
Copy the code

Here to create a new Object and give it the only one attribute Symbol. ToStringTag, we use string addition triggered the Object. The prototype. ToString calls, Finally found this attribute for the Object. The prototype. ToString has influenced the results.

4, new operation

The new operation is for the constructor object, not the class. “Here’s what the new operation does.

The new operation, which takes a constructor and a set of call parameters, actually does several things:

  • Create a new object based on the constructor’s Prototype property (note the distinction with the private field [[prototype]]).
  • Pass this and the call arguments to the constructor, and execute; If the constructor returns an object, otherwise the object created in the first step is returned.

Behavior like new tries to make function objects syntactically similar to classes, but it objectively provides two ways to add properties to the constructor and to the constructor’s Prototype property.

The following code shows two ways to emulate a class with a constructor:

function c1(){
    this.p1 = 1;
    this.p2 = function(){
        console.log(this.p1); }}var o1 = new c1;
o1.p2();



function c2(){
}
c2.prototype.p1 = 1;
c2.prototype.p2 = function(){
    console.log(this.p1);
}

var o2 = new c2;
o2.p2();
Copy the code

The first method is to modify this directly in the constructor, adding attributes to this.

The second method is to modify the object pointed to by the constructor’s Prototype property, which is the prototype of all objects constructed from the constructor.

In earlier versions of object.create, Object.setProtoTypeof, new was the only method that could specify [[prototype]] (Mozilla at the time provided a private __proto__ attribute, But most environments don't support it), so there were attempts to use it to replace the later Object.create, and we could even use it to implement an incomplete polyfill of Object.create,Copy the code
Object.create = function(prototype){
    var cls = function(){}
    cls.prototype = prototype;
    return new cls;
}
Copy the code

5. Classes in ES6

In any scenario, I recommend using ES6 syntax to define classes and returning function to its original function semantics. The class keyword was introduced in ES6, and all [[class]] related private attribute descriptions were removed from the standard. The concept of class was officially upgraded from attribute to language infrastructure, and class-based programming became the official programming paradigm of JavaScript.


class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
  // Getter
  get area() {
    return this.calcArea();
  }
  // Method
  calcArea() {
    return this.height * this.width; }}Copy the code

Getters/setters and methods are the most compatible of the existing class syntax.

Getters are created using the get/set keyword, methods are created using parentheses and braces, and data members are best written inside constructors.

The way classes are written is actually carried out by the stereotype runtime. Logically, JavaScript thinks of each class as a set of objects with a common stereotype, and the methods and properties defined in the class are written on top of the stereotype object.


class Animal { 
  constructor(name) {
    this.name = name;
  }
  
  speak() {
    console.log(this.name + ' makes a noise.'); }}class Dog extends Animal {
  constructor(name) {
    super(name); // call the super class constructor and pass in the name parameter
  }

  speak() {
    console.log(this.name + ' barks.'); }}let d = new Dog('Mitzie');
d.speak(); // Mitzie barks.
Copy the code

6,

In the new ES version, we no longer need mock classes: we have a clean new syntax. Prototype architecture exists as both a programming paradigm and a runtime mechanism. We are free to choose either a prototype or a class as our code’s abstraction style, but either way, it is important to understand the prototype system at runtime. So when designing code with classes in mind, we should try to declare classes using classes rather than using the old syntax of simulating objects with functions. Some radical ideas suggest that the class keyword and arrow operators can completely replace the old function keyword, which makes a clearer distinction between the intent to define functions and classes, and I think there is some truth to this.