JavaScript: arrays vs objects. Three secrets of arrays in JavaScript that you might not know about
- Translation
- I. Iterating over real arrays
- forEach method and related methods
- for loop
- Proper Use for...in loop
- for...of loop (implicit use of iterator)
- Explicit use of iterator
- Using methods to iterate over real arrays
- Convert to a real array
- A note on runtime objects
I. Iterating over real arrays
On at the moment There are three ways to iterate over the elements of a real array:- method Array.prototype.forEach ;
- classic for loop
- a “correctly” constructed for...in loop.
- for...of loop (implicit use of iterator);
- explicit use of iterator.
1. The forEach method and related methods
If your project is designed to support the features of the ECMAScript 5 (ES5) standard, you can use one of its innovations - the forEach method.Usage example:
var a = ["a", "b", "c"]; a.forEach(function(entry) ( console.log(entry); ));
IN general case using forEach requires connecting the es5-shim emulation library for browsers that do not natively support this method. These include IE 8 and above early versions, which are still in use here and there.
The advantage of forEach is that there is no need to declare local variables to store the index and value of the current array element, since they are automatically passed to the function callback(callback) as arguments.
If you're worried about the possible cost of calling a callback on each element, don't worry and read this.
ForEach is designed to iterate over all elements of an array, but in addition to it, ES5 offers several more useful methods for iterating through all or some elements plus performing some actions on them:
- every - returns true if for each element of the array the callback returns a value that can be converted to true .
- some - returns true if for at least one element of the array the callback returns a value that can be converted to true.
- filter - creates new array, including those elements source array, for which the callback returns true .
- map - creates a new array consisting of the values returned by the callback.
- reduce - reduces an array to a single value, applying a callback to each array element in turn, starting with the first (can be useful for calculating the sum of array elements and other summary functions).
- reduceRight - works similar to reduce, but iterates through elements in reverse order.
2. For loop
Good old for rules:Var a = ["a", "b", "c"]; var index; for (index = 0; index< a.length; ++index) {
console.log(a);
}
If the length of the array is constant throughout the loop, and the loop itself belongs to a performance-critical section of code (which is unlikely), then you can use a “more optimal” version of for that stores the length of the array:
Var a = ["a", "b", "c"]; var index, len; for (index = 0, len = a.length; index< len; ++index) {
console.log(a);
}
In theory, this code should run a little faster than the previous one.
If the order of the elements is not important, then you can go even further in terms of optimization and get rid of the variable for storing the length of the array, changing the order of the search to the reverse:
Var a = ["a", "b", "c"]; var index; for (index = a.length - 1; index >= 0; --index) ( console.log(a); )
However, in modern JavaScript engines such optimization games usually mean nothing.
3. Correct use of the for...in loop
If you are advised to use a for...in loop, remember that iterating over arrays is not what it is intended for. Contrary to a common misconception, the for...in loop does not iterate over array indices, but rather through enumerable properties of an object.However, in some cases, such as iterating over sparse arrays, for...in can be useful, as long as you take precautions, as shown in the example below:
// a - sparse array var a = ; a = "a"; a = "b"; a = "c"; for (var key in a) ( if (a.hasOwnProperty(key) && /^0$|^\d*$/.test(key) && key<= 4294967294) {
console.log(a);
}
}
In this example, two checks are performed at each iteration of the loop:
- that the array has its own property called key (not inherited from its prototype).
- that key is a string containing the decimal representation of an integer whose value is less than 4294967294 . Where does the last number come from? From the definition of an array index in ES5, which shows that the highest index an element in an array can have is: (2^32 - 2) = 4294967294 .
In order not to write such a cumbersome check code every time you need to iterate through an array, you can write it as a separate function:
Function arrayHasOwnIndex(array, key) ( return array.hasOwnProperty(key) && /^0$|^\d*$/.test(key) && key<= 4294967294;
}
Then the body of the loop from the example will be significantly reduced:
For (key in a) ( if (arrayHasOwnIndex(a, key)) ( console.log(a); ) )
The check code discussed above is universal, suitable for all cases. But instead, you can use a shorter version, although formally not entirely correct, but nevertheless suitable for most cases:
For (key in a) ( if (a.hasOwnProperty(key) && String(parseInt(key, 10)) === key) ( console.log(a); ) )
4. For...of loop (implicit use of iterator)
ES6, still in draft status, should introduce iterators to JavaScript.Iterator
is a protocol implemented by an object that defines a standard way to obtain a sequence of values (finite or infinite).
An iterator is an object that defines a next() method - a no-argument function that returns an object with two properties:
- done (boolean) - true if the iterator has reached the end of the iterable sequence. Otherwise the value is false .
- value - defines the value returned by the iterator. May be undefined (missing) if the done property is true .
Example of using for...of:
Varval; var a = ["a", "b", "c"]; for (val of a) ( console.log(val); )
In the example above, the for...of loop implicitly calls the Array object's iterator to obtain each value of the array.
5. Explicit use of iterator
Iterators can also be used explicitly, however, in this case the code becomes much more complicated compared to the for...of loop. It looks something like this:Var a = ["a", "b", "c"]; var it = a.entries(); var entry; while (!(entry = it.next()).done) ( console.log(entry.value); )
In this example, the Array.prototype.entries method returns an iterator that is used to display the values of the array. At each iteration, entry.value contains an array of the form [key, value] .
II. Iterating over array-like objects
In addition to real arrays, in JavaScript there are also array-like objects . What they have in common with real arrays is that they have a length property and properties named as numbers corresponding to the elements of the array. Examples include the DOM of the NodeList collection and the arguments pseudo-array, available inside any function/method.1. Using methods to iterate over real arrays
At a minimum, most, if not all, methods of iterating over real arrays can be used to iterate over array-like objects.The for and for...in constructs can be applied to array-like objects in exactly the same way as they are applied to real arrays.
ForEach and other Array.prototype methods also apply to array-like objects. To do this you need to use Function.call or Function.apply .
For example, if you want to apply forEach to the childNodes property of a Node object, you would do it like this:
Array.prototype.forEach.call(node.childNodes, function(child) ( // do something with the child object));
To make this trick easier to reuse, you can declare a reference to the Array.prototype.forEach method in a separate variable and use it as a shortcut:
// (Assuming all code below is in the same scope) var forEach = Array.prototype.forEach; // ... forEach.call(node.childNodes, function(child) ( // do something with the child object));
If an array-like object has an iterator, it can be used explicitly or implicitly to iterate over the object in the same way as for real arrays.
2. Convert to a real array
There is also another, very simple way to iterate over an array-like object: convert it into a real array and use any of the methods discussed above for iterating over real arrays. For conversion, you can use the generic Array.prototype.slice method, which can be applied to any array-like object. This is done very simply, as shown in the example below:Var trueArray = Array.prototype.slice.call(arrayLikeObject, 0);
For example, if you wanted to convert a NodeList collection into an actual array, you'd need code something like this:
Var divs = Array.prototype.slice.call(document.querySelectorAll("div"), 0);
Update: As noted in the comments
Arrays
Array is an ordered collection of values. The values in an array are called elements, and each element is characterized by a numeric position in the array, called an index. Arrays in JavaScript are untyped: elements of an array can be of any type, and different elements of the same array can have different types. Array elements can even be objects or other arrays, allowing you to create complex data structures such as arrays of objects and arrays of arrays.
JavaScript array indexes start at zero and use 32-bit integers - the first element of the array has index 0. JavaScript arrays are dynamic: they can grow and shrink in size as needed; there is no need to declare fixed array sizes when creating them, or to re-allocate memory when their sizes change.
Arrays in JavaScript are a specialized form of objects, and array indices mean little more than just property names, which coincidentally are integers.
Creating Arrays
The easiest way to create an array is to use a literal, which is a simple comma-separated list of array elements surrounded by square brackets. The values in an array literal do not have to be constants - they can be any expressions, including object literals:
Var empty = ; // Empty array var numbers = ; // Array with five numeric elements var misc = [ 1.1, true, "a", ]; // 3 elements of different types + trailing comma var base = 1024; var table = ; // Array with variables var arrObj = [, ]; // 2 arrays inside containing objects
Array literal syntax allows you to insert an optional trailing comma, i.e. the literal [,] matches an array with two elements, not three.
Another way to create an array is to call the constructor Array(). You can call the constructor in three different ways:
Call the constructor without arguments:
Var arr = new Array();
In this case, an empty array will be created, equivalent to the literal.
Call the constructor with a single numeric argument specifying the length of the array:
Var arr = new Array(10);
In this case, an empty array of the specified length will be created. This form of calling the Array() constructor can be used to pre-allocate memory for an array if the number of its elements is known in advance. Note that this does not store any values in the array.
Explicitly specify the values of the first two or more array elements or one non-numeric element in the constructor call:
Var arr = new Array(5, 4, 3, 2, 1, "test");
In this case, the arguments to the constructor become the values of the elements of the new array. Using array literals is almost always easier than using the Array() constructor.
Reading and Writing Array Elements
Array elements are accessed using the operator. To the left of the brackets there must be an array reference. Inside the parentheses there must be an arbitrary expression that returns a non-negative integer value. This syntax is useful for both reading and writing the value of an array element. Therefore, all of the following JavaScript instructions are valid:
// Create an array with one element var arr = ["world"]; // Read element 0 var value = arr; // Write the value to element 1 arr = 3.14; // Write the value to element 2 i = 2; arr[i] = 3; // Write the value to element 3 arr = "hello"; // Read elements 0 and 2, write the value to element 3 arr] = arr;
Let me remind you that arrays are a specialized type of object. Square brackets used to access array elements act exactly the same as square brackets used to access object properties. The JavaScript interpreter converts the numeric indexes in parentheses into strings—index 1 becomes the string "1"—and then uses the strings as property names.
There's nothing special about converting numeric indexes to strings: you can do the same with regular objects:
Var obj = (); // Create a simple object obj = "one"; // Index it with integers
The thing about arrays is that when you use property names that are non-negative integers, arrays automatically determine the value of the property length. For example, above we created an array arr with a single element. It then assigned values to its elements at indexes 1, 2, and 3. As a result of these operations, the value of the array's length property changed to 4.
You should clearly distinguish indexes in an array from object property names. All indices are property names, but only properties with names represented by integers are indices. All arrays are objects, and you can add properties to them with any names. However, if you touch properties that are array indices, arrays respond by updating the value of the length property as necessary.
Please note that negative and non-integer numbers can be used as array indices. In this case, numbers are converted to strings, which are used as property names.
Adding and Removing Array Elements
We've already seen that the easiest way to add elements to an array is to assign values to new indices. You can also use the method to add one or more elements to the end of the array. push():
Var arr = ; // Create an empty array arr.push("zero"); // Add a value to the end arr.push("one",2); // Add two more values
You can also add an element to the end of the array by assigning a value to the arr element. To insert an element at the beginning of an array, you can use the method unshift(), which moves existing elements in the array to positions with higher indexes.
You can delete array elements using the delete operator, just like regular object properties:
Var arr = ; delete arr; 2 in arr; // false, index 2 in the array is not defined arr.length; // 3: the delete operator does not change the length property of the array
Removing an element is similar (but slightly different) to assigning the value undefined to that element. Note that applying the delete operator to an array element does not change the value of the length property or shift down elements with higher indexes to fill the void left by deleting the element.
It is also possible to remove elements at the end of the array by simply assigning a new value to the length property. Arrays have a method pop()(the opposite of the push() method), which reduces the length of the array by 1 and returns the value of the removed element. There is also a method shift()(the opposite of unshift()), which removes the element at the beginning of the array. Unlike the delete operator, the shift() method shifts all elements down to a position below their current index.
Finally there is a multi-purpose method splice(), which allows you to insert, delete and replace array elements. It changes the value of the length property and shifts array elements to lower or higher indexes as needed. We will look at all these methods a little later.
Multidimensional arrays
JavaScript doesn't support "true" multidimensional arrays, but it does provide a good way to simulate them using arrays of arrays. To access a data element in an array of arrays, simply use the operator twice.
For example, suppose the variable matrix is an array of arrays of numbers. Each element of matrix[x] is an array of numbers. To access a specific number in an array, you can use the expression matrix[x][y]. Below is a specific example where a two-dimensional array is used as a multiplication table:
// Create a multidimensional array var table = new Array(10); // There are 10 rows in the table for(var i = 0; i
Methods of the Array class
The ECMAScript 3 standard defines Array.prototype as a set of convenient functions for working with arrays, which are available as methods on any array. These methods will be presented in the following subsections.
join() method
The Array.join() method converts all array elements into strings, joins them, and returns the resulting string. As an optional argument, you can pass a string to the method that will be used to separate the elements in the result string. If a delimiter string is not specified, a comma is used. For example, the following fragment results in the string "1,2,3":
Var arr = ; arr.join(); // "1,2,3" arr.join("-"); // "1-2-3"
reverse() method
The Array.reverse() method reverses the order of elements in an array and returns a reordered array. The permutation is performed directly in the original array, i.e. This method does not create a new array with the reordered elements, but rather reorders them in an already existing array. For example, the following snippet, using the reverse() and join() methods, results in the string "3,2,1":
Var arr = ; arr.reverse().join(); // "3,2,1"
sort() method
The Array.sort() method sorts the elements in the source array and returns the sorted array. If the sort() method is called without arguments, the sorting is done in alphabetical order (elements are temporarily converted to strings for comparison if necessary). Undefined elements are moved to the end of the array.
To sort in order other than alphabetical, you can pass a comparison function as an argument to the sort() method. This function sets which of its two arguments should come first in the sorted list. If the first argument must come before the second, the comparison function must return a negative number. If the first argument is to follow the second in a sorted array, then the function must return a number greater than zero. And if two values are equivalent (that is, their order does not matter), the comparison function should return 0:
Var arr = ; arr.sort(); // Alphabetical order: 1111, 222, 33, 4 arr.sort(function(a,b) ( // Numeric order: 4, 33, 222, 1111 return a-b; // Returns 0 // depending on the sort order a and b)); // Sort in the opposite direction, from largest to smallest arr.sort(function(a,b) (return b-a));
Notice how convenient it is to use an unnamed function in this snippet. The comparison function is only used here, so there is no need to give it a name.
concat() method
The Array.concat() method creates and returns a new array containing the elements of the original array on which concat() was called and the values of any arguments passed to concat(). If any of these arguments is itself an array, its elements are added to the returned array. It should be noted, however, that there is no recursive transformation of an array of arrays into a one-dimensional array. The concat() method does not change the original array. Below are some examples:
Var arr = ; arr.concat(4, 5); // Return arr.concat(); // Return arr.concat(,) // Return arr.concat(4, ]) // Return ]
slice() method
The Array.slice() method returns a slice, or subarray, of the specified array. The two method arguments specify the start and end of the returned fragment. The returned array contains the element whose number is specified in the first argument, plus all subsequent elements, up to (but not including) the element whose number is specified in the second argument.
If only one argument is given, the returned array contains all elements from the starting position to the end of the array. If any of the arguments is negative, it determines the element number relative to the end of the array. So, argument -1 corresponds to the last element of the array, and argument -3 corresponds to the third element of the array from the end. Here are some examples:
Var arr = ; arr.slice(0,3); // Return arr.slice(3); // Return arr.slice(1,-1); // Return arr.slice(-3,-2); // Return
splice() method
The Array.splice() method is a generic method that performs insertion or deletion of array elements. Unlike the slice() and concat() methods, the splice() method modifies the original array on which it was called. Note that the splice() and slice() methods have very similar names, but perform completely different operations.
The splice() method can remove elements from an array, insert new elements, or do both at the same time. Array elements are shifted as necessary to create a continuous sequence after insertion or deletion.
The first argument of the splice() method specifies the position in the array from which insertion and/or deletion will be performed. The second argument specifies the number of elements that should be removed (cut) from the array. If the second argument is omitted, all array elements from the specified to the end of the array are removed. The splice() method returns an array of the removed elements or (if no elements were removed) an empty array.
The first two arguments to the splice() method specify the array elements to be removed. These arguments can be followed by any number of additional arguments specifying the elements to be inserted into the array, starting at the position specified in the first argument.
Var arr = ; arr.splice(4); // Return , arr = arr.splice(1,2); // Return , arr = arr.splice(1,1); // Return ; arr = arr = ; arr.splice(2,0,"a","b"); // Return ; arr =
push() and pop() methods
The push() and pop() methods allow you to work with arrays as if they were stacks. The push() method adds one or more new elements to the end of the array and returns its new length. The pop() method performs the reverse operation - it removes the last element of the array, reduces the length of the array, and returns the value it removed. Note that both of these methods modify the original array rather than creating a modified copy of it.
unshift() and shift() methods
The unshift() and shift() methods behave almost exactly like push() and pop(), except that they insert and remove elements at the beginning of the array rather than at the end. The unshift() method shifts existing elements to larger indices to free up space, adds the element or elements to the beginning of the array, and returns the new length of the array. The shift() method removes and returns the first element of the array, shifting all subsequent elements down one position to take up the space vacated at the beginning of the array.
JavaScript is designed based on a simple paradigm. The concept is based on simple objects. An object is a collection of properties, and each property consists of a name and a value associated with that name. The property value can be a function, which can be called method object. In addition to the browser's built-in objects, you can define your own objects. This chapter describes how to use objects, properties, functions, and methods, and how to create your own objects.
Overview of objects
Objects in JavaScript, as in many other programming languages, are similar to real-life objects. The concept of JavaScript objects is easier to understand by drawing parallels with real-life objects.
In JavaScript, an object is an independent unit that has properties and a specific type. Let's compare, for example, with a cup. A cup has a color, shape, weight, material from which it is made, etc. Likewise, JavaScript objects have properties that define their characteristics.
Objects and Properties
In JavaScript, an object has properties associated with it. An object property can be understood as a variable assigned to an object. Object properties are essentially the same as JavaScript variables, except that they are assigned to the object. The properties of an object determine its characteristics. You can access a property of an object using dot notation:
ObjectName.propertyName
Like all JavaScript variables, the object name (which can also be a variable) and property name are case sensitive. You can define a property by specifying its value. For example, let's create an object myCar and define its make , model , and year properties as follows:
Var myCar = new Object(); myCar.make = "Ford"; myCar.model = "Mustang"; myCar.year = 1969;
Undefined object properties are undefined (not null).
MyCar. color; // undefined
Properties of JavaScript objects can also be accessed or set using bracket notation (see for more details). Objects are sometimes called associative arrays, because each property is associated with a string value that can be used to access it. So, for example, you can access the properties of the myCar object like this:
MyCar["make"] = "Ford"; myCar["model"] = "Mustang"; myCar["year"] = 1969;
Object property names can be JavaScript strings, or anything that can be converted to a string, including the empty string. However, any property name that contains an invalid JavaScript identifier (for example, a property name that contains a space and a dash, or begins with a number) can be accessed using square brackets. This notation is also useful when property names must be dynamically determined (when the property name is not determined until runtime). Examples below:
Var myObj = new Object(), str = "myString", rand = Math.random(), obj = new Object(); myObj.type = "Dot syntax"; myObj["date created"] = "String with space"; myObj = "String value"; myObj = "Random Number"; myObj = "Object"; myObj[""] = "Even an empty string"; console.log(myObj);
Note that all keys with square brackets are converted to a String type, since objects in JavaScript can only have a String type as a key. For example, in the code above, when the key obj is added to myObj , JavaScript calls the obj.toString() method and uses that resulting string as the new key.
You can also access properties using a string value that is stored in a variable:
Var propertyName = "make"; myCar = "Ford"; propertyName = "model"; myCar = "Mustang";
You can use square brackets in a for...in clause to iterate through all the properties of an object for which it is allowed. To show how this works, the following function shows all the properties of an object when you pass the object itself and its name as arguments to the function:
Function showProps(obj, objName) ( var result = ""; for (var i in obj) ( if (obj.hasOwnProperty(i)) ( result += objName + "." + i + " = " + obj[i ] + "\n"; ) ) return result;
So if we call this function like this showProps(myCar, "myCar"), we will get the result:
MyCar.make = Ford myCar.model = Mustang myCar.year = 1969
Listing all properties of an object
Using the constructor function
Another way to create an object in two steps is described below:
- Determine the type of an object by writing a constructor function. The name of such a function usually begins with a capital letter.
- Create an instance of an object using the new keyword.
To determine the type of an object, create a function that determines the type of the object, its name, properties and methods. For example, suppose you want to create an object type to describe machines. You want an object of this type to be called car , and you want it to have the properties make, model, and year. To do this, write the following function:
Function Car(make, model, year) ( this.make = make; this.model = model; this.year = year; )
Note that this is used to assign values (passed as function arguments) to the properties of the object.
Now you can create an object called mycar like this:
Var mycar = new Car("Eagle", "Talon TSi", 1993);
This statement creates an object of type Car with a reference mycar and assigns certain values to its properties. The value of mycar.make will be the string "Eagle", mycar.year will be the integer 1993, and so on.
You can create as many car objects as you need by simply calling new . For example:
Var kenscar = new Car("Nissan", "300ZX", 1992); var vpgscar = new Car("Mazda", "Miata", 1990);
An object can have a property that will be another object. For example, the following defines an object of type Person as follows:
Function Person(name, age, sex) ( this.name = name; this.age = age; this.sex = sex; )
and then create two new Person object instances as follows:
Var rand = new Person("Rand McKinnon", 33, "M"); var ken = new Person("Ken Jones", 39, "M");
Then, you can rewrite the definition of car to include an owner property, which is assigned a person object like this:
Function Car(make, model, year, owner) ( this.make = make; this.model = model; this.year = year; this.owner = owner; )
Then, to instantiate the new objects, follow these instructions:
Var car1 = new Car("Eagle", "Talon TSi", 1993, rand); var car2 = new Car("Nissan", "300ZX", 1992, ken);
Note that instead of passing a string, literal, or integer when creating new objects, the expressions above pass rand and ken objects as arguments to the function. Now, if you need to find out the owner name of car2, you can do it like this:
Car2.owner
Note that at any time you can add a new property to a previously created object. For example, the expression
Car1.color = "black";
adds a color property to car1, and sets its value to "black." However, this does not affect any other objects. To add a new property to all objects of the same type, you must add the property to the car object's type definition.
Using the Object.create method
Objects can also be created using the Object.create method. This method is very convenient because it allows you to specify a prototype object for a new object of yours without defining a constructor function.
// list of properties and methods for Animal var Animal = ( type: "Invertebrates", // Default value of type displayType: function() ( // Method displaying the type of the Animal object console.log(this.type); ) ); // Create an Animal object var animal1 = Object.create(Animal); animal1.displayType(); // Outputs: Invertebrates // Create an Animal object and assign it type = Fishes var fish = Object.create(Animal); fish.type = "Fishes"; fish.displayType(); // Outputs:Fishes
Inheritance
All objects in JavaScript inherit from at least another object. The object from which the inheritance occurred is called the prototype, and the inherited properties can be found in the constructor's prototype object.
Object Property Indexes
In JavaScript 1.0, you can refer to the properties of an object either by its name or by its ordinal index. In JavaScript 1.1 and later, if you initially defined a property by name, you must always refer to it by its name, and if you initially defined a property by index, you must refer to it by its index.
This limitation is imposed when you create an object and its properties using the constructor function (as we did earlier with the type Car) and when you define individual properties explicitly (e.g. myCar.color="red"). If you initially defined an object property through an index, for example myCar = "25 mpg" , then you can subsequently refer to this property only as myCar .
The exception to the rule is objects rendered from HTML, such as the forms array. You can always refer to the objects in these arrays either by their index (which is based on the order in which they appear in the HTML document) or by their names (if they have been defined). For example, if the second html tag