Freedom from the desire for an answer is essential to the understanding of a problem.
-- Jiddu Krishnamurti
There is a clear reason why you should use prototypes when creating classes in JavaScript.
They use less memory.
When a method is defined inside function or object, a new copy is created every time a new object is instantiated. Let's look at an example.
In most Object Oriented programming languages a class has a constructor. A constructor is a sort of initializing function that is called every time a new instance of the class is created. Usually the Constructor function name is defined using the actual class name or the keyword constructor:
// In Java
public class Animal {
private String _name;
// constructor function
public Animal(name){
// this content will be executed when an instance is created:
// Ex: Animal cat = new Animal('cat');
_name = name;
}
}
// In PHP
class Animal {
private $name;
public function __constructor($name){
// this content will be executed when an instance is created:
// Ex: $dog = new Animal('dog');
$this->name = $name;
}
}
But how about in JavaScript? Do we have a constructor? Yes we do, only everything in JavaScript is a weird, so the constructor is the class/function/constructor itself.
function Animal(name) {
// this is the class and the constructor at the same time.
// Ex: let cat = new Animal('cat')
this.name = name
}
So when we call new Animal() the constructor is called immediately. This is where the problem of performance occurs. Imagine I define three functions inside the constructor, this means every single time, those functions are defined anew.
function Animal() {
this.walk = function () {
}
this.talk = function () {
}
this.jump = function () {
}
}
We are creating duplicate functions every single time. If I create two or three objects, then the problem is negligible. But if we create a herd of animals, we start seeing our memory growing because for each animal we are creating a whole new method at run time/instance time.
let cat = new Animal()
let dog = new Animal()
(cat.walk === dog.walk) // false
The walk of the first object is different than the walk of the second object because each was created during instantiation. In other words, Animal does not know that the method walk() exists before being instantiated.
The solution to the problem is to use prototypes. What it does is allow us to define the methods once, as a blue print, and have each instance build from it.
function Animal(){}
Animal.prototype.walk = function () {
}
Animal.prototype.talk = function () {
}
Animal.prototype.jump = function () {
}
Now any new instance has a blue print of the class before being created. So every walk is a walk, and every jump is a jump:
let cat = new Animal()
let dog = new Animal()
(cat.walk === dog.walk) // true
Imagine creating a virtual DOM where each DOM element has a few methods. If you use the non-prototypical way with this you will be recreating each method for each virtual DOM element. Shortly after you will notice your application slowing down. But use prototypes and the methods are defined only once thus take much less memory. This is similar to how jQuery defines methods for DOM elements. They don't create a new .css for each element for example, they define it once using a prototype.
The only inconvenience of using prototypes is that there is no easy way to create private methods or variables.
function Animal() {
// this varialbe is private
let private_var = 10
// this function is public
this.walk = function () {
}
// this function is private
function dance() {
}
}
How you plan to use a class should be the deciding factor for using prototype or non-prototype methods. If you are going to create a lot of instances, use prototypes.
Many developers, especially those from a classical object-oriented background, would prefer a simplification or abstraction of JavaScript that they’re more familiar with, this inevitably leads toward the realm of classes. As a response to this need, several JavaScript libraries that simulate classical inheritance have popped up. Because each library implements classes in its own way, the ECMAScript committee has standardized the syntax for simulating class-based inheritance. Notice how we said simulating. Even though now we can use the class keyword in JavaScript, the underlying implementation is still based on prototype.
Our functionally code can be translated to identical ES6 code with class keyword.
class Animal {
constructor() {
}
walk() {
}
talk() {
}
jump() {
}
}
let cat = new Animal()
let dog = new Animal()
(cat.walk === dog.walk) // also true
网友评论