Forcing string representation of an array key - javascript

I am trying to maintain the order of an array with mixed key types. The array contains mostly keys represented by string values -- but if you enter a numbered key it goes to the front. How can I force a key which is a number to be a string type?
E.g.
array = [];
array["one"] = "some data";
array["two"] = "some more data";
array["3"] = "this should not be the first element";
How can I make "3" a string type to prevent it from moving to the top of the index?

Oh wow did you ever open multiple cans of worms.
Javascript arrays are a special type of Javascript objects, and like all Javascript objects they can have arbitrary string properties:
const foo = [];
foo["bar"] = "hi";
However that string is a property of the array object, not an item in the array:
foo.forEach(console.log); // logs nothing
You can still access it like any other object property:
console.log(foo["bar"]); // "hi"
But it won't show up in the usual iterative constructs like c-style for loops or the map/forEach array methods.
The line in your example
array["3"] = "this should not be the first element";
is very different however, because of Javascript's playing fast and loose with type conversions this actually sets the string to the 4th slot in the array:
const bar = [];
bar["3"] = "oops!"; // equivalent to bar[3] = "oops!"
console.log(bar); // [empty x 3, "oops!"]
This piece of it is actually a good thing (other than the implicit conversion part) rather than a problem: sometimes you need a sparse array and JS supports those. Iterating it will only produce the one element:
bar.forEach((item, index) => console.log(item, index)); // ["oops", 3]
Note though that the string has the correct index of 3, and can be accessed that way even though there's nothing "in front" of it:
bar[3]; // "oops"
So the first two assignments in your example create properties on the array object, and the third assignment is the only one that actually adds an item to the array, at the 4th index (there's nothing at the first 3).
What you seem to want as Reese Casey suggests, is a plain object:
const foo = {}; // curly
foo["some string"] = "whatever";
However now the properties are basically unordered. If you want them to be in a guaranteed specific order you do want an array, but all your indicies will need to be integers, and should be sequential. You can achieve this easily by using the .push method:
foo = [];
foo.push("something");
foo.push("something else");
Now foo will have two elements, in the correct order, and index 0 and 1 respectively.
Update based on comment on the other answer:
I want some of the data to be ordered, and the rest of the data to follow
This can be accomplished through object destructuring:
const responseFromDB = {
oneKeyICareAbout: 3,
anotherKeyICareAbout: 2,
foo: 6,
bar: 7,
};
const {
oneKeyICareAbout,
anotherKeyICareAbout,
*rest,
} = responseFromDB;
const stuffToDisplay = [
oneKeyICareAbout,
anotherKeyICareAbout,
...Object.values(rest),
]; // [3, 2, 6, 7]
And at least the destructured stuff you put in the array will be ordered because by doing so you've ordered it.

Javascript arrays cannot have string indexes. This is actually working incorrectly as the index is adding a property to the array object.
Changing to an object makes more sense for this.
EDIT: Whilst below its mentioned you can have string indexes you are not actually using the array by doing so. The answer by Jared Smith goes into much more detail as to why.

The other answers explain what is happening with your array-object mixture. For having an indexable thing which can reproduce the original order, you can use a Map:
The Map object holds key-value pairs and remembers the original insertion order of the keys.
array = new Map();
array.set("one","some data");
array.set("two","some more data");
array.set("3","this should not be the first element");
console.log("Test of get:",array.get("two"));
console.log("Test of order:");
for(let entry of array)
console.log(entry);

Related

Why I'm creating an empty object at the end of my array? [duplicate]

Ever since its introduction in ECMA-262, 3rd Edition, the Array.prototype.push method's return value is a Number:
15.4.4.7 Array.prototype.push ( [ item1 [ , item2 [ , … ] ] ] )
The arguments are appended to the end of the array, in the order in which they appear. The new length of the array is returned as the result of the call.
What were the design decisions behind returning the array's new length, as opposed to returning something potentially more useful, like:
A reference to the newly appended item/s
The mutated array itself
Why was it done like this, and is there a historical record of how these decisions came to be made?
I understand the expectation for array.push() to return the mutated array instead of its new length. And the desire to use this syntax for chaining reasons.
However, there is a built in way to do this: array.concat().
Note that concat expects to be given an array, not an item. So, remember to wrap the item(s) you want to add in [], if they are not already in an array.
newArray = oldArray.concat([newItem]);
Array chaining can be accomplished by using .concat(), as it returns an array,
but not by .push(), as it returns an integer (the new length of the array).
Here is a common pattern used in React for changing the state variable, based on its prior value:
// the property value we are changing
selectedBook.shelf = newShelf;
this.setState((prevState) => (
{books: prevState.books
.filter((book) => (book.id !== selectedBook.id))
.concat(selectedBook)
}
));
state object has a books property, that holds an array of book.
book is an object with id, and shelf properties (among others).
setState() takes in an object that holds the new value to be assigned to state
selectedBook is already in the books array, but its property shelf needs to be changed.
We can only give setState a top level object, however.
We cannot tell it to go find the book, and look for a property on that book, and give it this new value.
So we take the books array as it were.
filter to remove the old copy of selectedBook.
Then concat to add selectedBook back in, after updating its shelf property.
Great use case for wanting to chain push.
However, the correct way to do this is actually with concat.
Summary:
array.push() returns a number (mutated array's new length).
array.concat([]) returns a new array.
Technically, it returns a new array with the modified element added to the end, and leaves the initial arrays unchanged.
Returning a new array instance, as opposed to recycling the existing array instance is an important distinction, that makes it very useful for state objects in React applications, to get changed data to re-render.
I posted this in TC39's communication hub, and was able to learn a bit more about the history behind this:
push, pop, shift, unshift were originally added to JS1.2 (Netscape 4) in 1997.
There were modeled after the similarly named functions in Perl.
JS1.2 push followed the Perl 4 convention of returning the last item pushed.
In JS1.3 (Netscape 4.06 summer 1998) changed push to follow the Perl 5 conventions of returning the new length of the array.
see original jsarray.c source
/*
* If JS1.2, follow Perl4 by returning the last thing pushed. Otherwise,
* return the new array length.
*/
I cannot explain why they chose to return the new length, but in response to your suggestions:
Returning the newly appended item:
Given that JavaScript uses C-style assignment which emits the assigned value (as opposed to Basic-style assignment which does not) you can still have that behavior:
var addedItem;
myArray.push( addedItem = someExpression() );
(though I recognise this does mean you can't have it as part of an r-value in a declaration+assignment combination)
Returning the mutated array itself:
That would be in the style of "fluent" APIs which gained popularity significantly after ECMAScript 3 was completed and it would not be keeping in the style of other library features in ECMAScript, and again, it isn't that much extra legwork to enable the scenarios you're after by creating your own push method:
Array.prototype.push2 = function(x) {
this.push(x);
return this;
};
myArray.push2( foo ).push2( bar ).push2( baz );
or:
Array.prototype.push3 = function(x) {
this.push(x);
return x;
};
var foo = myArray.push3( computeFoo() );
I was curious since you asked. I made a sample array and inspected it in Chrome.
var arr = [];
arr.push(1);
arr.push(2);
arr.push(3);
console.log(arr);
Since I already have reference to the array as well as every object I push into it, there's only one other property that could be useful... length. By returning this one additional value of the Array data structure, I now have access to all the relevant information. It seems like the best design choice. That, or return nothing at all if you want to argue for the sake of saving 1 single machine instruction.
Why was it done like this, and is there a historical record of how these decisions came to be made?
No clue - I'm not certain a record of rationale along these lines exists. It would be up to the implementer and is likely commented in any given code base implementing the ECMA script standards.
I don't know "Why was it done like this, and is there a historical record of how these decisions came to be made?".
But I also think it's not clear and not intuitive that push() returns the length of array like below:
let arr = ["a", "b"];
let test = arr.push("c");
console.log(test); // 3
Then, if you want to use clear and intuitive method instead of push(), you can use concat() which returns the array with its values like below:
let arr = ["a", "b"];
let test = arr.concat("c");
console.log(test); // ["a", "b", "c"]
The question is partially answered in the document you mention (Ecma 262 3rd edition), there are methods that mutate the array and methods that don't. The methods that mutate the array will return the length of the mutated array. For adding elements that would be push, splice and unshift (Depending on the position you want the new element in).
If you want to get the new mutated array you can use concat. Concat will input any number of arrays you want added to the original array and add all the elements into a new array. i.e:
const array1 = ['a', 'b', 'c'];
const array2 = ['d', 'e', 'f'];
const array3=['g','h'];
const array4 = array1.concat(array2,array3);
The new array created will have all the elements and the other three won't be changed. There are other (Many) ways to add the elements to an array both mutative and not mutative. So there is your answer, it returns the length because it is changing it, it doesn't need to return the full array.

Problem with array assignment in javascript [duplicate]

Ever since its introduction in ECMA-262, 3rd Edition, the Array.prototype.push method's return value is a Number:
15.4.4.7 Array.prototype.push ( [ item1 [ , item2 [ , … ] ] ] )
The arguments are appended to the end of the array, in the order in which they appear. The new length of the array is returned as the result of the call.
What were the design decisions behind returning the array's new length, as opposed to returning something potentially more useful, like:
A reference to the newly appended item/s
The mutated array itself
Why was it done like this, and is there a historical record of how these decisions came to be made?
I understand the expectation for array.push() to return the mutated array instead of its new length. And the desire to use this syntax for chaining reasons.
However, there is a built in way to do this: array.concat().
Note that concat expects to be given an array, not an item. So, remember to wrap the item(s) you want to add in [], if they are not already in an array.
newArray = oldArray.concat([newItem]);
Array chaining can be accomplished by using .concat(), as it returns an array,
but not by .push(), as it returns an integer (the new length of the array).
Here is a common pattern used in React for changing the state variable, based on its prior value:
// the property value we are changing
selectedBook.shelf = newShelf;
this.setState((prevState) => (
{books: prevState.books
.filter((book) => (book.id !== selectedBook.id))
.concat(selectedBook)
}
));
state object has a books property, that holds an array of book.
book is an object with id, and shelf properties (among others).
setState() takes in an object that holds the new value to be assigned to state
selectedBook is already in the books array, but its property shelf needs to be changed.
We can only give setState a top level object, however.
We cannot tell it to go find the book, and look for a property on that book, and give it this new value.
So we take the books array as it were.
filter to remove the old copy of selectedBook.
Then concat to add selectedBook back in, after updating its shelf property.
Great use case for wanting to chain push.
However, the correct way to do this is actually with concat.
Summary:
array.push() returns a number (mutated array's new length).
array.concat([]) returns a new array.
Technically, it returns a new array with the modified element added to the end, and leaves the initial arrays unchanged.
Returning a new array instance, as opposed to recycling the existing array instance is an important distinction, that makes it very useful for state objects in React applications, to get changed data to re-render.
I posted this in TC39's communication hub, and was able to learn a bit more about the history behind this:
push, pop, shift, unshift were originally added to JS1.2 (Netscape 4) in 1997.
There were modeled after the similarly named functions in Perl.
JS1.2 push followed the Perl 4 convention of returning the last item pushed.
In JS1.3 (Netscape 4.06 summer 1998) changed push to follow the Perl 5 conventions of returning the new length of the array.
see original jsarray.c source
/*
* If JS1.2, follow Perl4 by returning the last thing pushed. Otherwise,
* return the new array length.
*/
I cannot explain why they chose to return the new length, but in response to your suggestions:
Returning the newly appended item:
Given that JavaScript uses C-style assignment which emits the assigned value (as opposed to Basic-style assignment which does not) you can still have that behavior:
var addedItem;
myArray.push( addedItem = someExpression() );
(though I recognise this does mean you can't have it as part of an r-value in a declaration+assignment combination)
Returning the mutated array itself:
That would be in the style of "fluent" APIs which gained popularity significantly after ECMAScript 3 was completed and it would not be keeping in the style of other library features in ECMAScript, and again, it isn't that much extra legwork to enable the scenarios you're after by creating your own push method:
Array.prototype.push2 = function(x) {
this.push(x);
return this;
};
myArray.push2( foo ).push2( bar ).push2( baz );
or:
Array.prototype.push3 = function(x) {
this.push(x);
return x;
};
var foo = myArray.push3( computeFoo() );
I was curious since you asked. I made a sample array and inspected it in Chrome.
var arr = [];
arr.push(1);
arr.push(2);
arr.push(3);
console.log(arr);
Since I already have reference to the array as well as every object I push into it, there's only one other property that could be useful... length. By returning this one additional value of the Array data structure, I now have access to all the relevant information. It seems like the best design choice. That, or return nothing at all if you want to argue for the sake of saving 1 single machine instruction.
Why was it done like this, and is there a historical record of how these decisions came to be made?
No clue - I'm not certain a record of rationale along these lines exists. It would be up to the implementer and is likely commented in any given code base implementing the ECMA script standards.
I don't know "Why was it done like this, and is there a historical record of how these decisions came to be made?".
But I also think it's not clear and not intuitive that push() returns the length of array like below:
let arr = ["a", "b"];
let test = arr.push("c");
console.log(test); // 3
Then, if you want to use clear and intuitive method instead of push(), you can use concat() which returns the array with its values like below:
let arr = ["a", "b"];
let test = arr.concat("c");
console.log(test); // ["a", "b", "c"]
The question is partially answered in the document you mention (Ecma 262 3rd edition), there are methods that mutate the array and methods that don't. The methods that mutate the array will return the length of the mutated array. For adding elements that would be push, splice and unshift (Depending on the position you want the new element in).
If you want to get the new mutated array you can use concat. Concat will input any number of arrays you want added to the original array and add all the elements into a new array. i.e:
const array1 = ['a', 'b', 'c'];
const array2 = ['d', 'e', 'f'];
const array3=['g','h'];
const array4 = array1.concat(array2,array3);
The new array created will have all the elements and the other three won't be changed. There are other (Many) ways to add the elements to an array both mutative and not mutative. So there is your answer, it returns the length because it is changing it, it doesn't need to return the full array.

What's an Associative Array?

I'm trying to understand what an associative array really is and what steps are needed to acquire one. I have seen many explanations that are totally different.
I have tried testing it out on my own but can't seem to really get it in the end.
var array = ["one", "two", "three"];
var test = array["one"];
console.log(test);
I expected for it to target the index in which the string "one" is in, but an error occurs.
You are likely looking for a JavaScript Object, what is basically the same as an associative array, dictionary, or map in other languages: It maps strings to values. Unlike Arrays, which use square brackets [] for declaration, Objects use curly braces {} (please note that there are some exceptions).
Try to think of an Object as an associative array:
const arr = {one: 1, two: 2, three: 3};
console.log(arr['one']);
console.log(arr.one);
It is worth noting that Array's in JavaScript are technically objects.
The JavaScript Array object is a global object that is used in the construction of arrays; which are high-level, list-like objects.
The main difference between Array's and Object's is that Arrays are numerically indexed.
const arr = ['fooValue', 'barValue'];
const obj = {foo: 'fooValue', bar: 'barValue'};
console.log('arr: ', arr[0], arr[1]);
console.log('obj: ', obj.foo, obj.bar);
It is worth noting, that unlike primitive types in JavaScript, Object's (and Array's, which are also Object's) are passed by reference, so extra care is needed when attempting to copy the object.
function test(obj) {
obj['oops'] = 'this will modify the object';
}
const obj = {one: 1, two: 2, three: 3};
test(obj);
console.log(obj); // Object was updated
To avoid accidentally mutating your object, you will have to create a new instance of the object before performing operations on it. There are multiple ways to accomplish this:
Destructuring/spreading you object let obj2 = {...obj};
Using Object.assign()
I'm trying to understand what an associative array really is...
JavaScript doesn't have associative arrays in the sense that, for instance, PHP does. JavaScript has:
Arrays, which are (effectively) numerically indexed (see my blog post for why I said "effectively")
Objects, which are collections of properties that have names, which are either strings or Symbols (and which have other features, like inheritance)
Maps, which are collections of key/value pairs where the keys can be any type (not just strings or Symbols)
Arrays
To find the index of an entry in an array, typically you use indexOf (for an === match) or findIndex if you want to provide a predicate function.
var array = ["one", "two", "three"];
console.log(array.indexOf("one")); // 0
Objects
If you wanted, you could create an object that mapped strings to numbers:
var obj = {"one": 1, "two": 2, "forty-two": 42};
console.log(obj["forty-two"]); // 42
Maps
Similarly, a Map could do that:
var map = new Map([
["one", 1],
["two", 2],
["forty-two", 42]
]);
console.log(map.get("forty-two")); // 42
Associative arrays are used to associate something throughout an array.
You can use this with the query string for example:
In order to attain the information from a forum submitted, you need to put the user data into an associative array.
You would start by getting the query string as follows:
var queryString = window.location.search;
queryString = queryString.substring(1);
The reason why I did substring(1) is so we could remove the '?' at the beginning.
Once you have the query string of the website, you'd need a loop to separate the values of data received:
while (queryString.indexOf("+") != -1)
queryString = queryString("+", " ");
This will replace all the '+' signs in the string to spaces, making you get the values without the '+' signs. You'll have "Name=John" for example.
Now we need to split the '&'s from the string.
We also need to make an array ready for the data from the user.
var array = queryString.split("&");
var userData = [];
Afterwards, make a for loop in order to target however amount of data submitted and to attain it individually while storing it into the array:
for (let x = 0; x < array.length; x++)
{
var equalSign = array[x].search("=");
var theKeyValue = array[x].substring(0, equal);
var userDataValue = array[x];
userDataValue = decodeURIComponent(userDataValue); //Puts symbols back
userData[theKeyValue] = userDataValue;
}
This is just an example to follow up with the usage of associative arrays, hopefully this helps. :)
See Wikipedia.
It is a data structure when you can look up a value by a key. This is typically implemented in JS using a Map or an Object.
const data = new Map([
['foo', 'one'],
['bar', 'two']
]);
console.log( data.get("bar") );
I expected for it to target the index in which the string "one" is in, but an error occurs.
You are attempting to look up the index of a property in an array by its value.
That has nothing to do with associative arrays and is achieved with the indexOf method.
var array = ["one", "two", "three"];
var test = array.indexOf("one");
console.log(test);
An associative array, is essentially a hashmap, or an array that associates relationships.
For example if I was to build an associative array for fruits let's say to prices it would look like.
const arr = {'apple': 1, 'orange': 2, 'pear': 3};
console.log(Object.keys(arr));
console.log(Object.values(arr));
Unlike other languages, array in Javascript are not limited by having only numeric indices. They can act as hashes as well (i.e. having a string as a key). An associative array is one where you set the key to be a non-numeric value.
By default, and in the example you provided, ascending numeric values are assigned to each member of the array. I.e.
var array = ["one", "two", "three"];
is equivalent to
var array = [];
array[0] = 'one';
array[1] = 'two';
array[2] = 'three';
An associative array would be one where instead of numeric values you assign a different value:
var array = [];
array['one'] = 'one';
array['two'] = 'two';
However this brings a few caveats in itself and it considered bad practice and the arrays become harder to manage. In cases like there it would be better to use either an object or a Map.
An associative array is a data structure, a data collection, which has the scope of associate a list of key to respective values (key: value).
You can read in Wikipedia here, that are example of associative array for example: Map, Dictionary, etc.
Sample of associative array are also PHP indexed array, e.g.:
$cars[0] = "Volvo";
$cars[1] = "BMW";
$cars[2] = "Toyota";
That's not an associative array, that's just a regular array, filled with text.
An associative array example (you can also use object syntax like Miroslav's answer):
var stuff = [];
stuff['one'] = "hello 1";
stuff['two'] = "hello 2";

Reversing an array which is a value in object in Javascript

I am trying to reverse an array which is an element in an object.
colorKey = {
"2m":["#ffffff","#000000"]
}
colorKey["2mi"] = colorKey["2m"];
Array.reverse(colorKey["2mi"])
This is not working and returning colorKey["2mi"] the same as colorKey["2m"]. When I run the same command in developer console in browser, it reverses successfully. Where is the problem?
This is no static method off Array called reverse. reverse is an instance method (Array.prototype.reverse) off the Array object, so the instance of the Array must be the caller.
This solves your problem:
colorKey = {
"2m":["#ffffff","#000000"]
}
colorKey["2mi"] = colorKey["2m"];
colorKey["2mi"].reverse();
Output:
["#000000", "#ffffff"]
Calling reverse() for an array mutates it (reverse is in place - a new array is not created). What you want, apparently, is to have a reversed copy of the array. Basically, create a new array with the same values and then reverse it.
var a = [1, 2], b;
b = a.slice(0).reverse();
Slice creates a new array with the same elements (but remember that it is not cloning the elements).
#Rajat Aggarwal
What you are asking for, is to clone your previous array in reverse order.
The only trivial part of it would be reversing it. Because there is no way of cloning Objects and Arrays, nor a general method that you could write down as a function to be using it universally.
This specific array from the sample you provided can be cloned easily because it is flat and it only contains primitives. But the solution to it, will be exactly as specific as the sample array provided.
A specific solution to this task would be to use a plain coma-separated string of successive values and convert that to specific arrays of their corresponding primitive values.:
var colors = "#ffffff,#000000";
var colorKey = {
"2m":colors.split(","),
"2mi":colors.split(",").reverse()
}
which will yield you a:
>> colorKey
{
2m : #ffffff,#000000,
2mi : #000000,#ffffff
}

Why does Array.prototype.push return the new length instead of something more useful?

Ever since its introduction in ECMA-262, 3rd Edition, the Array.prototype.push method's return value is a Number:
15.4.4.7 Array.prototype.push ( [ item1 [ , item2 [ , … ] ] ] )
The arguments are appended to the end of the array, in the order in which they appear. The new length of the array is returned as the result of the call.
What were the design decisions behind returning the array's new length, as opposed to returning something potentially more useful, like:
A reference to the newly appended item/s
The mutated array itself
Why was it done like this, and is there a historical record of how these decisions came to be made?
I understand the expectation for array.push() to return the mutated array instead of its new length. And the desire to use this syntax for chaining reasons.
However, there is a built in way to do this: array.concat().
Note that concat expects to be given an array, not an item. So, remember to wrap the item(s) you want to add in [], if they are not already in an array.
newArray = oldArray.concat([newItem]);
Array chaining can be accomplished by using .concat(), as it returns an array,
but not by .push(), as it returns an integer (the new length of the array).
Here is a common pattern used in React for changing the state variable, based on its prior value:
// the property value we are changing
selectedBook.shelf = newShelf;
this.setState((prevState) => (
{books: prevState.books
.filter((book) => (book.id !== selectedBook.id))
.concat(selectedBook)
}
));
state object has a books property, that holds an array of book.
book is an object with id, and shelf properties (among others).
setState() takes in an object that holds the new value to be assigned to state
selectedBook is already in the books array, but its property shelf needs to be changed.
We can only give setState a top level object, however.
We cannot tell it to go find the book, and look for a property on that book, and give it this new value.
So we take the books array as it were.
filter to remove the old copy of selectedBook.
Then concat to add selectedBook back in, after updating its shelf property.
Great use case for wanting to chain push.
However, the correct way to do this is actually with concat.
Summary:
array.push() returns a number (mutated array's new length).
array.concat([]) returns a new array.
Technically, it returns a new array with the modified element added to the end, and leaves the initial arrays unchanged.
Returning a new array instance, as opposed to recycling the existing array instance is an important distinction, that makes it very useful for state objects in React applications, to get changed data to re-render.
I posted this in TC39's communication hub, and was able to learn a bit more about the history behind this:
push, pop, shift, unshift were originally added to JS1.2 (Netscape 4) in 1997.
There were modeled after the similarly named functions in Perl.
JS1.2 push followed the Perl 4 convention of returning the last item pushed.
In JS1.3 (Netscape 4.06 summer 1998) changed push to follow the Perl 5 conventions of returning the new length of the array.
see original jsarray.c source
/*
* If JS1.2, follow Perl4 by returning the last thing pushed. Otherwise,
* return the new array length.
*/
I cannot explain why they chose to return the new length, but in response to your suggestions:
Returning the newly appended item:
Given that JavaScript uses C-style assignment which emits the assigned value (as opposed to Basic-style assignment which does not) you can still have that behavior:
var addedItem;
myArray.push( addedItem = someExpression() );
(though I recognise this does mean you can't have it as part of an r-value in a declaration+assignment combination)
Returning the mutated array itself:
That would be in the style of "fluent" APIs which gained popularity significantly after ECMAScript 3 was completed and it would not be keeping in the style of other library features in ECMAScript, and again, it isn't that much extra legwork to enable the scenarios you're after by creating your own push method:
Array.prototype.push2 = function(x) {
this.push(x);
return this;
};
myArray.push2( foo ).push2( bar ).push2( baz );
or:
Array.prototype.push3 = function(x) {
this.push(x);
return x;
};
var foo = myArray.push3( computeFoo() );
I was curious since you asked. I made a sample array and inspected it in Chrome.
var arr = [];
arr.push(1);
arr.push(2);
arr.push(3);
console.log(arr);
Since I already have reference to the array as well as every object I push into it, there's only one other property that could be useful... length. By returning this one additional value of the Array data structure, I now have access to all the relevant information. It seems like the best design choice. That, or return nothing at all if you want to argue for the sake of saving 1 single machine instruction.
Why was it done like this, and is there a historical record of how these decisions came to be made?
No clue - I'm not certain a record of rationale along these lines exists. It would be up to the implementer and is likely commented in any given code base implementing the ECMA script standards.
I don't know "Why was it done like this, and is there a historical record of how these decisions came to be made?".
But I also think it's not clear and not intuitive that push() returns the length of array like below:
let arr = ["a", "b"];
let test = arr.push("c");
console.log(test); // 3
Then, if you want to use clear and intuitive method instead of push(), you can use concat() which returns the array with its values like below:
let arr = ["a", "b"];
let test = arr.concat("c");
console.log(test); // ["a", "b", "c"]
The question is partially answered in the document you mention (Ecma 262 3rd edition), there are methods that mutate the array and methods that don't. The methods that mutate the array will return the length of the mutated array. For adding elements that would be push, splice and unshift (Depending on the position you want the new element in).
If you want to get the new mutated array you can use concat. Concat will input any number of arrays you want added to the original array and add all the elements into a new array. i.e:
const array1 = ['a', 'b', 'c'];
const array2 = ['d', 'e', 'f'];
const array3=['g','h'];
const array4 = array1.concat(array2,array3);
The new array created will have all the elements and the other three won't be changed. There are other (Many) ways to add the elements to an array both mutative and not mutative. So there is your answer, it returns the length because it is changing it, it doesn't need to return the full array.

Categories

Resources