Related
Are arrays merely objects in disguise? Why/why not? In what way(s) are they (such/not)?
I have always thought of arrays and objects in JS as essentially the same, primarily because accessing them is identical.
var obj = {'I': 'me'};
var arr = new Array();
arr['you'] = 'them';
console.log(obj.I);
console.log(arr.you);
console.log(obj['I']);
console.log(arr['you']);
Am I mislead/mistaken/wrong? What do I need to know about JS literals, primitives, and strings/objects/arrays/etc...?
Are arrays/objects merely strings in disguise? Why/why not? In what way(s) are they (such/not)?
Arrays are objects.
However, unlike regular objects, arrays have certain special features.
Arrays have an additional object in their prototype chain - namely Array.prototype. This object contains so-called Array methods which can be called on array instances. (List of methods is here: http://es5.github.com/#x15.4.4)
Arrays have a length property (which is live, ergo, it auto-updates) (Read here: http://es5.github.com/#x15.4.5.2)
Arrays have a special algorithm regarding defining new properties (Read here: http://es5.github.com/#x15.4.5.1). If you set a new property to an array and that property's name is a sting which can be coerced to an integer number (like '1', '2', '3', etc.) then the special algorithm applies (it is defined on p. 123 in the spec)
Other than these 3 things, arrays are just like regular objects.
Read about arrays in the spec: http://es5.github.com/#x15.4
Objects are an unordered map from string keys to values, arrays are an ordered list of values (with integer keys). That's the main difference. They're both non-primitive, as they're composed of multiple values, which also implies pass-by-reference in JavaScript.
Arrays are also a kind of object, though, so you can attach extra properties to them, access their prototype and so on.
In your revised example, you're only taking advantage of the fact that an array is actually an object, i.e. you can set any property on them. You shouldn't do that. If you don't need an ordered list of values, use a plain object.
Strings can be either primitive or objects, depending on how they were declared.
var str = 'yes';
Gives you a primitive, while,
var str = new String('yes');
will give you a String object.
All arrays are the same (Whether or not they were defined with [] or new Array()), are of the type object and inherit from the "Array" object's prototype. There aren't real classes in Javascript, everything is an object, and there's a system defined object called Array. It has a property called 'prototype' (of type object), and when you use the new keyword on an object with a prototype property, it creates an instance with a reference to the contents of the prototype and stores it in your variable. So all arrays you've ever used in Javascript are objects and instances of Array's prototype property.
In any case, although arrays really are objects, they behave like arrays because of their useful properties and functions (Such as length, slice, push etc).
Another note, although I said there are no classes, when you do this:
console.log(Object.prototype.toString.call(your_object));
it will give you a string in the form [object Object]. But what's useful is that when you call it with an array, you get [object Array] same with functions which give [object Function] and a number of other system defined types, which assists in differentiating between normal objects and arrays (Since the typeof operator will always just return the string 'object').
Try this
var a = Array;
and go into firebug and examine the contents of a, especially it's 'prototype' property.
Edit: Changed the wording a bit, to be more correct. In fact when you use the new keyword, it creates an instance which references the prototype object. So any changes made to the prototype after the instance's declaration, will still affect the instance.
Edit: In answer to your latest revised question (are arrays/objects actually strings in disguise): No. They are objects, as I've explained. Strings are either a primitive type, or an object type (An instance of the String object) which contains the primitive equivalent as one of it's properties.
Arrays are not primitives in Javascript, they are objects. The key difference is that as a result, when you pass an array to a function it is passed by reference, not by value.
So yes! Arrays are objects in javascript, with a full blown Array.prototype and everything (don't touch that though...)
The confusion comes from the fact that javascripts lets you access object attributes in two ways:
myObj.attribute
or
myObj["attribute"]
Really what makes an array an array has nothing to do with the way you store data -- any object can store values using the syntax you use to store the array -- what makes an array an array is the fact that array methods (e.g. shift() and sort()) are defined for Array.prototype.
Trying to be brief with what I believe to be of the most significance: arrays have a number of methods that objects do not. Including:
length
push
pop
An object declared as var x = {foo:bar} has no access to a .length() method. They are both objects but with the array as a sort of superset with methods mentioned as above.
I don't feel I this is even close to being of Crockford standard in terms of explanation but I'm trying to be succinct.
If you want to get some quick results, open up Firebug or your javascript Console and try Array.prototype and Object.prototype to see some details
Update: In your example you declare an array and then do:
foo['bar'] = 'unexpectedbehaviour';
will produce unexpected results and won't be available in simple loops such as:
var foo=[0,1];
foo['bar'] = 2;
for(var i=0;i<foo.length;i++){
console.log(foo[i]);
}
//outputs:
//0
//1
An array can accept foo['bar']=x or foo.bar=y like an object but won't necessarily be available to be looped through as highlighted above.
Not that I'm saying that you can't iterate through the properties of an object, just that when working with an Array, you're utilising that unique functionality and should remember not to get confused.
In JavaScript you have a few types, everything else is an object. The types in JavaScript are: boolean, number, and string. There are also two special values, "null" and "undefined".
So the quest "is a JavaScript array an object?" is slightly ambiguous. Yes, a JavaScript array is an "object" but it is not an instance of "Object". A JavaScript array is an instance of "Array". Although, all objects inherit from Object; you can view the inheritance chain on the MDC. Additionally, arrays have slightly different properties than an object. Arrays have the .length property. They also have the .slice(), .join(), etc methods.
Douglas Crockford provides a nice survey of the language's features. His survey discusses the differences you are asking about. Additionally, you can read more about the difference between literals and constructors in question #4559207.
Arrays are Objects, but of a specialized nature. Objects are collections of values indexed by keys (in Javascript notation, {'key': 'value'}), whereas Arrays are Objects whose keys are numeric (with a few functions and properties). The key difference between them is obvious when you use a for each loop--an Object will iterate over all the values in its properties, whereas an Array will return the keys instead. Here's a link to a JSFiddle demonstrating the difference--notice that the first for each, which uses an array, returns the indexes, not the values; in contrast, the second for each returns the actual values at those keys.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
As we already know, one of the differences between an array and object is:
"If you want to supply specific keys, the only choice is an object. If you don't care about the keys, an array it is" (Read more here)
Besides, according to MDN's documentation:
Arrays cannot use strings as element indexes (as in an associative
array) but must use integers
However, I was surprised that:
> var array = ["hello"]; // Key is numeric index
> array["hi"] = "weird"; // Key is string
content structure looks like: ["hello", hi: "weird"]
The content structure of the array looks weird.
Even more, when I check the type of array it returns true
Array.isArray(array) // true
Questions:
Why have this behavior? This seems inconsistent, right?
What is the data structure actually storing behind the scene: as an array or something like an object, hash table, linked list?
Does this behavior depend on a specific JavaScript engine (V8, spidermonkey, etc..) or not?
Should I use arrays like this (keys are both numeric index and string) over normal objects?
An array in JavaScript is not a separate type, but a subclass of object (an instance of the class Array, in fact). The array (and list) semantics are layered on top of the behavior that you get automatically with every object in JavaScript. JavaScript objects are actually instances of the associative array abstract data type, also known as a dictionary, map, table, etc., and as such can have arbitrarily-named properties.
The rest of the section of the MDN docs you quoted is important:
Setting or accessing via non-integers using bracket notation (or dot
notation) will not set or retrieve an element from the array list
itself, but will set or access a variable associated with that array's
object property collection. The array's object properties and list of
array elements are separate, and the array's traversal and mutation
operations cannot be applied to these named properties.
So sure, you can always set arbitrary properties on an array, because it's an object. When you do this, you might, depending on implementation, get a weird-looking result when you display the array in the console. But if you iterate over the array using the standard mechanisms (the for...of loop or .forEach method), those properties are not included:
> let array = ["hello"]
> array["hi"] = "weird"
> for (const item of array) { console.log(item) }
hello
> array.forEach( (item) => console.log(item) )
hello
The MDN statement that "The array's object properties and list of array elements are separate" is slightly exaggerated; the indexed elements of an array are just ordinary object properties whose keys happen to be numbers. So if you iterate over all of the properties with for..in, then the numeric ones will show up along with the others. But as is well-documented, for..in ignores the Array-ness of arrays and should not be used if you're looking for arraylike behavior. Here's another page from MDN that talks about that:
Array iteration and for...in
Note: for...in should not be used to iterate over an Array where the index order is important.
Array indexes are just enumerable properties with integer names and are otherwise identical to general object properties. There is no
guarantee that for...in will return the indexes in any particular
order. The for...in loop statement will return all enumerable
properties, including those with non–integer names and those that are
inherited.
Because the order of iteration is implementation-dependent, iterating over an array may not visit elements in a consistent order.
Therefore, it is better to use a for loop with a numeric index (or
Array.prototype.forEach() or the for...of loop) when iterating over
arrays where the order of access is important.
So to answer your questions:
Why have this behavior? This seems inconsistent, right?
"Why" questions are always difficult to answer, but fundamentally, the answer in this case seems to be that what you are seeing is not an intentional behavior. As far as we can tell, Brendan Eich and the subsequent designers of JavaScript didn't set out to make an array type that also allows non-numeric keys; instead, they elected not to make an array type at all. In JavaScript, there are only eight types: Null, Undefined, Boolean, Number, BigInt, String, Symbol, and Object. Array didn't make the cut — it's not a separate type, but just a class of object. In fact, you could remove arrays from the core language and implement them entirely in JavaScript itself (although you'd lose the convenience of the [...] literal syntax).
So that's why: JavaScript arrays aren't their own type, but just a class of object; all objects in JavaScript are associative arrays; therefore, you can use arrays as associative arrays.
What is the data structure actually storing behind the scene: as an array or something like object, hashtable, linkedlist?
The ECMAScript specification requires objects to function as associative arrays, but does not dictate the implementation; you can assume that they're hash tables without losing any generality. But since the Array class is typically part of the core language implementation rather than pure JavaScript runtime code, I would not be surprised to find that it included special optimizations beyond the generic-object property-handling code for handling the numerically-indexed values more efficiently. As long as the semantics are the same, it doesn't matter.
Whether this behavior depends on a specific JavaScript Engine (V8, SpiderMonkey, etc..) or not?
Different engines might change how Array values are displayed/serialized, and in particular whether such string representations include the non-numeric properties. But the underlying behavior of being able to store arbitrary key–value pairs is a natural side-effect of the language's design and should be universal across all implementations compliant with the ECMAScript specification.
Should I use array like this(keys are both numeric index and string) over normal object?
Well, again, an array is a normal object. But for maximum readability and minimum surprise to those reading your code, I would not recommend using the same object as both a regular and associative array. You could implement a new class that has array-like behavior, maybe even inherit from the Array prototype, but it's usually going to be better to keep those two data structure types separate.
This stumped me recently as well! It seemed to me that if JavaScript allows something like ['a', b: 'c'], it must support associative arrays, so why all the redundancy?
Upon further research, I realized while this does look like an associative array or a JS object…
It's not an associative array, because JS does not actually support them unless we are synonymizing "associative array" and "object".
It IS an array, which is why Array.isArray(array) returned true.
EPIPHANY moment — arrays ✨ ARE ✨ objects. Hear me out 👇🏼
TL;DR
Here are the TL;DR versions of my answers to your questions. For more context and examples, keep scrolling…
On the surface, it does seem inconsistent, but it's actually very consistent when you take a deeper look at the prototype chain and primitive types vs. reference types.
Your array is an array even behind the scenes, but arrays in JS are a type of object and thus can be assigned custom properties in addition to their usual array elements.
Nope! No specific engine needed for this. This is just pure JavaScript.
If you require keys to be numeric and alphanumeric, use an object. HOWEVER, if you would like to use an array, it's perfectly okay to add custom properties to that array as well. Just keep in mind they are only properties of the object, not array elements.
If you require keys, and you also want to maintain the insertion order of your keys (since JS objects cannot reliably retain their property order), consider using a Map object-type instead.
The long version
Almost everything in JavaScript is some sort of object in one way or another, especially if you start exploring the __proto__ chain (MDN docs). In the same way, your array is an array, but it's also an object, just as all arrays are.
However, when you add a value to your array with a key like array["hi"] = "weird", you're not actually pushing a new value to the array, or even a key to the object for that matter in the usual JS objects kind of way, but rather, you are adding a property to the object that the array actually belongs to. So you will still be able to call that property like this:
array.hi // -> "weird"
…but this item is not actually an element in your array, so the below array, even though it's full of properties still only has a length of one.
const array = [];
array.push(1);
array['a'] = 'funky';
array.length; // -> 1
Even more interesting, this only happens when trying to pass an index with an alpha character in it. Even if you pass a numerical string, it will still push the value to the array in the usual/expected way. It's when alpha characters are present that arrays fall back to assigning properties instead of pushing array items.
Stranger yet — you can not only reference these properties without them "counting against" your array length, but you can actually store entire arrays and objects in these properties too as you would any other JS object.
const array = [];
array.push(1);
array['a'] = { b: 'test1', c: ['test2', 'test3']};
array.a.c[1]; // -> "test3"
array.length; // -> 1
Answers to your questions
1. Why have this behavior? This seems inconsistent, right?
Yes and no. This behavior is actually there to be consistent with the object-oriented nature of JavaScript as a whole. At the same time, as you mentioned, this is not consistent with the usual usage of JavaScript arrays and in most cases would likely baffle another developer working on a project where this was used in practice, so I wouldn't advise assigning properties to an array as a means of entry into that array, as it does not function that way.
However, properties are useful in all objects, and it is perfectly safe to add custom properties to any object as long as you are careful not to overwrite existing ones you might need. When you initialize an array [], it has a length of 0, right? Right. But does it already have inherent custom properties? Yep!
If you run the below code, you get ["length"] as a property name that already exists on an empty array.
Object.getOwnPropertyNames([]); // -> ["length"]
Similarly, if you add your own properties, they will also show up when calling this method, along with your array elements:
let array = ['a','b','c'];
array['test'] = true;
Object.getOwnPropertyNames(array); // -> ["0", "1", "2", "length", "test"]
More practically, you may have a time when you want to add a special function to an array in your project but not necessarily want that function to spread across all other arrays. Rather than implementing this as a new prototype function, you can add this new function to a specific array by adding the function as the value of a property as you did in your example. Your properties can even interact with each other.
let array = ['a','b','c'];
array.doubleLength = function() { return this.length * 2 };
array.hasAtLeast = function(x) { return this.length >= x };
array.length; // -> 3
array.doubleLength(); // -> 6
array.hasAtLeast(1); // -> true
array.hasAtLeast(3); // -> true
array.hasAtLeast(4); // -> false
2. What is the data structure actually storing behind the scene: as an array or something like object, hashtable, LinkedList?
I discussed this in more detail above as well. Essentially, what is happening here is that the new properties are being stored as object properties, but not in the usual object { key: value } key-value pair sort of way. Arrays and objects are both actually different types of what we'll refer to here as "raw objects". Everything in JavaScript is some instance of a raw object in one way or another. Arrays are a type of "raw" object. Key-value pair objects are a type of object and are also not these "raw" objects we are talking about, but another manifestation of them.
All objects shared a few key attributes. One of those attributes is that they all share the same ability to store properties, which we normally recognize as the keys in the objects we work with on a daily basis. All objects allow the addition of custom properties.
Some types of objects like strings require you to traverse to their prototypes in order to add properties. Because of this, this won't work:
let string = "Hello World";
string.addExclamation = function() { return this + "!" };
string.addExclamation() // -> THROWS ERROR!!!
…but this WILL work:
let string = "Hello World";
string.__proto__.addExclamation = function() { return this + "!" };
string.addExclamation(); // -> "Hello World!"
Other types of objects including both key-value objects and arrays, allow you to add custom properties directly to them without traversing to their prototypes, as I mentioned in my answer to your first question above.
This distinction between which types of objects allow the direct adding of properties and which don't, and which we'd consider "raw" objects and which we wouldn't boils down to a JavaScript ideology known as "primitive types" and "reference types". I highly suggest reading up on that "primitive vs. reference" distinction more.
It's also useful to note how to set up these prototype properties and the difference between prototype and __proto__. In many ways, prototype and __proto__ work the same, the key difference being that you can call the __proto__ property on any variable/object to get the prototype for its object type. On the other hand, prototype can be called only on the actual constructor for a variable/object. The below two prototype and __proto__ lines actually call the same object.
const string = "";
string.__proto__; // -> String { … }
String.prototype; // -> String { … }
string.__proto__ === String.prototype; // -> true
3. Whether this behavior depends on a specific Javascript Engine (V8, SpiderMonkey, etc..) or not?
Nope! This is about as raw as it comes when working with JavaScript. Just the beauty of object-oriented programming. I explain this in a lot more depth in the above two answers to your questions, as well as the content I added before my answers.
4. Should I use an array like this (keys are both numeric index and string) over a normal object?
Contrary to what a lot of answers are saying, yes 👏🏼 do use arrays like this IF your situation calls for it. I don't mean to contradict myself here. Earlier, I did say you may want to avoid this, and that's true, so allow me to elaborate.
Should you add elements to arrays like this, where it adds them as properties and not as array elements? No. Adding to arrays like this is actually adding JS properties to them, not array elements.
Is there ever a case where I SHOULD add properties to arrays like this? Yes! It may not be often, and I explain this in more detail in my response to your first question, but if you are in a situation where you want to add custom properties, even functional properties to one specific array and not the Array.prototype which would affect all arrays, this is a perfectly fine and safe way to do so. I'll add my same example from my answer to question #1 below for reference:
let array = ['a','b','c'];
array.doubleLength = function() { return this.length * 2 };
array.hasAtLeast = function(x) { return this.length >= x };
array.length; // -> 3
array.doubleLength(); // -> 6
array.hasAtLeast(1); // -> true
array.hasAtLeast(3); // -> true
array.hasAtLeast(4); // -> false
For further reading, I would highly encourage reading my post in its entirety and chewing on it, and then checking out the MDN docs on the prototype chain. For even further study, I highly suggest signing up for Just JavaScript, a completely free 10-part email digest series and takes you on a deep dive into JavaScript Mental Models, which focuses largely on this prototype chain and other fascinating parts of what makes JavaScript so robust. It's written by Dan Abramov, one of the co-creators of Redux, and beautifully illustrated by Maggie Appleton. Definitely worth a peek!
Other answers look good.
In JavaScript, an array is an object.
For example, you can destructure an array as an object due to each item in an array is an object with key-value pairs.
const array = ["Hello", "World"];
const {0: first, 1 :second} = array;
console.log({first, second});
And in case that the keys of each item in an array including integer, string, etc. You can object destructure by a specific key.
var array = ["hello"];
array["hi"] = "weird";
const {
0: first, // integer --> index number
hi: second // string --> string key
} = array;
console.log({first, second});
Besides, you can only access an item by index when key is an integer.
var array = ["hello"];
array["hi"] = "weird";
console.log(array[0]); // hello
console.log(array[1]); // undefined
console.log(array["hi"]); // weird
Why does array allow string as an index in JavaScript
To add custom behaviour to an object
Question 1.1
Why have this behavior?
This is because array is itself an object with specific behaviour.
Array is a data structure which defines the behaviour of the object. So when we declare array we tell the compiler that this object must be treated as an array so the compiler only considers numeric indexes in an array.
For an array:
let array = []
If you write like this:
array["hi"] = "weird";
The compiler treats it as a property of array and in array, all properties are ignored by default
length is one of the properties of an array which returns it's length.
Since we know that length is a property of array. Try running the below program you'll get the idea.
let array = [];
array[0] = "first";
array[1] = "second";
array[2] = "third";
array[3] = "fourth";
array["hi"] = "weird";
// we overrided a predefined property of an array. You can try changing it's length and see what happens
array["length"] = 3;
console.log(array, '\n Length of array: ', array.length);
Question 1.2
This seems inconsistent, right?
No, what if we want to add custom behaviour to the array. However, it can be done usnig 'prototype` but it applies for all the arrays but for specific array it might be needed. However, it is never needed.
Question 2
What is the data structure actually storing behind the scene: as an array or something like object, hashtable, linkedlist?
It is stored as an object since it is a data structure
Question 3
Whether this behavior depends on a specific Javascript Engine (V8, SpiderMonkey, etc..) or not?
Behaviour of this won't change for javascript operations but handling of operations may differ.
If you run the above snippet in Console of Dev Tools in Chrome, the hi index is printed whereas it doesn't in the case of the Firefox and stackoverflow because they use different engines
You can read more about it here
Question 4
Should I use array like this(keys are both numeric index and string) over normal object?
No, it doesn't make sense to use array to store values in a (string)key when you cannot use the string keys in methods like forEach, map and array related methods. It'll make things complicated but still if you want to do it then use an object instead.
You can read more about it here
Answer to question 1 and 2
Arrays are so-called "Integer Indexed Exotic Objects" in ECMAScript which are based on which in return belong to the object data type. Exotic objects are objects with some special behavior such as integer indices in our case. As far as I can tell, since we set a string index, our array is no longer an integer indexed exotic object.
Answer to question 3
Since this is ECMAScript, my understanding is, that all JavaScript engines have to implement it this way to stay compatible with the specification.
Answer to question 4
You should definitely not. Arrays should only have integer indices as per spec ("Integer Indexed Exotic Objects"). If you want to use string or mix both, use an object. When using an object, integer indices are coerced to string indices.
Note that this will only work in Chrome or in any other V8 engine browser. I tested your code in Safari and it didn't store the "hi" key-value pair at all. But in Safari it is rather an exception than the rule since you don't get an error either.
The reason why it works is that it is still an object. The functionalities of arrays are stacked on top of what objects in general have.
typeof array // "object"
Edit
By the advice of #Kevin B, I realized that Safari indeed doesn't handle it differently than Chrome. The console.log implementation must be different in both browsers in this regard. I was still able to access the key value pair even if it wasn't shown when printing the array in the console.
Also I noticed that the OP is looking for an answer from a reputable source. The only reputable source that I came across which exactly reflects what I wrote above is from w3schools.com
Arrays are Objects
Arrays are a special type of objects. The typeof operator in
JavaScript returns "object" for arrays.
But, JavaScript arrays are best described as arrays.
Arrays use numbers to access its "elements". In this example,
person[0] returns John:
[...]
In JavaScript, there are two categories of data types: primitive types (number, string, boolean, bigInt, symbol, undefined, null) and objects (also known as Reference types).
An array is a special object that uses integers as its keys. JavaScript still treats it as an object. That means you can add/remove properties (That array will be called associative array or dictionary, like your example). If you want to truly treat it as a standard array, you should never use strings as keys.
Furthermore, you should use arrays as standard arrays because in JavaScript arrays have behavior and optimizations specific to their intended use. Also, when you add a new property with a string key to your array, the value of length will not change.
var array = ["hello"]; // Another way to declare a array is array = new Array("Hello"). This version clearly shows array is just a object.
array["hi"] = "weird";
console.log(array.length) // 1 not 2
array[1] = "A.Phong"
console.log(array.length) // 2
Are arrays merely objects in disguise? Why/why not? In what way(s) are they (such/not)?
I have always thought of arrays and objects in JS as essentially the same, primarily because accessing them is identical.
var obj = {'I': 'me'};
var arr = new Array();
arr['you'] = 'them';
console.log(obj.I);
console.log(arr.you);
console.log(obj['I']);
console.log(arr['you']);
Am I mislead/mistaken/wrong? What do I need to know about JS literals, primitives, and strings/objects/arrays/etc...?
Are arrays/objects merely strings in disguise? Why/why not? In what way(s) are they (such/not)?
Arrays are objects.
However, unlike regular objects, arrays have certain special features.
Arrays have an additional object in their prototype chain - namely Array.prototype. This object contains so-called Array methods which can be called on array instances. (List of methods is here: http://es5.github.com/#x15.4.4)
Arrays have a length property (which is live, ergo, it auto-updates) (Read here: http://es5.github.com/#x15.4.5.2)
Arrays have a special algorithm regarding defining new properties (Read here: http://es5.github.com/#x15.4.5.1). If you set a new property to an array and that property's name is a sting which can be coerced to an integer number (like '1', '2', '3', etc.) then the special algorithm applies (it is defined on p. 123 in the spec)
Other than these 3 things, arrays are just like regular objects.
Read about arrays in the spec: http://es5.github.com/#x15.4
Objects are an unordered map from string keys to values, arrays are an ordered list of values (with integer keys). That's the main difference. They're both non-primitive, as they're composed of multiple values, which also implies pass-by-reference in JavaScript.
Arrays are also a kind of object, though, so you can attach extra properties to them, access their prototype and so on.
In your revised example, you're only taking advantage of the fact that an array is actually an object, i.e. you can set any property on them. You shouldn't do that. If you don't need an ordered list of values, use a plain object.
Strings can be either primitive or objects, depending on how they were declared.
var str = 'yes';
Gives you a primitive, while,
var str = new String('yes');
will give you a String object.
All arrays are the same (Whether or not they were defined with [] or new Array()), are of the type object and inherit from the "Array" object's prototype. There aren't real classes in Javascript, everything is an object, and there's a system defined object called Array. It has a property called 'prototype' (of type object), and when you use the new keyword on an object with a prototype property, it creates an instance with a reference to the contents of the prototype and stores it in your variable. So all arrays you've ever used in Javascript are objects and instances of Array's prototype property.
In any case, although arrays really are objects, they behave like arrays because of their useful properties and functions (Such as length, slice, push etc).
Another note, although I said there are no classes, when you do this:
console.log(Object.prototype.toString.call(your_object));
it will give you a string in the form [object Object]. But what's useful is that when you call it with an array, you get [object Array] same with functions which give [object Function] and a number of other system defined types, which assists in differentiating between normal objects and arrays (Since the typeof operator will always just return the string 'object').
Try this
var a = Array;
and go into firebug and examine the contents of a, especially it's 'prototype' property.
Edit: Changed the wording a bit, to be more correct. In fact when you use the new keyword, it creates an instance which references the prototype object. So any changes made to the prototype after the instance's declaration, will still affect the instance.
Edit: In answer to your latest revised question (are arrays/objects actually strings in disguise): No. They are objects, as I've explained. Strings are either a primitive type, or an object type (An instance of the String object) which contains the primitive equivalent as one of it's properties.
Arrays are not primitives in Javascript, they are objects. The key difference is that as a result, when you pass an array to a function it is passed by reference, not by value.
So yes! Arrays are objects in javascript, with a full blown Array.prototype and everything (don't touch that though...)
The confusion comes from the fact that javascripts lets you access object attributes in two ways:
myObj.attribute
or
myObj["attribute"]
Really what makes an array an array has nothing to do with the way you store data -- any object can store values using the syntax you use to store the array -- what makes an array an array is the fact that array methods (e.g. shift() and sort()) are defined for Array.prototype.
Trying to be brief with what I believe to be of the most significance: arrays have a number of methods that objects do not. Including:
length
push
pop
An object declared as var x = {foo:bar} has no access to a .length() method. They are both objects but with the array as a sort of superset with methods mentioned as above.
I don't feel I this is even close to being of Crockford standard in terms of explanation but I'm trying to be succinct.
If you want to get some quick results, open up Firebug or your javascript Console and try Array.prototype and Object.prototype to see some details
Update: In your example you declare an array and then do:
foo['bar'] = 'unexpectedbehaviour';
will produce unexpected results and won't be available in simple loops such as:
var foo=[0,1];
foo['bar'] = 2;
for(var i=0;i<foo.length;i++){
console.log(foo[i]);
}
//outputs:
//0
//1
An array can accept foo['bar']=x or foo.bar=y like an object but won't necessarily be available to be looped through as highlighted above.
Not that I'm saying that you can't iterate through the properties of an object, just that when working with an Array, you're utilising that unique functionality and should remember not to get confused.
In JavaScript you have a few types, everything else is an object. The types in JavaScript are: boolean, number, and string. There are also two special values, "null" and "undefined".
So the quest "is a JavaScript array an object?" is slightly ambiguous. Yes, a JavaScript array is an "object" but it is not an instance of "Object". A JavaScript array is an instance of "Array". Although, all objects inherit from Object; you can view the inheritance chain on the MDC. Additionally, arrays have slightly different properties than an object. Arrays have the .length property. They also have the .slice(), .join(), etc methods.
Douglas Crockford provides a nice survey of the language's features. His survey discusses the differences you are asking about. Additionally, you can read more about the difference between literals and constructors in question #4559207.
Arrays are Objects, but of a specialized nature. Objects are collections of values indexed by keys (in Javascript notation, {'key': 'value'}), whereas Arrays are Objects whose keys are numeric (with a few functions and properties). The key difference between them is obvious when you use a for each loop--an Object will iterate over all the values in its properties, whereas an Array will return the keys instead. Here's a link to a JSFiddle demonstrating the difference--notice that the first for each, which uses an array, returns the indexes, not the values; in contrast, the second for each returns the actual values at those keys.
I am a novice in Basic JavaScript Concepts so want to understand how is this possible.
I have an object x
var x={}
and it has a propery y whose value is an array
x.y=["a","b","c"]`
so its like a map where y is the key and array["a","b","c"] is the value.then how can y hold another property called z which has some other value say "hi"
x.y.z= "hi"
y is already ["a","b","c"]-------------------------> x.y= ["a","b","c"]
how can it be {"z":"hi"} then------------------------>x.y={"z":"hi"}
and if you expand x this is how it is shown
To have a clear picture on this ,which basic concepts i should be familiar with?
Because arrays are object withe some special methods.
Arrays are list-like objects whose prototype has methods to perform traversal and mutation operations. Neither the length of a JavaScript array nor the types of its elements are fixed. Since an array's size length grow or shrink at any time, JavaScript arrays are not guaranteed to be dense. In general, these are convenient characteristics; but if these features are not desirable for your particular use, you might consider using typed arrays.
Some people think that you shouldn't use an array as an associative array. In any case, you can use plain objects instead, although doing so comes with its own caveats. See the post Lightweight JavaScript dictionaries with arbitrary keys as an example.
In javascript, arrays are objects. For example, if your check the "type" for each:
var myArray = [];
var myObject = {};
console.log(typeof(myArray)); // yields 'object'
console.log(typeof(myObject)); // yields 'object'
The idea is that an array is built upon the lower-level "object" (Arrays extend Object) by adding additional functionality, such as the "length" property, join, sort, etc.
So when you manually put a property "into" an array it will honor your request because Array is an extension of Object, so and Array can do everything that an object can do.... and more!
So for this example:
// Our traditional array
var myArray = ["aaa", "bbb", "ccc"];
We'd expect the normal indicing, where:
myArray[0] -> aaa
myArray[1] -> bbb
myArray[2] -> ccc
But when we manually put a property into the array:
myArray.xyz = "interesting";
Well then, it can and will get stored in the array.
If you think about an array for a second, you can access it's "length" property, right?
var len = myArray.length;
So there are a bunch of properties already within each array, so when you add your own property, that's ok (although not recommended), because javascript is quite flexible.
That proto thing you see is showing how "things" in javascript can "extend". Again, Array extends Object. In javascript Prototype is kinda like the "parent" class that other classes can build upon -- or extend -- and incorporate more functionality.
So you'll see that there is an "Object" proto in there, which means that "Array" is leveraging the "Object's" Prototype (so it can do everything that an object can do), then it adds a bunch of stuff to the prototype and the result is the Array Prototype, which is now it's own entity, complete with different functionality beyond that which the Object had.
You'll hear from time to time folks say that Javascript is a "prototype language". And your browser shows you how the prototyping is structured if you dig down into the rabbit hole.
The difference between a JavaScript Array, and Object is not very big. In fact it seems Array mainly adds the length field, so you can use both Arrays and Objects as numeric arrays:
var ar = new Array();
ar[0] = "foo";
ar["bar"] = "foo";
var ob = new Object();
ob[0] = "foo";
ob["bar"] = "foo";
assert(ar[0] == ob[0] == ar["0"] == ob["0"] == ar.bar == ob.bar); // Should be true.
So my questions is, in popular JavaScript engines (V8, JavaScriptCore, SpiderMonkey, etc.), how is this handled? Obviously we do not want our arrays to be actually stored as hash maps with key values! How can we be reasonably sure our data is stored as an actual array?
As far as I can see there are a few approaches engines could take:
Array is implemented exactly the same way as Object - as an associative array with string keys.
Array is a special case, with a std::vector-like array backing the numeric keys, and some density heuristic to prevent insane memory use if you do ar[100000000] = 0;
Array is the same as Object, and all objects get a heuristic to see if using an array would make more sense.
Something insanely complicated that I haven't thought of.
Really this would be simpler if there were a proper array type (cough WebGL typed arrays cough).
In SpiderMonkey, arrays are implemented basically as C arrays of jsvals. These are referred to as "dense arrays". However, if you start doing un-array-like things to them -- like treating them like objects -- their implementation is changed to something which very much resembles objects.
Moral of the story: when you want an array, use an array. When you want an object, use an object.
Oh, a jsval is a sort of variadic type which can represent any possible JavaScript value in a 64 bit C type.
In V8 and Carakan (and presumably Chakra), all (non-host) objects (both those that are arrays and those that aren't) with properties whose names are array indexes (as defined in ES5) are stored as either a dense array (a C array containing some value wrapper) or a sparse array (which is implemented as a binary search tree).
The unified object representation shows through in that it affects enumeration order: with an object, SpiderMonkey and SquirrelFish both give all properties in insertion order; and with an array, they in general (there are special cases in SM at least!) array indexes first then all other properties in insertion order. V8, Carakan, and Chakra always give array indexes first then all other properties in insertion order, regardless of object type.