- Methods
pop
andpush
- Methods
shift/unshift
- Iterating over array
- Using
length
to trim an array Array
isObject
, consequences.- Sparse arrays, details of
length
- Removing from an array
- Method
reverse
- Sorting, method
sort(fn)
- More on array definition
- Summary
Here we’ll talk about regular arrays, that is with numeric indices.
An array is usually declared using square-bracketed notation:
var fruits = ["Apple", "Orange", "Donkey"]
To get an element, put its index in square brackets. First index is 0
:
var fruits = ["Apple", "Orange", "Donkey"] alert(fruits[0]) alert(fruits[1]) alert(fruits[2])
We can also retrieve its length:
var fruits = ["Apple", "Orange", "Donkey"] alert(fruits.length)
Wops! We created an array with two fruits and a donkey. The next step will be to remove the donkey.
Methods pop
and push
There is a method pop
which removes last item and returns it.
The following example demonstrates how the “Donkey” is being popped out.
var fruits = ["Apple", "Orange", "Donkey"] alert("I remove "+fruits.pop()) // Now we have ["Apple","Orange"] alert("Now length is: "+fruits.length) // donkey removed
Note how pop
modifies the array itself.
A counterpart to pop
is push
which appends an element to the array. Let’s say we’ve forgotten a peach:
var fruits = ["Apple", "Orange"] fruits.push("Peach"); // now got ["Apple", "Orange", "Peach"] alert("Last element is:"+fruits[fruits.length-1])
- Create an array
styles
with elements “Jazz”, “Blues”. - Append a value “Rock’n’Roll”
- Replace the second value from tail by “Classic”. The array should become “Jazz”,”Classic”,”Rock’n’Roll”. The code should work for any array length.
- Extract the last value from the array and
alert
it.
// 1 var styles = ["Jazz", "Bluez"] // 2 styles.push("Rock'n'Roll") // or: styles[styles.length] = "Rock'n'Roll" // 3 styles[styles.length-2] = "Classic" // 4 alert( styles.pop() )
Methods shift/unshift
Methods pop/push
manipulate with the end of array, but you can also use shift
to shift off first value or unshift
to prepend a value to an array.
var fruits = ["Apple", "Orange"] var apple = fruits.shift() // now we have only ["Orange"] left fruits.unshift("Lemon") // now got ["Lemon", "Orange"] alert(fruits.length) // 2
Both push
and unshift
can add multiple elements at once:
var fruits = ["Apple"] fruits.push("Orange","Peach") fruits.unshift("Pineapple","Lemon") // now: ["Pineapple", "Lemon", "Apple", "Orange", "Peach"]
Write a code to alert
a random value from array arr
:
var arr = ["Plum","Orange","Donkey","Carrot","JavaScript"]
P.S. The code to get a random integer from min to max (inclusive) is:
var rand = min + Math.floor(Math.random()*(max+1-min))
We need to get a random integer from 0
to arr.length-1
(inclusive).
var arr = ["Plum","Orange","Donkey","Carrot","JavaScript"] var rand = Math.floor(Math.random()*arr.length) alert(arr[rand])
Iterating over array
To iterate over elements, a loop over all indices is usually used.
The following example demonstrates iterating with for
loop.
var fruits = ["Pineapple", "Lemon", "Apple", "Orange", "Peach"] for(var i=0; i<fruits.length; i++) { alert(fruits[i]) }
Create a function find(arr,value)
which finds a value in given array and returns its index, or -1 if not found.
For instance:
arr = [ "test", 2, 1.5, false ] find(arr, "test") // 0 find(arr, 2) // 1 find(arr, 1.5) // 2 find(arr, 0) // -1
A possible solution could look like that:
function find(array, value) { for(var i=0; i<array.length; i++) { if (array[i] == value) return i; } return -1; }
Although it is wrong, because ==
makes no difference between 0
and false
.
More correct variant uses ===
. Also, there is a native function Array#indexOf in the newer ES5 standard. So we can define the function like this:
function find(array, value) { if (array.indexOf) return array.indexOf(value) for(var i=0; i<array.length; i++) { if (array[i] === value) return i; } return -1; } var arr = ["a", -1, 2, "b"]; var index = find(arr, 2); alert(index);
An even smarter step would be to define find conditionally, by checking if the indexOf
method exists. We’ll cover that in the next sections.
Create a function filterNumeric(arr)
which takes an array and returns new array which contains only numeric values from arr
.
An example of how it should work:
arr = ["a", 1, "b", 2]; arr = filterNumeric(arr); // now arr = [1,2]
The solution is to iterate over array and add a value to new array only if it is numeric. Check it out here.
join
and split
Sometimes we need a quick’n’easy way to turn an array into a string. That is exactly what join
method is for.
It joins an array into string using given separator:
var fruits = ["Lemon","Apple","Orange","Peach"]; var str = fruits.join(', '); alert(str);
The inverse operation is also easy with split
:
var fruits = "Apple,Orange,Peach"; var arr = fruits.split(','); // arr is ["Apple", "Orange", "Peach"] alert(arr[0]);
An object has a className
property which keeps it’s class names delimited by spaces:
var obj = { className: 'open menu' }
Write a function addClass(obj, cls)
which adds a class cls
, but only if it doesn’t yet exist:
addClass(obj, 'new') // obj.className='open menu new' addClass(obj, 'open') // no changes (class already exists) addClass(obj, 'me') // obj.className='open menu new me' alert(obj.className) // "open menu new me"
P.S. Your function shouldn’t add extra spaces.
The solution is to split the className
and loop over pieces. If there is no matching class, then add it.
The loop is slightly optimized for performance:
function addClass(elem, cls) { for(var c = elem.className.split(' '), i=c.length-1; i>=0; i--) { if (c[i] == cls) return } elem.className += ' '+cls } var obj = { className: 'open menu' } addClass(obj, 'new') addClass(obj, 'open') alert(obj.className) // open menu new
In the example above, var c
is defined in the beginning of the loop and i
is set to it’s last index.
The loop itself goes backwards, ending condition is i>=0
. The reason is that i>=0
check is faster than i. It evades
length
property lookup in c
.
Create a function camelize(str)
which transforms a string from “my-short-string” to “myShortString”.
So, all parts after a hyphen become camelcased instead. For instance:
camelize("background-color") == 'backgroundColor' camelize("list-style-image") == 'listStyleImage'
Such function may be useful when operating with CSS.
Note. Remember charAt
, substr
and check str.toUpperCase()
function which transforms the string to upper case.
Using length
to trim an array
Using length
property, one can trim an array as follows:
var arr = [0, 1, 2, 3] alert(arr[2]); // ok it's here arr.length = 2; // trim to 2 elements (that is: [0,1]) alert(arr[2]); // nope, it was trimmed out
You just set the length and browser trims the array.
Array
is Object
, consequences.
In fact Array
in JavaScript is internally an Object
extended with auto-length and special methods.
This is different from arrays in some languages which represent a contiguous segment of memory, and also different from queue/stack structures based on linked-lists.
The keys are numeric, but can have any name:
arr = [] arr[0] = 5 *!*arr.prop = 10*/!* // don't do that
Although that’s not recommended. Numeric arrays are suited for numeric keys, objects are for associative key-value pairs. There’s usually no reason to mix them.
In JavaScript, arrays being a hash table gives certain performance benefits and drawbacks.
For instance, push/pop
operate on last element of array only, so they are blazingly fast, say O(1).
See what I mean, push
only works with the tail:
var arr = ["My", "array"] arr.push("something") alert(arr[1]) // string "array"
Methods shift/unshift
are slow, because they have to renumber whole array. Method splice
may also lead to renumbering.
So, using shift/unshift
is generally slower than push/pop
. The larger array - the more work to renumber it.
What will be the result? Why?
arr = ["a", "b"] arr.push( function() { alert(this) } ) arr[arr.length-1]() // ?
Because arrays are objects, arr<a href="/..">..</a>
is actually an object method call, like obj<a href="/method">method</a>
.
arr[arr.length-1]() // is same as arr[2]() // syntactically wrong, but ideologically same as: arr.2() // rewritten to be same style as obj.method()
this = arr
is passed to the function in such case, so the contents of arr
is alerted.
arr = ["a", "b"] arr.push( function() { alert(this) } ) arr[arr.length-1]() // "a","b",function
Sparse arrays, details of length
The length
property in JavaScript is not quite a length, it is last index + 1
.
That becomes important in sparse arrays, with ‘holes’ in indexes.
In the next example we add two elements to empty fruits
, but length
becomes 100
:
var fruits = [] // empty array fruits[1] = 'Peach' fruits[99] = 'Apple' alert(fruits.length) // 100 (but 2 elements)
If you try to output a sparse array, the browser outputs values at skipped indexes as empty:
var fruits = [] // empty array fruits[2] = 'Peach' fruits[5] = 'Apple' alert(fruits) // ,Peach,,,Apple (or kind of)
But naturally, an array is just an object with two keys. The missing values do not occupy space.
Sparse arrays behave weird when array methods are applied to them. They don’t have an idea that indexes are skipped:
var fruits = [ ] fruits[1] = 'Peach' fruits[9] = 'Apple' alert( fruits.pop() ) // pop 'Apple' (at index 9) alert( fruits.pop() ) // pop undefined (at index 8)
Try to evade sparse arrays. Anyway, it’s methods won’t work well. Use an Object
instead.
Removing from an array
As we know, arrays are just objects. So we could use delete
to remove a value:
var arr = ["Go", "to", "home"] delete arr[1] // now arr = ["Go", undefined, "home"] alert(arr[1]) // undefined
You see, the value is removed, but probably not the way we’d want it to be, because array has got an undefined hole inside.
A delete
operator removes key-value pair, that’s all it does. Naturally, because array is just a hash, the slot becomes undefined
.
More often we need to remove an item without leaving holes between indexes. There is another method which helps with that.
Method splice
Method splice
is a swiss-knife for JavaScript arrays, it can delete elements and replace them.
It’s syntax is as follows:
arr.splice(index, deleteCount[, elem1, ..., elemN])
- Remove
deleteCount
elements starting withindex
and then pasteelem1, ..., elemN
on their place.
Let’s see a few examples.
var arr = ["Go", "to", "home"] arr.splice(1, 1) // remove 1 element starting at index 1 alert( arr.join(',') ) // ["Go", "home"] (1 element removed)
This way you can use splice
to remove a single element from an array. Array numbers shift to fill the gap.
var arr = ["Go", "to", "home"] arr.splice(0, 1) // remove 1 element starting at index 0 alert( arr[0] ) // "to" became first element
The next example demonstrates how to replace elements.
var arr = [*!*"Go", "to", "home",*/!* "now"]; // remove 3 first elements and add two arr.splice(0, 3, "Come", "here") alert( arr ) // [*!*"Come", "here"*/!*, "now"]
Method splice
returns array of removed elements:
var arr = [*!*"Go", "to", "home",*/!* "now"]; // remove 2 first elements var removed = arr.splice(0, 2) alert( removed ) // "Go", "to" <-- array of removed elements
Splice
is able to insert elements, just set deleteCount
to 0
.
var arr = ["Go", "to", "home"]; // from 2nd position // delete 0 // and insert "my", "sweet" arr.splice(2, 0, "my", "sweet") alert( arr) // "Go", "to", "my", "sweet", "home"
It also can use a negative index, which counts from array end:
var arr = [1, 2, 5] // at element -1 (pre-last) // delete 0 elements, // then insert 3 and 4 arr.splice(-1, 0, 3, 4) alert(arr) // 1,2,3,4,5
An object has a className
property which keeps it’s class names delimited by spaces:
var obj = { className: 'open menu' }
Write a function removeClass(obj, cls)
which removes a class cls
if it is set:
removeClass(obj, 'open') // obj.className='menu' removeClass(obj, 'blabla') // no changes (no class to remove)
The solution is to split the className
and loop over pieces. If there is a match, then remove it from the array and join the array back at the end.
We’ll do it in a slightly optimized way:
function removeClass(elem, cls) { for(var c = elem.className.split(' '), i=c.length-1; i>=0; i--) { if (c[i] == cls) c.splice(i,1) } elem.className = c.join(' ') } var obj = { className: 'open menu' } removeClass(obj, 'open') removeClass(obj, 'blabla') alert(obj.className) // menu
In the example above, var c
is defined in the beginning of the loop and i
is set to it’s last index.
The loop itself goes backwards, ending condition is i>=0
. The reason is that i>=0
check is faster than i. It evades
length
property lookup in c
.
Create a function filterNumericInPlace(arr)
which takes an array and removes all non-numeric values from it.
An example of how it should work:
arr = ["a", 1, "b", 2]; filterNumericInPlace(arr); alert(arr) // [1,2]
The solution is to iterate over array and use arr.splice
to remove non-numeric values. Check it out here.
Method slice
You can also extract a portion of array using slice(begin[, end])
:
var arr = ["Why", "learn", "JavaScript"]; var arr2 = arr.slice(0,2) // take 2 elements starting at 0 alert(arr2.join(', ')) // "Why, learn"
Note, this method does not modify array, it just copies a slice of it.
You can omit second argument to get all elements starting with certain index:
var arr = ["Why", "learn", "JavaScript"]; var arr2 = arr.slice(1) // take all elements starting at 1 alert(arr2.join(', ')) // "learn, JavaScript"
The method also supports negative indices, just like String#slice
.
Method reverse
Another useful method is reverse. Suppose, I want a last part of a domain, like “com” from “my.site.com”. Here is how I can do that:
var domain = "my.site.com" var last = domain.split('.').reverse()[0] alert(last)
Note how JavaScript allows complex syntax like: reverse()[0]
- to call a method and then take an element of resulting array.
Actually, you can compose longer calls, like reverse()<a href="/0%5D%5B1">0][1</a>[5]...
, language syntax allows that.
Sorting, method sort(fn)
Method sort()
sorts the array in-place:
var arr = [ 1, 2, 15 ] arr.sort() alert( arr ) // 1, 15, 2
Run the example above. Notice something strange? The order is 1, 15, 2.
That’s because sort
converts everything to string and uses lexicographical order by default.
To make it smarter, we need to pass in the custom comparison function. It should accept two arguments and return 1, 0 or -1:
function compare(a, b) { if (a > b) return 1 else if (a < b) return -1 else return 0 } var arr = [ 1, 2, 15 ] arr.sort(compare) alert( arr ) // 1, 2, 15
Now it works right.
Create a function ageSort(people)
to sort array of people objects by their age.
var john = { name: "John Smith", age: 23 } var mary = { name: "Mary Key", age: 18 } var bob = { name: "Bob-small", age: 6 } var people = [ john, mary, bob ] ageSort(people) // now people is [ bob, mary, john ]
Output people names after sorting.
The solution makes use of Array#sort
and custom comparison:
function ageCompare(a, b) { if (a.age > b.age) return 1 else if (a.age < b.age) return -1 return 0 } *!* function ageSort(people) { people.sort(ageCompare) } */!* // test it var john = { name: "John Smith", age: 23 } var mary = { name: "Mary Key", age: 18 } var bob = { name: "Bob-small", age: 6 } var people = [ john, mary, bob ] ageSort(people) // check the order for(var i=0; i<people.length; i++) { alert(people[i].name) }
Shorter variant
The comparison function may be shorter. Alternative solution:
people.sort(function(a,b) { return a.age - b.age })
It works, because it is not required to return 1/-1/0, positive or negative will do.
More on array definition
new Array()
Technically, there is another syntax to define an array:
var arr = Array("Apple", "Peach", "etc")
It is rarely used, just because square brackets []
are shorter.
Also, there is a pitfall here, because new Array
, called with single numeric argument produces an array of undefined
with given length:
var arr = new Array(2,3) // ok we have [2, 3] arr = new Array(2) // do we have [2] ? alert(arr[0]) // no! we have array [undefined, undefined]
The example above outputs undefined
, because new Array(number)
creates an empty array with length
set to number
.
That might be quite unexpectable. But if you know about the feature, then here’s a nice use of new Array(number)
:
var indent = new Array(5).join('a') // aaaa (4 times)
That’s a smart way to repeat a string.
Multidimensional arrays
Arrays in JavaScript can store any data type inside.
var arr = ["My", "Small array", true, {name:'John'}, 345] alert(arr[1]) // Small array
That can be used to store multidimensional arrays:
var matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ] alert(matrix[1][1]) // central element
Make a generic function filter(arr, func)
which filters an array using given function.
Only those elements for which func(elem)
returns true
should compose the result.
Every element which pass through and returns new array which contains only numeric values from
arr
.
An example of how it should work:
arr = ["a", -1, 2, "b"] arr = filter(arr, isNumeric) // arr = [-1, 2], only numeric in result arr = filter(arr, function(val) { return val > 0 }) // arr = [2] , for other values function returns false
There is nothing really special in this task. Passing functions around and applying them is easy in JavaScript. Check the solution here.
A prime number is a natural number which has exactly two distinct natural number divisors: 1 and itself.
To find all the prime numbers less than or equal to a given integer n by Eratosthenes’ Sieve:
- Create a list of consecutive integers from two to
n: (2, 3, 4, ..., n)
. - Set
p=2
, the first prime number. - Strike from the list all multiples of
p
less than or equal ton
. (2p, 3p, 4p
, etc.) - Set p to first not striked number in the list after
p
. - Repeat steps 3-4 until
p*p > n
. - All the remaining numbers in the list are prime.
There is also an animation available.
Implement the Eratosthenes’ Sieve in JavaScript. Compute the sum of all primes up to 100 and alert it.
Summary
That’s all with deep introduction to array.
We’ve covered:
- How to declare an array, two syntaxes.
- How to add, replace, remove from/to array and its both ends.
- How to iterate over an array.
- How to split a string into array and join it back.
- Relations between
Array
andObject
in JavaScript
That’s enough 95% of time. For more methods and examples, refer to Array in Mozilla manual.