Data Structure Introduction

This notebook is to help you learn the basics of JavaScript data structures, particularly lists and dictionaries. You have hopefully seen a little bit of these two data structures in 2308, as list or vector and hash_map. Python and JavaScript both make these structures very easy to work with, and web development depends heavily on them.

This is a JavaScript translation of the Python Data Structures notebook.

Warmup: Basic JavaScript Types

JavaScript provides a variety of basic data types that support common operations.

You can write numbers and strings:

In [1]:
var a_num = 5
var a_str = 'puppy'
Out[1]:
undefined

Note that, unlike Python, we declare our variables with var. JavaScript requires you to declare your variables (like C++), but does not give them types (unlike C++).

Our notebook will also happily print the value of the last expression:

In [2]:
a_str
Out[2]:
'puppy'

You can do math, of course:

In [3]:
a_num * 3
Out[3]:
15

And manipulate strings:

In [4]:
a_str + ' dog'
Out[4]:
'puppy dog'

JavaScript can coerce data to other types, unlike Python. While the following Python code:

'puppy' + 5

will fail, JavaScript is just fine with it:

In [5]:
a_str + 5
Out[5]:
'puppy5'

If one of the operands of + is a string, it will convert the other to a string and concatenate them.

JavaScript does not have a good, built-in equivalent to Python's string formatting.

We can find out the length of a string:

In [6]:
a_str.length
Out[6]:
5

A Note on Equals

In Python, == respects type: a string is never equal to a number.

In JavaScript, == will convert the objects to be of a compatible type and then compare them.

In [7]:
1 == 1
Out[7]:
true
In [8]:
'1' == 1
Out[8]:
true
In [9]:
0 == false
Out[9]:
true
In [10]:
1 == null
Out[10]:
false
In [11]:
0 == null
Out[11]:
false
In [12]:
1 == true
Out[12]:
true

Wonky. To avoid that, use === (strict comparison) instead of ==:

In [13]:
0 === false
Out[13]:
false

There is a corresponding !== operator.

Writing Functions

We can write functions in JavaScript:

In [14]:
function add5(n) {
    return n + 5
}
Out[14]:
undefined
In [15]:
add5(10)
Out[15]:
15

The function is declared with function, and its parameters are just named (without types), as they are in Python.

To help us avoid certain errors in JavaScript, it is useful to enable strict mode for all our JavaScript functions:

In [16]:
function fib(n) {
    'use strict'; // this enables strict mode
    // also, comments work like C++
    var v1 = 1, v2 = 1;
    var i;
    for (i = 2; i < n; i++) {
        var tmp = v2;
        v2 = v2 + v1;
        v1 = tmp;
    }
    return v2;
}
fib(5)
Out[16]:
5
In [17]:
fib(10)
Out[17]:
55

Strict mode turns things like undeclared variables into errors, and makes a few other improvements. It is not supported by all JavaScript engines, but modern browsers support it.

Arrays

Lists, which JavaScript calls arrays, do what they say on the tin: they store a list of things. Think like a grocery list, or a to-do list: it is a sequence of items.

For example, the following code creates a new list and assigns it to a variable called beatles:

In [18]:
var beatles = ['John', 'Paul', 'George', 'Ringo']
Out[18]:
undefined

We can see that the list has 4 items by examining its length:

In [19]:
beatles.length
Out[19]:
4

JavaScript arrays look a lot like C++ arrays, in that we can get a specific item:

In [20]:
beatles[0]
Out[20]:
'John'

and we can reassign one:

In [21]:
beatles[2] = 'Albert'
Out[21]:
'Albert'

If we want to loop over the elements of an array, the most straightforward way to do it is with a C++-style counter loop:

In [22]:
var i;
for (var i = 0; i < beatles.length; i++) {
    console.log(beatles[i])
}
John
Paul
Albert
Ringo
Out[22]:
undefined

(The undefined is just because the last expression — our for loop — does not return any value, but the JavaScript notebook support doesn't suppress JavaScript undefined like it does Python None.)

We can also loop using JavaScript's forEach method, and an anonymous function. This is the way that is most analagous to Python's for loop, and is often what I use:

In [23]:
beatles.forEach(function(beatle) {
    console.log(beatle)
})
John
Paul
Albert
Ringo
Out[23]:
undefined

This code creates a little function that prints out its argument, and passes that function as an object to the forEach method of the JavaScript array. Like Python, but unlike C++, functions are objects that can be passed around like any other object. This is a common pattern in JavaScript.

ES6, the latest version of the JavaScript standard, introduces a for loop that works like Python's:

for (var beatle of beatles) {
    console.log(beatle)
}

Unfortunately, ES6 support is not sufficiently widespread to allow us to take advantage of this.

Like Python lists, but unlike C++ arrays, JavaScript arrays allow us to add values:

In [24]:
var results = []
results.length
Out[24]:
0

OK, an empty list. Let's add things to it:

In [25]:
results.push('wumpus')
Out[25]:
1

JavaScript uses push instead of Python's append. We can see that the results list now has length 1:

In [26]:
results.length
Out[26]:
1

And see the element there:

In [27]:
results[0]
Out[27]:
'wumpus'

There isn't a good way to delete arbitrary elements of an array. However, we can delete the first element with shift, or the last with pop.

In [28]:
results.shift()
Out[28]:
'wumpus'
In [29]:
results.length
Out[29]:
0

We can populate it in a loop:

In [30]:
for (var i = 0; i < beatles.length; i++) {
    results.push("Beatle number " + i + " is " + beatles[i]);
}
results
Out[30]:
[ 'Beatle number 0 is John',
  'Beatle number 1 is Paul',
  'Beatle number 2 is Albert',
  'Beatle number 3 is Ringo' ]

Objects

JavaScript objects work like Python dictionaries or other languages' hash tables and maps. They let us associate arbitrary properties by name, and put data in them. The syntax is even very similar.

In [31]:
var liz_the_first = {
    'name': 'Elizabeth I',
    'region': 'England',
    'birth_date': '1533-09-07',
    'death_date': '1603-03-24',
    'coronation_date': '1559-01-15'
}
Out[31]:
undefined

The squiggly braces denote an object, and the keys and values are separated by colons (:).

Finding out how many things are in it is a little trickier. There is a method, Object.keys, that gives us an array of the keys in the object:

In [32]:
Object.keys(liz_the_first)
Out[32]:
[ 'name', 'region', 'birth_date', 'death_date', 'coronation_date' ]

We can get its length:

In [33]:
Object.keys(liz_the_first).length
Out[33]:
5

We can get individual items:

In [34]:
liz_the_first['name']
Out[34]:
'Elizabeth I'

Since name is a valid JavaScript identifier, we can also just access it as a property:

In [35]:
liz_the_first.name
Out[35]:
'Elizabeth I'

We can also assign new values:

In [36]:
liz_the_first.mother = 'Anne Boleyn'
liz_the_first['family'] = 'Tudor'
Out[36]:
'Tudor'

Now, if we want to iterate over the keys, we can do this:

In [37]:
for (var k in liz_the_first) {
    console.log(k + ': ' + liz_the_first[k])
}
name: Elizabeth I
region: England
birth_date: 1533-09-07
death_date: 1603-03-24
coronation_date: 1559-01-15
mother: Anne Boleyn
family: Tudor
Out[37]:
undefined

This kind of a for loop only works for iterating over object keys.

We can also delete information, and assign arbitrary types of values:

In [38]:
delete liz_the_first.region
liz_the_first.regions = ['England', 'Ireland']
liz_the_first
Out[38]:
{ name: 'Elizabeth I',
  birth_date: '1533-09-07',
  death_date: '1603-03-24',
  coronation_date: '1559-01-15',
  mother: 'Anne Boleyn',
  family: 'Tudor',
  regions: [ 'England', 'Ireland' ] }
In [ ]: