What is a prototype?

In Javascript, functions can have attributes or attach attributes to functions. Each function has a property called prototype. The stereotype property itself is of object type, and each stereotype object contains two default attributes: constructor and __proto__; Where the constructor property is the constructor of the current function, which can be used to construct an instance of the current function, and __proto__ is a property property that points to the prototype that built the current function.

If we define a function func1, the syntax looks like this:

function func1() {};
Copy the code

Func1’s prototype object (prototype) can be accessed by func1. Prototype. Similarly, we can attach attributes to the prototype object:

function func1() {};
func1.prototype.funcName = 'myFunc1';
console.log(func1.prototype);
Copy the code

Output result:

{funcName: "myFunc1", constructor: ƒ}
funcName: "myFunc1"
constructor: ƒ func1()
__proto__: Object
Copy the code

By combining the above explanations and code examples, we can simply summarize a few key points.

Key knowledge points
  1. Each function has a prototype (prototype);
  2. The prototype itself is an object that can be accessed by the function name.prototype.
  3. The stereotype itself has two default properties:constructorand__proto__, includingconstructorIs the constructor of the current function, which can be used to construct an instance object of the current function.__proto__Is a property property that points to the prototype that built the current function.
  4. The prototype object of a function can have some attributes attached;
Extension problem

Here, the reader can pause to read and memorize the key points above. I pose a few questions for the reader to think about and move on with. The question is:

  1. Every function has a prototype, so is an object with a prototype a function?

I do not know whether the reader has the answer, here I will analyze the problem. First, we can use the instanceof keyword to determine whether an object is an instance constructed by another object. So we can tell if an object is an instanceof Function by using the syntax Obj instanceof Function (functions are all instances of Function).

Here’s an example:

function func1(){}; func1 instanceof Function; Function instanceof Function; // all objects are instances of Object, but is Object a function? Object instanceof Function; // true // Try another built-in object String instanceof Function; // true Number instanceof Function; // true // Try the new ES6 syntax class. Is a class function? class SomeClass{}; SomeClass instanceof Function; // trueCopy the code

Func1, Function, Object, String, Number, and SomeClass have prototype properties on the console. They can all be instantiated using the new keyword, and given that the stereotype itself has the constructor property, we can conclude:

  1. Objects that have archetypes are essentially functions;
  2. Objects with stereotypes can be instantiated using a constructor (constructor) property to instantiate;

What is a prototype chain?

In Javascript, each object has a prototype object from which the object templates and inherits methods and properties. A prototype object may also own a prototype and inherit methods and properties from it, layer by layer, and so on. This relationship is often referred to as a prototype chain.

After reading the explanation, the reader is left with a few questions: What exactly is a prototype chain? What does the prototype chain do? (30 seconds is recommended)

A prototype chain is a chain relationship. In fact, it is a chain relationship between the prototype object and the prototype object, which is called the prototype chain. The prototype object can inherit the properties and methods of the prototype object. In short, a prototype chain represents a chain relationship between the prototype object and the prototype of the prototype object, but essentially because there is an inheritance relationship between the prototype object and the prototype object’s prototype. Therefore, the prototype chain is actually represents the inheritance relationship realized through the prototype in JavaScript language. This inheritance relationship is chaining, so it is called the prototype chain. For example:

function Dog(){}; Dog.prototype.personalName= 'A Dog'; Dog.prototype.bark = () => console.log('wang... '); const wangcai = new Dog(); const erHa = new Dog(); console.log(wangcai.personalName); // 'A Dog' console.log(wangcai.bark()); // 'wang... ' console.log(erHa.personalName); // 'A Dog' wangcai.personalName = 'wangcai'; Bark = () => console.log(' wangwang.bark '); console.log(wangcai.personalName); // 'wangcai' console.log(wangcai.bark()); // 'Wangwang Snow cake'Copy the code

As you can see, the code first defines a function Dog, then defines the attribute personalName and method bark on the prototype of function Dog, and then instantiates two objects wangcai erHa using the keyword new. As you can see, both Wangcai and Erha can use the function Dog attribute PersonalName and method bark, but both wangcai and Erha have the same name as A Dog and will only be called Wang… . At this point, the code has given wangcai a new name and its own unique call (Wangwang Snow Cake), and when it accesses the personalName property and method bark, it accesses the newly assigned properties and methods.

On rational analysis, wangcai inherits the attribute (personalName) method (bark) defined by the function Dog on its prototype. That is, the inheritance is realized through the prototype, and the attributes and methods inherited by Wangcai are reassigned to realize the overloading of attributes and methods. That is to say, the use of prototype (prototype) characteristics, the realization of object-oriented. So, you can also say that Javascript is object-oriented based on prototype implementation.

Summarizing the above text and code examples, the following key points emerge.

Key knowledge points
  1. Javascript realizes inheritance based on prototype and object-oriented based on prototype. The object-oriented of Javascript is object-oriented based on prototype (different from other object-oriented based on class, such as Java).
  2. In the function’s prototype object (prototype) can be inherited and overridden by instance objects of the function;
Extension problem

At this point, the reader might be thinking:

  1. How does an instance of a function inherit its properties and methods?
  2. What kind of mechanism is involved?

We can enter the following code on the console:

Dog.prototype;
erHa.__proto__;
Copy the code

The resulting output is:

{personalName: "A Dog", manufacturer: ƒ, constructor: ƒ} Bark: () => console.log('wang... ') personalName: "A Dog" constructor: ƒ Dog() __proto__: ObjectCopy the code

If you enter the following code on the console:

erHa.__proto__ === Dog.prototype; // true
Dog.__proto__ === Function.prototype; // true
Dog.prototype.__proto__ === Object.prototype; // true
Copy the code

From the above code, the following conclusions can be drawn:

  1. The __proto__ attribute of an object refers to the prototype of the object from which it was constructed;
  2. The __proto__ attribute of the function’s prototype refers to the prototype from which it was constructed: Object.prototype;
  3. ObjectThe prototype (prototype)__proto__The property points tonull;

These three conclusions are short but not easy to understand, so let me break them down. First, the __proto__ attribute of an object refers to the prototype of the object from which it was constructed. For example, we know that the object erHa is constructed from the object Dog (the Function itself is an object), which in turn is constructed from Function (all functions are constructed from Function), as evidenced by the first and second lines above. As an example, we know that Javascript has some built-in specific objects that are themselves functions that can be instantiated (String, Number, Object, etc.) to get the corresponding objects. Since they are both functions, they should all be constructed by Function, so their __proto__ attribute should point to the Function prototype. Verify this with code:

String.__proto__ === Function.prototype; // true
Number.__proto__ === Function.prototype; // true
Object.__proto__ === Function.prototype; // true
Copy the code

And you can see that our idea is validated. So, as some readers might think, Function is itself a Function, so following the first conclusion, Function should be constructed by Function. The Function attribute __proto__ should refer to the Function prototype. The reader can verify that this conjecture is correct by typing the following code on the console.

Function.__proto__ === Function.prototype; // true
Copy the code

After multiple proofs, the first conclusion is correct. Prototype’s __proto__ attribute refers to the prototype from which it was constructed, object.prototype.

In the example above, we defined the Function Dog. String, Number, Function, and Object are all functions. The prototype __proto__ attribute of each of these functions should refer to the prototype of Object. Enter the following code on the console:

Dog.prototype.__proto__ === Object.prototype; // true String.prototype.__proto__ === Object.prototype; // true Number.prototype.__proto__ === Object.prototype; // true Function.prototype.__proto__ === Object.prototype; // true // notice object.prototype. __proto__ === object.prototype; // false Object.prototype.__proto__ === null; // trueCopy the code

It can be seen that the __proto__ attribute of Dog, String, Number and Function (prototype) as functions all refer to the prototype of Object (prototype), confirming conclusion 2. Only the __proto__ attribute of Object (prototype) points to null, confirming conclusion 3.

With that in mind, let’s review our original example. Enter the following code on the console:

wangcai.__proto__ === Dog.prototype;
Dog.prototype.__proto__ === Object.prototype;
Object.prototype.__proto__ === null;	
wangcai.__proto__.__proto__.__proto__ === null;	
Copy the code

As you can see, there is a chain between wangcai, dog. prototype, Object.prototype, and NULL. So, if the properties we defined on the prototype Object are inherited down the hierarchy, wangcai inherits the properties and methods that Dog and Object defined on their prototype.

We define the properties we want to define higher up the object prototype chain, so that objects can inherit those properties and methods. Since functions end up inheriting properties and methods from Object’s Prototype, isn’t it convenient to define all property methods that you want to inherit in Obejct?

It’s a nice idea, but we shouldn’t do it. Javascript does not copy the attributes and methods of the parent class to the object itself at instantiation, unlike the way __ is class-oriented __, which copies the attributes and methods of the parent class to the object itself. Instead, when you access an instantiated object, like erHa, which doesn’t have a property personalName and a method bark defined on it, it goes up the prototype chain, looks for the property personalName and the method Bark on Dog’s prototype, and if it doesn’t, it continues to validate the prototype chain search, Undefined is returned if it is not found. As you can see, if we put all the attributes we want to inherit on Object’s prototype, then accessing these attributes will validate that the prototype chain is looking up, which will cost more performance. So in real development, the properties and methods that you want to inherit should be defined level by level along the prototype chain.

Iii. Extended content: Class and prototype

After reading the above article, the reader can know that class is just a syntactic sugar, its essence is also through the inheritance of prototype implementation, here I will briefly discuss with the reader class prototype. For example:

class Person {}
class Man extends {}
var man1 = new Man();
Person.__proto__ === Function.prototype;
Man.__proto__ === Person;
man1.__proto__ === Man.prototype;
Copy the code

Here we find that the man-like prototype object is actually Person itself, not Person.prototype. So when we add attributes directly to the Person object itself, the Man instance inherits the attributes added to Person through the stereotype chain. When we add attributes to Person.prototype, Man does not inherit through the prototype chain. The code is as follows:

class Person {} class Person {}; class Man extends Person {}; var man1 = new Man(); Person.__proto__ === Function.prototype; Man.__proto__ === Person; man1.__proto__ === Man.prototype; Person.className = 'Person'; Person.prototype.myClassName = 'MyPerson'; console.log('Man.className', Man.className); // Output: man.className Person console.log(' man.myclassname ', man.myclassname); // Output: man.myclassName undefinedCopy the code

As you can see, when we add className to the Person object, man. className is accessible through the prototype chain; However, when we add the person. prototype attribute myClassName, the value of man. myClassName is undefined. This leads us to the conclusion that inheritance in class is actually the prototype object of the parent class itself, not the prototype of the parent class.

Thus, we can simply simulate class as follows:

function Animal() {}; function Dog() {}; Dog.__proto__ = Animal; Animal.className = "Animal"; console.log("Dog.className", Dog.className); Dog. ClassName Animal class Person {}; class Man extends Person {};Copy the code

In the code above, we added the property className directly to Animal. The object Dog also inherits this property and can be accessed directly through dog.classname. This is just an extension, but if you are interested in the relationship between classes and prototypes, you are advised to consult the official documentation or search engines.

References, suggested reading articles:

  1. Object prototype (MDN);
  2. Inheritance in Javascript (MDN);