42

Namely, how does the following code:

var sup = new Array(5);
sup[0] = 'z3ero';
sup[1] = 'o3ne';
sup[4] = 'f3our';
document.write(sup.length + "<br />");

output '5' for the length, when all you've done is set various elements?

My 'problem' with this code is that I don't understand how length changes without calling a getLength() or a setLength() method. When I do any of the following:

a.length
a['length']
a.length = 4
a['length'] = 5

on a non-array object, it behaves like a dict / associative array. When I do this on the array object, it has special meaning. What mechanism in JavaScript allows this to happen? Does JavaScript have some type of property system which translates

a.length
a['length']

into "get" methods and

a.length = 4
a['length'] = 5

into "set" methods?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Claudiu
  • 224,032
  • 165
  • 485
  • 680
  • 1
    @some: i'm new to javascript. i could implement this behavior in python, where i know how to overload __getitem__ et.al., but I have no idea how the innards of javascript work. you seem pretty well-acquainted, if you think this is trivial - please post a reply! – Claudiu Dec 14 '08 at 00:27
  • I'm having major difficulties understanding you question. What is it really you are trying to do? what is missing for you in Javascript? – Eran Galperin Dec 14 '08 at 00:39
  • @Eran: In many languages you can create objects that can use array-like syntax foo[x] without actually being arrays (i.e. have their own logic happening in the background) – Gareth Dec 14 '08 at 00:41
  • @Gareth: Obviously, but in javascript the basic associative dictionary is an object. It can have methods and properties in addition to serving as a hash array – Eran Galperin Dec 14 '08 at 00:42
  • let me try to re-phrase the question. – Claudiu Dec 14 '08 at 00:43
  • I'm sorry if I upset someone. I had written a few words in an answer when I saw the high rep and was very surprised to find that high number. It was not my intention to be patronizing. – some Dec 14 '08 at 00:47

8 Answers8

27

Everything in JavaScript is an object. In the case of an Array, the length property returns the size of the internal storage area for indexed items of the array. Some of the confusion may come into play in that the [] operator works for both numeric and string arguments. For an array, if you use it with a numeric index, it returns/sets the expected indexed item. If you use it with a string, it returns/sets the named property on the array object - unless the string corresponds to a numeric value, then it returns the indexed item. This is because in JavaScript array indexes are coerced to strings by an implicit toString() call. Frankly, this is just one more of those things that makes you scratch your head and say "JavaScript, this, this is why they laugh at you."

The actual underlying representation may differ between browsers (or it may not). I wouldn't rely on anything other than the interface that is supplied when working with it.

You can find out more about JavaScript arrays at MDN.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
tvanfosson
  • 524,688
  • 99
  • 697
  • 795
  • ah this was my question: "In the case of an Array, the length property returns the size of the internal storage area for indexed items of the array.". So I guess my question is 'how do properties work?' - which I can answer myself. I just didn't know where to look! – Claudiu Dec 14 '08 at 00:46
  • (answer myself by googling, i meant - but i might still need help on this part) – Claudiu Dec 14 '08 at 00:51
  • is there any way to use this overloading in a javascript program I create myself, or is this just a special-case for arrays? – Claudiu Dec 14 '08 at 01:15
  • "For an array, if you use it with a numeric index, it returns/sets the proper indexed item. If you use it with a string, it returns/sets the named property on the array object." This is incorrect. Try a[1] = "foo"; print(a["1"]); In javascript objects *every key is a string*. In fact I don't think Arrays are guaranteed to be implemented as arrays at all (they were probably hashmaps in early implementations). – Timmmm Feb 10 '12 at 19:23
  • @Timmmm old comment, but thanks for the prod, made me look at the documentation. I've updated. – tvanfosson Feb 09 '14 at 16:11
  • 1
    `Everything in JavaScript is an object`... except primitives – Josh Hibschman Sep 05 '19 at 14:16
  • When used in property access, keys are either symbols or coerced to strings. This makes indexed collections consistent with general Objects (and everything inheriting from the Object prototype), Proxies, and (in the near future) Records and Tuples. There is no benefit of Array key access being specified as integers; they function in an equivalent way. Implementors may even optimize Array key access using integers. That shouldn’t matter. – Sebastian Simon Oct 11 '21 at 04:43
5

Characteristics of a JavaScript array

  1. Dynamic - Arrays in JavaScript can grow dynamically .push
  2. Can be sparse - for example, array[50000] = 2;
  3. Can be dense - for example, array = [1, 2, 3, 4, 5]

In JavaScript, it is hard for the runtime to know whether the array is going to be dense or sparse. So all it can do is take a guess. All implementations use a heuristic to determine if the array is dense or sparse.

For example, code in point 2 above, can indicate to the JavaScript runtime that this is likely a sparse array implementation. If the array is initialised with an initial count, this could indicate that this is likely a dense array.

When the runtime detects that the array is sparse, it is implemented in a similar way to an object. So instead of maintaining a contiguous array, a key/value map is built.

For more references, see How are JavaScript arrays implemented internally?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Samyak Jain
  • 856
  • 1
  • 9
  • 12
4

This really depends on what you intend to do with it.

[].length is "magical".
It doesn't actually return the number of items in the array. It returns the largest instated index in the array.

var testArr = [];  testArr[5000] = "something";  testArr.length; // 5001

But the method behind the setter is hidden in the engine itself.
Some engines in some browsers will give you access to their implementations of those magic-methods. Others will keep everything completely locked down.

So don't rely on defineGetter and defineSetter methods, or even, really, __proto__ methods, unless you know which browsers you know you're targeting, and which you aren't.

This will change in the future, where opt-in applications written in ECMAScript Next/6 will have access to more.

ECMAScript 5-compliant browsers are already starting to offer get and set magic methods in objects and there's more to come... ...but it's probably a while away before you can dump support for oldIE and a tonne of smartphones, et cetera...

Sebastian Simon
  • 18,263
  • 7
  • 55
  • 75
Norguard
  • 26,167
  • 5
  • 41
  • 49
3

As other people have mentioned, a property in JavaScript can basically act as both as getter and a setter of your array (or string or other inputs).

As a matter of fact, you might try this yourself:

const test = [1, 2, 3, 4, 5]
test.length = 3
console.log(test) // [1, 2, 3]
test.length = 5
console.log(test) // Guess what happens here!

As far as I know, arrays in JavaScript do not work exactly like associative arrays and you have elements which are put in memory as contiguously as possible (given that you can have arrays of mixed objects), depending on the JavaScript engine you are considering.

As a side note, I am a bit baffled that the most voted answer keeps spreading the over-simplified myth (or half-truth) of "everything being an object in JavaScript"; that is not exactly true, otherwise you will never study primitives, for example.

Try to do this:

const pippi = "pippi"
pippi.cat = "cat"
console.log(pippi.cat) // Will it work? Throw an error? Guess why again

Spoiler: the string is wrapped in a throwaway object for that specific operation on the second line, and then in the following one you are just going to access a property of the primitive which is not there (provided you did not play with String.prototype or the like), so you get undefined.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Ajna
  • 71
  • 1
  • 12
2

It is important to know that when you do sup['look'] = 4; you are not using an associative array, but rather modify properties on the object sup.

It is equivalent to sup.look = 4; since you can dynamically add properties on JavaScript objects at any time. sup['length'] would for an instance output 5 in your first example.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
finpingvin
  • 692
  • 1
  • 7
  • 14
  • can property access / mutation be turned into a method call? if not, how would the 'length' property change if I've only modified the '0' and '1' properties? – Claudiu Dec 14 '08 at 00:51
  • An array is always an array, but in sup['look'] you are modifying the properties of the array-object, but when you do sup[0] you are accessing the array-index, not the object propery. I think tvanfosson explained it pretty good :) – finpingvin Dec 14 '08 at 00:55
2

To add to tvanfosson's answer: In ECMA-262 (the 3.0 specification, I believe), arrays are simply defined as having this behavior for setting properties (See 15.4.5.1). There's no general mechanism underlying it (at least as of now) - this is just how it's defined, and how JavaScript interpreters must behave.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Claudiu
  • 224,032
  • 165
  • 485
  • 680
1

Array object inherits caller, constructor, length, and name properties from Function.prototype.

Eugene Yokota
  • 94,654
  • 45
  • 215
  • 319
0

A JavaScript array is an object just like any other object, but JavaScript gives it special syntax.

arr[5] = "yo"

The above is syntactic sugar for

arr.insert(5,"yo")

which is how you would add stuff to a regular object. It's what is inside the insert method that changes the value of arr.length

See my implementation of a customArray type here: http://jsfiddle.net/vfm3vkxy/4/

Niko Bellic
  • 2,370
  • 2
  • 29
  • 25