Working with Strings

String Review

We first saw strings in the section Variables and Functions. There we said that they represent text, and that when we want to write a literal string in our JavaScript code, it's wrapped in either single or double quotes: "I'm a string", 'And so am I'.

It's important to understand (and notice) what parts of your code are a string like this, and what is other parts of the code. For example, the variables created in these two lines are not the same:

a = '12'
b = 12

The first variable holds a string with two characters: a digit 1 followed by a digit 2. The second holds the number twelve (i.e. the next integer after eleven). Those two things look similar to us, but are treated differently in JavaScript calculations.

We can see this difference more clearly if we do some operations on the values:

c = a + '34'
d = b + 34

The first line creates the variable c holding the string '1234': when the + is applied to strings, it joins them together (or concatenates them). The second line creates d holding the number forty-six: + applied to numbers does addition.

Building Strings

We often need strings to pass along as arguments to functions, especially when doing CSS and SVG manipulations (with jQuery and Raphaël). For example, we used .append() in an example introducing the for loop:

$('#example1').append('<p>One more paragraph.</p>')

The argument to .append() is a string: the HTML code for the content to be inserted. If we want to have any control over these arguments (such as having them different each time around a for loop), we need to build them as the code runs, as opposed to just typing in the string literally.

If we have a variable holding a string (that's created somehow), we can join various pieces together to get the final string we want, something like this:

r = 'f'
g = '5'
b = '0'
newstyle = {
  'color': '#' + r + g + b
}

That would create an object that we could use as an argument for jQuery .css() with color value '#f50'. In our code so far, we haven't had string variable, we have had numbers. For example, in the next example on the for loop, we did something a little different:

for (n = 1; n <= 6; n += 1) {
  $('#example2').append('<p>Paragraph #' + n + '</p>')
}

Here, n is a number (like all loop counters), but we added it to strings.

When you try to add a string and a number together in JavaScript, the number is automatically converted to a string, and the strings are joined. That means that the three variables here will end up with the same value after the assignment:

a1 = 'abc' + 123
a2 = 'abc' + '123'
a3 = 'abc123'

So in our example code above, the argument to .append() was evaluated like this (for example, the third time around the loop when n was 3):

'<p>Paragraph #' + n + '</p>'
'<p>Paragraph #' + 3 + '</p>'
'<p>Paragraph #' + '3' + '</p>'
'<p>Paragraph #3</p>'

We can do the same thing with any number in JavaScript, so we can do some calculation before building the string. For example, it's often useful to be able to build attribute values for Raphaël.

The .scale() and .rotate() functions are convenient, but they won't let us animate either scaling or rotation. To do that. we need .animate() and the 'transform' attribute.

With 'transform', we can give strings like 'r30' to indicate a rotation of 30° or 's2' to indicate scaling of two times. If we want to create several rectangles with different rotations, we can do something like this:

for (count = 1; count <= 6; count += 1) {
  r = paper.rect(30, 30, 90, 90)
  animation_attrs = {
    'transform': 'r' + (count*15)
  }
  r.attr(animation_attrs)
}

This draws six squares, rotated by 15°, 30°, 45°, 60°, 75°, and 90°. The result is this:

Result of transformed shapes
Result of transformed shapes

For a complex example, we can recreate part of the image from the last section and animate it into existence while we're at it:

paper = Raphael('container2', 140, 140)
rect_attrs = {
  'fill': '#292',
  'stroke-width': '1.5'
}
for (count = 0; count <= 11; count += 1) {
  r = paper.rect(50, 50, 40, 40)
  r.attr(rect_attrs)
  angle = count*3
  scale = 3 - count*0.25
  anim_attrs = {
    'transform': 'r' + angle + 's' + scale
  }
  r.animate(anim_attrs, 2000)
}

Instead of using .attr(), this uses .animate() to rotate and scale the squares as they are created. Have a look at the page with both of these examples on it to see the animation.

Strings as Objects

Strings we have been using in JavaScript have the fundamental job of holding characters. They also behave as objects: they hold variables (including functions) that do useful things wit the contents of the string.

For example, every string contains a function .toLowerCase() that gives back a copy of itself converted to entirely lowercase:

greeting = 'Hello World!'
lower_greeting = greeting.toLowerCase()

After this code, the variable greeting contains 'Hello World!' and lower_greeting contains 'hello world!'. The original string didn't get changed, but the function returned a copy of itself with uppercase letters converted to lowercase.

Strings also contain a .charAt() function that can be used to extract individual characters from a string (counting from zero). It is used like this:

letters = 'abcdefg'
third = letters.charAt(2)

After this code, the variable third will contain the character 'c': 'a' is character 0 in that string, 'b' is character 1, 'c' is character 2.

We can do something a little more interesting: in Colours in CSS, we first saw the 0 to f scale for colour components. There are 16 possible values there, which we'll think of as 0 to 15.

If we create the string '0123456789abcdef', then it has characters 0 to 15 that we can extract to create color codes #000 to #f00 like this:

color_values = '0123456789abcdef'
paper = Raphael('container', 350, 120)
for (red = 0; red <= 15; red += 1) {
  r = paper.rect(red*20, red*5, 30, 30)
  rect_attrs = {
    'fill': '#' + color_values.charAt(red) + '00'
  }
  r.attr(rect_attrs)
}
Result of generated colours
Result of generated colours

You can also view the page with this example.

We will be able to do more interesting things with string methods once we can get strings from the user in the next section…