6

This is more of a general question than a problem I need solved. I'm just a beginner trying to understand the proper way to do things.

What I want to know is whether or not I should only use objects as prototypes (if that's the correct term to use here) or whether or not it's OK to use them to store things.

As an example, in the test project I'm working on, I wanted to store some images for use later. What I currently have is something like:

var Images = {
    james: "images/james.png",
    karen: "images/karen.png",
    mike: "images/mike.png"
};

Because I would know the position, I figure I could also put them in an array and reference the position in the array appropriately:

var images = ["images/james.png", "images/karen.png", "images/mike.png"];
images[0];

Using the object like this works perfectly fine but I'm wondering which is the more appropriate way to do this. Is it situational? Are there any performance reasons to do one over the other? Is there a more accepted way that, as a new programmer, I should get used to?

Thanks in advance for any advice.

AGx-07_162
  • 301
  • 1
  • 3
  • 14
  • What language are you talking about? Please [edit] your question to include the appropriate tag. As far as this question goes, it depends on how you want to work with the data. If you want to be able to access them by name (e.g., `Images.james`), use an object. – Heretic Monkey May 01 '17 at 17:57
  • I did make that edit right after I posted when I realized. Might need to refresh. It's JavaScript. – AGx-07_162 May 01 '17 at 18:01
  • 1
    This question is waaay too broad I'm afraid and will probably get closed. Think about this though, which is more readable `src="\`${images[0]}\`"` or `src="\`${Images.james}\`"` - there is no right and wrong and performance at this level is not worth thinking about - better to learn as you go along and ask questions on here when/if you hit problems – StudioTime May 01 '17 at 18:08
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures – Waxi May 01 '17 at 18:09
  • An object is a map, an array is a list, they behave differently. Arrays define order of the items (since integers are ordered), objects do not define or preserve the order of attributes. You can easily iterate over array's elements, you have harder time iterating over object's named attributes. Adding or deleting elements in the middle of a (long) list is expensive; objects have no 'middle'. – 9000 May 01 '17 at 18:27

3 Answers3

11

Introduction

Unlike PHP, JavaScript does not have associative arrays. The two main data structures in this language are the array literal ([]) and the object literal ({}). Using one or another is not really a matter of style but a matter of need, so your question is relevant.

Let's make an objective comparison...

Array > Object

  1. An array literal (which is indirectly an object) has much more methods than an object literal. Indeed, an object literal is a direct instance of Object and has only access to Object.prototype methods. An array literal is an instance of Array and has access, not only to Array.prototype methods, but also to Object.prototype ones (this is how the prototype chain is set in JavaScript).

let arr = ['Foo', 'Bar', 'Baz'];
let obj = {foo: 'Foo', bar: 'Bar', baz: 'Baz'};

console.log(arr.constructor.name);
console.log(arr.__proto__.__proto__.constructor.name);

console.log(obj.constructor.name);
  1. In ES6, object literals are not iterable (according to the iterable protocol). But arrays are iterable. This means that you can use a for...of loop to traverse an array literal, but it will not work if you try to do so with an object literal (unless you define a [Symbol.iterator] property).

let arr = ['Foo', 'Bar', 'Baz'];
let obj = {foo: 'Foo', bar: 'Bar', baz: 'Baz'};

// OK
for (const item of arr) {
  console.log(item);
}

// TypeError
for (const item of obj) {
  console.log(item);
}

If you want to make an object literal iterable, you should define the iterator yourself. You could do this using a generator.

let obj = {foo: 'Foo', bar: 'Bar', baz: 'Baz'};

obj[Symbol.iterator] = function* () {
  yield obj.foo;
  yield obj.bar;
  yield obj.baz;
};

// OK
for (const item of obj) {
  console.log(item);
}

Array < Object

  1. An object literal is better than an array if, for some reason, you need descriptive keys. In arrays, keys are just numbers, which is not ideal when you want to create an explicit data model.

// This is meaningful
let me = {
  firstname: 'Baptiste',
  lastname: 'Vannesson',
  nickname: 'Bada',
  username: 'Badacadabra'
};

console.log('First name:', me.firstname);
console.log('Last name:', me.lastname);

// This is ambiguous
/*
   let me = ['Baptiste', 'Vannesson', 'Bada', 'Badacadabra'];
   
   console.log('First name:', me[0]);
   console.log('Last name:', me[1]);
*/
  1. An object literal is extremely polyvalent, an array is not. Object literals make it possible to create "idiomatic" classes, namespaces, modules and much more...

let obj = {
  attribute: 'Foo',
  method() {
    return 'Bar';
  },
  [1 + 2]: 'Baz'
};

console.log(obj.attribute, obj.method(), obj[3]);

Array = Object

  1. Array literals and object literals are not enemies. In fact, they are good friends if you use them together. The JSON format makes intensive use of this powerful friendship:

let people = [
  {
    "firstname": "Foo",
    "lastname": "Bar",
    "nicknames": ["foobar", "barfoo"] 
  },
  {
    "firstName": "Baz",
    "lastname": "Quux",
    "nicknames": ["bazquux", "quuxbaz"]
  }
];

console.log(people[0].firstname);
console.log(people[0].lastname);
console.log(people[1].nicknames[0]);
  1. In JavaScript, there is a hybrid data structure called array-like object that is extensively used, even though you are not necessarily aware of that. For instance, the good old arguments object within a function is an array-like object. DOM methods like getElementsByClassName() return array-like objects too. As you may imagine, an array-like object is basically a special object literal that behaves like an array literal:

let arrayLikeObject = {
  0: 'Foo',
  1: 'Bar',
  2: 'Baz',
  length: 3 
};

// At this level we see no difference...
for (let i = 0; i < arrayLikeObject.length; i++) {
  console.log(arrayLikeObject[i]);
}

Conclusion

Array literals and object literals have their own strengths and weaknesses, but with all the information provided here, I think you can now make the right decision.

Finally, I suggest you to try the new data structures introduced by ES6: Map, Set, WeakMap, WeakSet. They offer lots of cool features, but detailing them here would bring us too far...

Badacadabra
  • 8,043
  • 7
  • 28
  • 49
3

Actually, the way you declared things brings up the "difference between associative arrays and arrays".

An associative array, in JS, is really similar to an object (because it's one): When you write var a = {x:0, y:1, z:3} you can access x using a.x(object) or a["x"](associative array).

On the other hand, regular arrays can be perceived as associative arrays that use unsigned integers as ID for their indexes.
Therefore, to answer your question, which one should we pick ?

It depends : I would use object whenever I need to put names/labels on thing (typically not for a collection of variables for instance). If the type of the things you want to store is homogeneous you will probably use an array (but you can still go for an object if you really want to), if some of/all your things have a different type than you should go for an object (but in theory you could still go for an array).
Let's see this :

var a = {
  x:0,
  y:0,
  z:0
}

Both x,y,z have a different meaning (components of a point) therefore an object is better (in terms of semantic) to implement a point. Because var a = [0,0,0] is less meaningful than an object, we will not go for an array in this situation.


var storage = {
  one:"someurl",
  two:"someurl2",
  three:"someurl3",
}

Is correct but we don't need an explicit name for every item, therefore we might choose var storage = ["someurl","someurl2","someurl3"]




Last but not least, the "difficult" choice :

var images = {
  cathy: "img/cathy",
  bob: "img/bob",
  randompelo: "img/randompelo"
}

and var images = ["img/cathy","img/bob","img/randompelo"] are correct but the choice is hard. Therefore the question to ask is : "Do we need a meaningful ID ?".

Let's say we work with a database, a meaningful id would be better to avoid dozens of loops each time you wanna do something, on the other hand if it's just a list without any importance (index is not important, ex: create an image for each element of array) maybe we could try and go for an array.



The question to ask when you hesitate between array and object is : Are keys/IDs important in terms of meaning ? If they are then go for an object, if they're not go for an array.

Vivick
  • 3,434
  • 2
  • 12
  • 25
2

You're correct that it would be situational, but in general its not a good idea to limit your program by only allowing a finite set of supported options like:

var Images = {
  james: "images/james.png",
  karen: "images/karen.png",
  mike: "images/mike.png"
};

Unless, of course, you happen to know that these will be the only cases which are possible - and you actively do not want to support other cases.

Assuming that you dont want to limit the possibilities, then your array approach would be just fine - although personally I might go with an array of objects with identifiers, so that you arent forced to track the index elsewhere.

Something like:

var userProfiles = [
  {"username": "james", "image": "images/james.png"},
  {"username": "karen", "image": "images/karen.png"},
  {"username": "mike", "image": "images/mike.png"}
];
Steve Land
  • 4,852
  • 2
  • 17
  • 36
  • This makes sense. The actual little program I'm writing does have a limited number of possibilities. Again, as I'm trying to get a grasp on what I can and can't do, I'm not going very broad. In the end I want to get a hand on working with data in a database in which case I'd probably have to approach what I'm doing differently to handle data being added, removed, and modified. In this case, I'm hand entering the few elements I'm actually going to use. – AGx-07_162 May 01 '17 at 20:45