How to build a "class" (with properties and methods) upon which will be created a lot of instances?
JavaScript does not use classes in the same way as Java, C++ or the like. One way to achieve your effect is to define a function in which the this keyword is used--accessing members roughly as you would in Java. Then, use the new keyword in calling this function to create an object.
Closures and classes behave differently in JavaScript with a fundamental difference: closures support encapsulation, while JavaScript classes don't support encapsulation. NB: There is a proposal for this and it is in stage 3. It's enabled in some browsers by default and can also be enabled through a Babel plugin.
JavaScript, being a prototype-based language, has something called constructor functions. Classes, introduced with ES6 provide “syntactical sugar”, that is comparable to inheritance in object-oriented languages. Classes are special functions meant to mimic the class keyword from these other languages.
The "Private field must be declared in an enclosing class" error occurs when we try to read a private value directly from our code outside of the class object. To solve the error, make sure to only read private values from inside of the class. Here's an example of how the error occurs. index.js. Copied!
The modern way is to use class
, as introduced in ES6.
class Movie { constructor(name) { this.name = name; // The "_" prefix is commonly used to denote "private" members. this._id = +new Date(); } getName() { return `${this.name} ${this._id}`; } setName(name) { this.name = name; } } const movie = new Movie('Beerfest'); console.log(movie.getName());
The above example provides an equivalent interface to the original examples from 2010.
In "modern" JavaScript, there are three popular methods for defining objects.
The first method is the classic method and is still popular because of its simplicity; however, it is discouraged by MDC in favor of the second method because of the inefficiency of having to redefine each function every time an instance of the object is created.
// Constructor, methods and members all rolled up into one definition var Movie = function(name) { this.name = name; // Note that private members can be created using the closure property var _id = +(new Date()); this.getName = function() { return this.name + " " + _id; }; this.setName = function(name) { this.name = name; }; }; var m = new Movie("Beerfest");
The second method is a variation of and can be used interchangeably with the first. It is also useful for adding new methods to existing objects via the prototype
property. Private members and methods are not possible in this form.
// Constructor is separate from its methods var Movie = function(name) { this.name = name; } Movie.prototype.getName = function() { return name; }; Movie.prototype.setName = function(name) { this.name = name; }; var m = new Movie("Kill Bill");
The third method is to use the module pattern, which makes it possible to instantiate objects without having to use the new
operator.
var Movie = function (name) { var _id = +(new Date()); var privateMethod = function() { alert(_id); }; // All methods and members defined here are public return { name: name, getName: function() { return this.name + " " + _id; }, setName: function(name) { this.name = name; } }; }; var m = Movie("Stackoverflow: the movie");
Note that in the first and third methods, you can use private access members and methods. But be aware that to use this
within private methods some must happen.
// I like this pattern.. // class function Person(name, birthdate) { this._name = name; this._birthdate = birthdate; /* should not do this * this.getAge = function() { * } * as the method will be constructed * for each instance, better to let it * be inherited from prototype, see below */ } // class methods Person.prototype.getBirthdate = function() { return this._birthdate; } // same as above, function as a method Person.prototype.getAge = function() { var currentDate = new Date(); // age in millis return currentDate - this._birthdate; } // the get age method can be a "static" // method on the constructor function if you pass the // person object Person.getAge = function(person) { var currentDate = new Date(); // age in millis //no reference to this return currentDate - person.getBirthdate(); } // you could use it like this myPerson = new Person("Steve", new Date("1980-01-01")); // returns age in millis myPerson.getAge(); // returns age in millis Person.getAge(myPerson);
You could also use a anonymous function to simulate private and public
var PersonFactory = (function() { // private area, no one can alter // the person cache var _cache = {} // public area return { // returns a person born now getPerson: function(name) { if(_cache[name]) { return _cache[name]; } else { _cache[name] = new Person(name, new Date()); return _cache[name]; } } } })(); var p = PersonFactory.getPerson("Leif"); p.getAge(); p = PersonFactory.getPerson("Leif"); // should be the same age / obj p.getAge();
I don't like this pattern though. The underscore warning _myVariable should be enough to keep users of your lib from using those variables / methods. I used it allot when I first discovered it because of my Java background.. It makes it difficult to work with prototype inheritance and can cause memory leaks.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With