0

What is the preferred way of defining common fields for all instances of a class in Javascript? Via prototype or constructor?

function A() {
}

A.prototype.names = ['1', '2', '3']

Or

A.names = ['1', '2', '3']

I understand that these two ways require different access patterns, e.g., this.names and A.names, respectively.

Wickoo
  • 6,745
  • 5
  • 32
  • 45
  • 1
    You seem to understand the issue at hand. There is no correct answer, just different options and preferences and this means this is not a good fit for StackOverflow . – Ruan Mendes Jun 03 '18 at 11:37
  • I have a strong feeling that there is actually an correct answer, as long as javascript is convention over configuration language. So convention decides what is best and how to do that better necessity way. – Allan Felipe Murara Jun 04 '18 at 02:16

3 Answers3

1

For non-primitive types, you most of the time don't want to set them in the prototype. The "problem" with the prototype base version, is that all instance would share the same object.

function A() {
}

A.prototype.names = ['1', '2', '3']

var a1 = new A()
var a2 = new A()

a1.names.push(4);

console.log(a1.names);
console.log(a2.names);

Only if you really want to share the same object among all instance you would you the prototype based solution. But even then I would go with the static like entry and assign it to the constructor:

A.names = ['1', '2', '3']

Because then it's clear that is it a shared object, that is the same for all.

t.niese
  • 39,256
  • 9
  • 74
  • 101
  • Retracted my upvote because the OP is asking about adding the properties to the constructor, as in static fields. However, here's a dirty plug for a post that explains what you are referring to http://js-bits.blogspot.com/2014/10/understanding-prototypical-inheritance.html – Ruan Mendes Jun 03 '18 at 10:42
  • @t.niese I see your point, but with constructor, there is also only one instance of the array and you can modify it. Is it preferred because the access is static and it's more explicit? – Wickoo Jun 03 '18 at 10:43
  • That's what I'm saying in my answer, I'd rather refer to `A.names` instead of `A.prototype.names` if I don't have an instance of it – Ruan Mendes Jun 03 '18 at 10:44
0

They are similar ways. There will be only one copy of the names array.

If you need it accessible without an instance, you should put it on the constructor since it will be easier for others to access: A.names instead of A.prototype.names.

If you have a case where it will always be accessed by the instance, then you may put it on the prototype so callers can refer to this.names, but I'd suggest against that since it's not very intuitive.

But it doesn't make a difference, it's just a matter of convenience when calling it.

Having said that, my personal preference in these day of JS modules is to just export a separate const from the module. That way you don't need to prefix it with anything in the class itself and the callers and you can rename it when you import it if you wish. If you do it for private static variables, then you make them truly private.

// A.js
export class A () {}
export const names = ["", "a"];
// main.js
import A, names as ANames from "a";
console.log("look ma, no prefix for static fields", ANames);
Ruan Mendes
  • 90,375
  • 31
  • 153
  • 217
0

previous answers are not wrong, but i would like to give you an detailed feedback about what you are talking about. First of all remember, everything is object in JS. (functions, classes related, How is almost everything in Javascript an object? )

The way you are dealing with, is not using constructor. Prototype is a context (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this) . Remember, constructors are part of the object (function) creation, and they are basically the function itself, so you gonna use function A() { this.names = [1,2,3,4] } and simple instance new A();

If you really believe that you need to hook it in the constructor take a look at - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor

Follow this, is the closes to the right answer you will find.

Now that we know what a 'context' mean to an object, let's discuss what you can do with our new friend, prototype "context"!

function names(names) {
  this.names = names;
  return this.names;
}
const assigned1 = new names('allan');
console.log('first assign', assigned1);

names.prototype.reassign = function() { this.names = [ ...arguments ]};

assigned1.reassign('allan', 'joao', 'maria');

console.log('reasigned', assigned1);

That said, If you really need to have a .names into your object ( that is not common to js ), go with constructor. Otherwise you will be doing a not suggested approach. But whenever you want to go a bit deeper, try out the concept of geters and seters in js :) They are more what you need, you also need to avoid setting objects directly in functions, it is not a good approach =) try out creating a new JSON object.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set