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:
Framework heavy user
Our current mainstream front-end business is almost all usedvue
To react,Wechat applets
In 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.- Basic knowledge of
Still no home
Are in useThe framework
Doing business, there is no time to in-depth study of technical principles, and no ability to sealLoading of rolling
. - 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:
- encapsulation
- Inheritance (I also classify inheritance in encapsulation)
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
- Reuse common code, such as
createElement
.onclick
,classList.add
- 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
Date
, Array.Function
.Regex
.String
The Number,Boolean
Are alljs
Pro.- 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
- A constructor is also a function
- The constructor is meant to be
new
的 - Inside the constructor
this
Is equal to the followingperson1
- Not needed inside the constructor
return
The default isreturn this
; - every
new
Once, 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
-
Simple type comparison value comparison luffy ≠ Joba
-
Comparison of complex types references address comparison
p1
≠p2
p1.say
≠p2.say
-
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.
- A function is divided into two entrances
say
和SuperPerson
say
Methods 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
SuperPerson
Referred to asThe constructor
p1
.p2
Referred to asThe instance
prototype
Referred to asA prototype object
Among them
- The constructor
SuperPerson
Father (mother is ok) p1
.p2
Understood as aThe child
- the
prototype
Is 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.
__proto__
Also called a prototype.- It is nonstandard and exists on instances.
- 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.
- 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
-
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
-
At present, it is basically using ES6 class instead of ES5 prototype.
-
A class is called a class. Responsible for wrapping all the code that defines the object together
-
Extend indicates who to inherit from. Equivalent to
CreateCurveImg.prototype = new CreateCurveElement(); Copy the code
-
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