Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the best way to create JavaScript classes? [duplicate]

Tags:

javascript

oop

Possible Duplicate:
Use of ‘prototype’ vs. ‘this’ in Javascript?
Object Oriented questions in Javascript

Can you please recommend which of the following is the best or their pros and cons?

Method 1

function User() {      this.name = "my name";     this.save = function() {      }; } 

Method 2

function User() {      this.name = "my name"; }  User.prototype.save = function() {  } 
like image 873
Arunoda Susiripala Avatar asked Nov 02 '12 05:11

Arunoda Susiripala


People also ask

How do you duplicate a class in JavaScript?

To clone a JavaScript class instance, we can use some object methods. to create the Foo class. Then we create a new Foo instance and assign it to foo . To create a clone of foo , we call Object.

What is copy constructor in JavaScript?

A copy constructor is a constructor that uses another instance of the current class to set up the current instance. Copy constructors are popular in static languages such as C++ and Java, where you can provide multiple versions of a constructor via static overloading.

Can an object have multiple classes JavaScript?

No, in JavaScript, a class cannot extend from multiple classes, which is also known as “multiple inheritance”. In JavaScript, objects can only be associated with a single prototype, and extending multiple classes would mean that an object associates with multiple prototypes, which is not possible.


1 Answers

Coming from a background in Java and PHP, I had initially struggled with the whole 'class' concept in JavaScript. Here are a few things to think about.

Construction

First, since you're likely going to be defining your classes as..

Customer = function () {} Customer.prototype = new Person(); 

You will end up running into all sorts of nightmares of code if you are defining properties and methods during construction. The reason being is that a piece of code like Customer.prototype = new Person(); requires that the Person be called in the Customer constructor for true inheritance.. otherwise you'll end up having to know what the original one sets at all times. Take the following example:

Person = function (name) {     this.name = name;     this.getName = function () {return this.name} } Customer = function (name) {     this.name = name; } Customer.prototype = new Person(); 

Now we're going to update Person to also set whether they are 'new':

Person = function (name, isNew) {     this.name = name;     this.isNew = isNew;     this.getName = function () {return (this.isNew ? "New " : "") + this.name; } } 

Now on any 'class' that is inheriting from the Person, you must update the constructor to follow form. You can get around that by doing something like:

Customer = function () {     Person.apply(this, arguments); } 

That will call 'Person' in the scope of the new 'Customer', allowing you to not have to know about the Person construction.

Speed

Take a look at these benchmarks: http://jsperf.com/inherited-vs-assigned.
Basically, what I am attempting to prove here is that if you're creating these objects en masse, your best route is to create them on the prototype. Creating them like:

Person = function (name) {     this.name = name;     this.getName = function () {return this.name} } 

is very slow, because for every object creation, it creates a new function - it doesn't simply look up the prototype chain for the already existing one. Conversely, if you've got only a few objects that the methods are called extremely frequently on, defining them locally helps with the speed lost by looking up the prototype chain.

Shared properties

This always gets me. Let's say you've got something like the following:

Person = function () {     this.jobs = {};     this.setJob = function (jobTitle, active) {this.jobs[jobTitle] = active; } }  Employee = function () {} Employee.prototype = new Person();  var bob = new Employee(); bob.setJob('janitor', true);  var jane = new Employee(); console.log(jane.jobs); 

Guess what? Jane's a janitor! No joke! Here's why. Since you didn't define this.jobs as being a new object on instantiation of the Employee, it's now just looking up the prototype chain until it finds 'jobs' and is using it as is. Fun, right?

So, this is useful if you want to keep track of instances, but for the most part you're going to find it incredibly frustrating. You can get around that by doing the following:

Employee = function () { Person.apply(this); } 

This forces 'Person' to create a new 'this.jobs'.

Private variables

Since there's nothing that's really "private" in JavaScript, the only way you can get private variables is to create them in the constructor, and then make anything that relies on them initialize in the constructor.

Person = function () {     var jobs = {};     this.setJob = function (jobTitle, active) {jobs[jobTitle] = active; }     this.getJob = function (jobTitle) { return jobs[jobTitle]; } } 

However, this also means that you must call that constructor on every instantiation of an inherited class.


Suggestion

http://ejohn.org/blog/simple-javascript-inheritance/

This is a super basic class setup. It's easy. It works. And it'll do what you need it to do 90% of the time without having to deal with all the insanity JavaScript has to offer :)

</rant>

like image 134
Stephen Avatar answered Sep 24 '22 15:09

Stephen