Javascript Arrays - How do they work internally? - javascript

I wanted to know how javascript arrays work internally, I mean when for example you create a new array.
array = [1,2,3];
It's internally creating a new array: array = new Array();
and then calling Array.push() or similar?
Thanks.

The best resource to find out how javascript internals work is ECMAScript specification itself.
In order to understand what happens internally when you do array = [1, 2, 3] you would need to read section 7.3.16 CreateArrayFromList (elements). Roughly what happens is that first Array object gets created, then each element gets set to this object with CreateDataProperty (7.3.4 CreateDataProperty section) (DefineOwnProperty) internal method.
Then you want to learn what exactly happens when you push element to array. You check 22.1.3.17 Array.prototype.push ( ...items ) section for this. There you will find out that it uses quite different algorithm, namely it sets specific property of an object (7.3.3 Set (O, P, V, Throw) section).
So the answer is no, creating array like a = [1, 2, 3] does not uses same mechanics to insert items as push does. The first one roughly creates new property on (newly created) array object, the push sets property to existing object.

and then calling Array.push() or similar?
No. As you can see in the below example that when array is initialized push (overridden) method is not invoked.
Array.prototype.push = function(){ console.log("adding") };
var array = [1,2,3];
//console.log(array);
But, it is invoked when console statement is executed (after un-commenting the same).

var array = [1,2,3];
It doesn't call push but it's a simpler way to initialize an array when you know the elements in advance.
If you want to add another element you can do it in multiple ways like:
1) array.push(22); // adds integer 22 to the array
or
2) array[4] = 22; // adds integer 22 to the array at index 4
You can even do this:
array[20] = 22; // this will resize the array and keep all the uninitialized elements returns undefined. So array[10] is undefined, for ex.
If you want to know all the details about arrays explained in a simple way I recommend you the book: Secrets of the JavaScript Ninja. It has an entire chapter about arrays.
https://www.amazon.com/Secrets-JavaScript-Ninja-John-Resig/dp/1617292850/ref=sr_1_1?ie=UTF8&qid=1519484868&sr=8-1&keywords=javascript+ninja

Related

Why does the isArray() Javascript method in this example returns true, if the array has been redefined as a standard object?

I'm trying to learn Javascript - here's my issue:
In the w3schools.com javascript array examples, they show the sequent example:
var person = [];
person["firstName"] = "John";
person["lastName"] = "Doe";
person["age"] = 46;
document.getElementById("demo").innerHTML =
person[0] + " " + person.length;
An array "person" has been defined, but then they proceed to add some elements whit a "named" index. Then tries to print the HTML document the 0th element and the number of elements of the array, like you would do with a standard array.
The description says:
If you use a named index when accessing an array, JavaScript will
redefine the array to a standard object, and some array methods and
properties will produce undefined or incorrect results.
In fact, person[0] and person.length return respectively "undefined" and "0". Even is person was initially defined as an array, by inserting new named indexes elements, the array should be redefined as an object. But when i try do use the Array.isArray() method for checking it, it returns true:
var person = [];
person["firstName"] = "John";
person["lastName"] = "Doe";
person["age"] = 46;
document.getElementById("demo").innerHTML =
person[0] + " " + person.length;
document.getElementById('test').innerHTML = Array.isArray(person);// returns true
So, why? if, as specified by the tutorial, this has been effectively redefined as a standard object, and the ECMAScript 5 has added the .isArray() method for checking if something is an array and nothing else, shouldn't this return false insted of true?
I'm sure i missed something. If i define person like this:
person = {};
then it returns false, as expected. What is happening here? I just wanted to understand arrays a little bit more, this confuses me. Is this just a broken array, but still an array?
Here's the example (without the Array.isarray() bit, just the default): https://www.w3schools.com/js/tryit.asp?filename=tryjs_array_associative_2
First of all I want to note that the example you took from the w3schools page on arrays, is from the "Associative Arrays" section, which has this important introduction:
Many programming languages support arrays with named indexes.
Arrays with named indexes are called associative arrays (or hashes).
JavaScript does not support arrays with named indexes.
In JavaScript, arrays always use numbered indexes.
This puts the example into context, because it really makes no sense to define a variable as an array and then use string keys. But this was an example to illustrate the point.
Does an Array become an Object?
That JavaScript still considers the variable to be an array is as expected. It becomes an array at the moment of assignment of [], and that does not change by adding properties to that object. Yes, arrays are objects. They just have additional capabilities.
The array did not lose any of its array-like capabilities, but those features just don't work on those string properties, ... only on numerical ones (more precisely, the non-negative integer ones).
You loosely quoted the following statement from w3schools:
If you use named indexes, JavaScript will redefine the array to a standard object.
That is wrong information and leads to your misunderstanding. There is no redefinition happening. When you add properties to any object, then the object does not change "type". It remains an instance of what it was before... An array remains an array, a date object remains a date, a regex object remains a regex, even if you assign other properties to it. But non-numerical properties do not "count" for an array: the length will remain unchanged when you add such properties. The length only reveals something about the numerical properties of the object.
This quote is yet another illustration of what the JavaScript community thinks about w3schools.com, i.e. that it is not the most reliable reference, even though it has its value for learning the language.
Example of adding useful properties to arrays
Having said the above, there are cases where you may intentionally want to make use of such properties on arrays. Let's for example think of an array of words that is sorted:
const arr = ["apple", "banana", "grapefruit", "orange", "pear"];
Now let's add something to this array that denotes that it is currently sorted:
arr.isSorted = true;
We could imagine a function that would allow one to add a value to this array, but which also verifies if the array is still sorted:
function addFruit(arr, fruit) {
if (arr.length && fruit < arr[arr.length-1]) {
arr.sorted = false;
}
arr.push(fruit);
}
Then after having added several values, it would maybe be interesting to verify whether the array needs sorting:
if (!arr.sorted) arr.sort();
So this extra property helps to avoid executing an unnecessary sort. But for the rest the array has all the functionality as if it did not have that extra property.
An object that is set up as an array and then filled as an object becomes a member of both classes. Methods of the Array class will apply to its 'array-ness':
Array.isArray(person);
returns true. Methods of the Object class will apply to its 'object-ness':
typeof(person);
returns object. When it could be either one, the 'array-ness' will prevail, because the variable was first defined as an array:
console.log(person);
will put Array [ ] on the console, because it runs the Array class's logging method. It is displayed as an empty array, since it has no numbered elements, but you could add some:
person[2]=66;
and then console.log would log Array [ <2 empty slots>, 66 ].
I think the polyfill implementation of isArray() will clear your doubt by some extent.
#Polyfill

JavaScript: Weird (edge?) case of a mixed Array/Object

I saw this for the first time (or noticed it for the first time) today during a maintenance of a colleagues code.
Essentially the "weird" part is the same as if you try to run this code:
var arr = [];
arr[0] = "cat"; // this adds to the array
arr[1] = "mouse"; // this adds to the array
arr.length; // returns 2
arr["favoriteFood"] = "pizza"; // this DOES NOT add to the array. Setting a string parameter adds to the underlying object
arr.length; // returns 2, not 3
Got this example from nfiredly.com
I don't know what the technical term for this "case" is so I haven't been able to find any additional information about it here or on Google but it strikes me very peculiar that this "behaviour" can at all exists in JavaScript; a kind of "mix" between Arrays and Objects (or Associative Arrays).
It states in the above code snippet that that Setting a string parameter adds to the underlying object and thus not affect the length of the "array" itself.
What is this kind of pattern?
Why is it at all possible? Is it a weird JS quirk or is it deliberate?
For what purpose would you "mix" these types?
It's possible because arrays are objects with some special behaviors, but objects nevertheless.
15.4 Array Objects
However, if you start using non-array properties on an array, some implementations may change the underlying data structure to a hash. Then array operations might be slower.
In JavaScript, arrays, functions and objects are all objects. Arrays are objects created with Array constructor function.
E.g.
var a = new Array();
Or, using shortcut array literal,
var a = [];
Both are the same. They both create objects. However, special kind of object. It has a length property and numeric properties with corresponding values which are the array elements.
This object (array) has methods like push, pop etc. which you can use to manipulate the object.
When you add a non-numeric property to this array object, you do not affect its length. But, you do add a new property to the object.
So, if you have
var a = [1];
a.x = 'y';
console.log(Object.keys(a)); // outputs ["0", "x"]
console.log(a); // outputs [1];

What's is the difference between Array.of(n) , Array(n) and array = [n]?

As the title, i'm wondering what's the difference between this 3 methods of initialization an array.
I'm actually more interested in the new Array.of() method provided from ES6, why they feel the needs of implements that?
The Array constructor can be called in two ways: a list of values to be used as values for array elements, or with a single numeric value giving the initial length:
var myArray = new Array("hello", "world"); // 2 elements
var otherArray = new Array(100); // 100 elements, all empty
Because there's an ambiguity when just one number is passed, that old API is considered badly designed. Thus, there's Array.of(), which is the same as the first option for the Array constructor:
var otherArray = Array.of(100); // 1 element
The third way to make an array is with an array initialization expression:
var otherArray = [100]; // 1 element
The array instances that are created by each of the above are functionally equivalent and completely interchangeable.
One more thing: why does Array.of() have to exist, given that we can use the array initialization expression? Well, Array.of() is a function, so it can be used as a value applied in functional-style programming. You can (as a slightly dumb example) copy an array with:
var copy = Array.of.apply(Array, original);
One reason that's dumb is that there's also (in ES2015) Array.from() to do the same thing:
var copy = Array.from(original);
That works on any sort of iterable original, so it's a good way to turn arguments or a NodeList into an array.
The MDN site has documentation on Array.of(). The constructor and the array initializer form have been around since forever, so any JavaScript reference will cover those (though possibly without reference to Array.of()).
Array.of(2) will create an array with the element 2.
var temp = Array.of(2); // temp = [2]
Array(2) will create an array of 2 elements.
var temp = new Array(2); // temp = [undefined, undefined]
temp = [2] will create an array with the element 2.
var temp = [2]; // temp = [2]

Attaching a function to an array

var primes=[2,3,5,7]
primes.sync = function(){this[0]=23;}
primes // => [2, 3, 5, 7]
primes.sync()
primes // => [23, 3, 5, 7]
This seems to work perfectly in Chrome.
Are there any reasons to not use this syntax/"feature"? Also, can I count on primes to be behave as a normal array (e.g. when passing it to a function that expects an array)?
This is why I want to use it:
Say I have a peopleList in my program. Functions all over the app will use it like an array. Then, suddenly, I do a POST to the server. I then want the array to query the server directly, and update itself. This would allow for some very elegant code in my angular.js app.
The only trouble you'll likely have will be if you (incorrectly) try to use for-in to iterate the Array. As long as you use a for statement or one of the Array iterator methods to constrain the enumeration to numeric indices, there shouldn't be any trouble.
The Array will continue to behave like a typical Array.
What you would want to do is to add a function to Array.prototype, rather than adding it to an array instance. See below.
Array.prototype.sync = function(){this[0]=23;};
This way, all array instances, including those that have been initialized before adding the function, will automatically be able to use the function at once.
var a = [];
a.sync(); // TypeError: Object [object Array] has no method 'sync'
Array.prototype.sync = function(){this[0]=23;};
a.sync();
a // [23]
var b = [1,2,3];
b.sync();
b // [23, 2, 3]
However, only add those functions that are useful/meaningful/reusable to Array.prototype because it is going to be available for all array instances ever created and will be created.
If your function is going to be used by only few instances. You are better of adding them to each instance like you did above.

Is always necessary to use new at create an instance of Array in JavaScript? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What are the best practices to follow when declaring an array in Javascript?
Would be correct don't use new Array after of defining a variable using []?
var v = [];
v = Array(5); // is new necessary?
You are creating two Array objects and throwing away one, so what you are doing is not necessary.
Declare the variable and create an array:
var v;
v = new Array(5);
Or as a single statement:
var v = new Array(5);
The preferred way of creating arrays is using new Array when you want to specify a size, and an array literal when you want to create an array from items:
var a1 = new Array(42); // creates an array with 42 undefined items
var a2 = [1, 2, 3]; // creates an array with the 3 items
For a zero size array you can use either:
var a1 = new Array(); // creates an empty array
var a2 = []; // creates an empty array
The Array constructor can also take a list of items, but that use should be avoided because it behaves differently if there is one item and that item is numerical:
var a1 = new Array(100, 101, 102); // creates an array with three items
var a2 = new Array(100, 101); // creates an array with two items
var a3 = new Array(100); // creates an array with 100 undefined items
The first line creates an empty array.
The second creates an array with 5 elements, all of which have the value undefined.
There is no sense in using both of them. Which one to use depends on what you are trying to do, but the second form is not encountered very often in practice. It's very likely that the first is all you are going to need.
No it is not necessary because both do the same thing. Basically all you should be doing is :
var v=[]; or var v=[value1, value2 ...];
The second version of defining an array has some issues like:
Array(4) ==> creates an empty 4-elements array
Array(4,5) ==> creates an array with 2 elements (4 and 5)
So if you want to create a 1 element array, it blows up in your face. Therefore, the first version is recommended.
The simple answer is that there's almost never a good reason to use the Array keyword in a declaration, whether that's:
var a = Array(n)
or
var a = new Array(n)
just use:
var a = [];
instead.
See https://stackoverflow.com/a/11500550/6782
Its not necessary to use new with Array,i think you can create Array without using new operator
You are reassigning the value of v from a zero length array to an array of length 5. This makes the =[] part redundant.
EDIT:
The major difference here is that the Array constructor's prototype can be modified, so what you get in the end is not necessarily identical to a standard issue javascript Array.
When you assign using [], an internal constructor is used, which means Array prototype tampering will not affect your new object. For example, I can set Array.prototype.join=function(){alert("duh");} and all Arrays that you construct using new Array(...) will alert "duh" when you try to call the join method. Arrays assigned using [] are immune to this.
JavaScript - unlike most language - provides you arrays that kind of self-extend themselves when needed. But that doesn't mean it has no cost.
If you have an array of length N and put something at index M >= N, it has to create a new array of length M - 1, copy everything from N into it and then add your element, that's quite slow.
Note that JavaScript has very diverse implementations and that some just consider arrays as normal objets with a special length property.
So to avoid that, when you know what size your array will be but not what it'll contain, you use new Array( size ). If you know what it will contain, it's better to use the litteral notation [ item1, item2 ]. And if you really don't know, just put [].
added

Categories

Resources