Variables in JavaScript and Grabbing Attributes

This will be a fairly dry post. Talking about variables isn’t very interesting, but understanding them is vital to progress in JavaScript.

What Is A Variable

How much could one banana cost?

A variable is a placeholder. You use them already, and all the time. When you remember that a banana is $10, and realise you can get 5 of them with $50, you have used a variable and also performed some algebra.

Types of Variable

Variables aren’t always numbers. Here are the types of variables you can encounter:

  • Integer: Whole numbers, like 0, 1, 2, 3000, -5, and so on.
  • Floating Point Numbers: an irritating label for numbers that aren’t integers. 1.3 is is a floating point number. Any number with a decimal or fractional part is a floating point number.
  • String: any single value that isn’t a number, typically words and sentences. Strings are always enclosed in quotes, like “Harry”, “This is a string”, and “3”. Notice that last one looks like a number, but because it is in quotes it is a string. You’ll find what difference that makes below.
  • Javascript Object: or simply, Object. This is a very versatile variable type, and you’ll use them whenever you use the getAttrs and setAttrs functions. Objects are always contained in curly brackets { }.
  • Array: An array is a list of other variables, enclosed in [ ]. You’ll learn how useful these are when Getting Loopy in JavaScript.

You can ignore most of that for now, the only types you regularly need to think about are strings and the two number types.

Naming Variables

You can’t use just any name for variables. Follow these rules:

  • Variable names cannot start with a number.
  • Variable names can include names, numbers, and underscores.
  • Variable names are case-sensitive: Strength, strength, and StReNgTh are three different variables.

There are differences between variable names and character sheet attribute names. An attribute name can start with a number, can include spaces and any other characters, and are not case-sensitive (Strength, strength, and StReNgTh are the same attribute).

It’s a good idea to use the same rules for attributes and variables, for consistency but also to avoid subtle problems. Here are the rules I’d recommend following for both attributes and variables:

  • Always use lower-case – no upper-case letters anywhere.
  • Never start a name with a number, always start with a letter.
  • Use underscores to separate words.

Only the middle rule here is required. The others are suggestions, but they will make your life easier. And also will make things easier for people reading your code (especially if using screen readers – something like WineBottle isn’t very readable, but the screen reader will be fine with wine_bottle).

Creating Variables

You’ll need to create variables in your code. The old method was to do it like this:

var my_variable = 13;
Code language: JavaScript (javascript)

This creates a variable named my_variable, and gives it a value of 13. The var at the start is telling your browser that whatever follows is the name of a variable.

But var has some issues (which will be described in a later post), so recently, the devs introduced two new ways to create variables:

let my_variable = 13; const my_constant = 10;
Code language: JavaScript (javascript)

let is basically the replacement for var. Whenever you see an older sheet worker that contains var, you can almost always replace let and use it unchanged.

const is different – it creates a constant, a special kind of variable whose value is fixed. If I later tried to change the my_constant variable, the code would crash. That might sound like a bad thing, but there are a lot of variables you don’t want to accidentally change, so setting them as consts can help you avoid errors.

There are other differences between var, let, and const, but that’s what you need to know to use them for now.

Initialising Variables

You can create an empty variable, like this:

let my_variable;
Code language: JavaScript (javascript)

That’s fine if you want to create a variable ahead of time and assign it later. But it’s usually better to give it a value, even a zero value, because javaScript will assign it a type. Like

let my_number = 0; let my_string = "";
Code language: JavaScript (javascript)

JavaScript always tries to assign a variable type (string, integer, etc), and if you declare it with a value like this, the correct data type will be created. This is a subtle concern, and since javascript happily switches variables between data type, it’s not often a problem. But it can avoid subtle errors.

Numbers vs Strings

You are working with a character sheet, and that sheet has a lot of attributes with values stored in it. By default, Roll20 stores every value as a string. So you might think you have a strength score of 10, but that score is often actually “10”.

Note: if the value is stored in a type=”number” input, it might be stored as a number. But it’s best to assume everything is a string, for safety reasons. Plus, not all attributes are stored in number inputs.

That might seem like a distinction without a meaning, but you can’t perform arithmetic with strings. Let’s say you try to do this:

let my_sum = "10" + "7";
Code language: JavaScript (javascript)

You might expect to get the answer 17, but you’ll actually get 107.

When working with strings, the “add” operation joins the strings (in programming terminology, it concatenates them). The two strings are simply slammed together, with no arithmetic performed.

Wouldn’t it be handy to convert that string to a number? Handily you can do that. That’s where the parseInt and parseFloat functions come in.

let my_stat = "10"; let my_number = parseInt(my_stat);
Code language: JavaScript (javascript)

parseInt converts something into an integer, and parseFloat converts into a floating point number.

If you are creating character stats, you probably want integers, but if calculating things like cost, encumbrance, or anything that can have a value less than 1, you’ll want floating point numbers.

parseInt and parseFloat arent the only way to coerce variables into numbers. there is also the Number function (and its shorthand + operator). I’ll leave that as an exercise for the reader – this series is using the same methods for consistency, so will always use parseInt and parseFloat.

JavaScript Logic and Handling Errors when Creating Variables

One error that can crop up very often is trying to create number variables that aren’t meant to be numbers. Let’s say you do this:

let my_word = "a word"; let my_number = parseInt(my_word);
Code language: JavaScript (javascript)

Here, parseInt will try to convert my_word into a number, but it can’t because there is no number there. The error will cause your worker to fail completely.

Here’s another problem that can easily occur:

let empty_variable = ""; let my_number = parseInt(empty_variable);
Code language: JavaScript (javascript)

Many attributes on a character sheet have a default value of “”, or have no value at all – both parseInt and parseFloat will error out, and the sheet worker will crash.

You can avoid these errors by supplying a default value:

let my_word = "a word"; let my_number = parseInt(my_word) || 0; my_word = "a word"; let my_number = parseInt(my_word) || 0;
Code language: JavaScript (javascript)

The || 0 part simply means “if an error is created, use 0 instead”.

We’ll talk more about that later, but that’s the essence here. You are supplying a default value after the ||. Sometimes you’ll want to supply a different value, like || 1, but || 0 is a good value to use generally.

Concatenating Things

You don’t usually need a parseString function, because everything is treated like a string unless it’s set up as something else. Just use the + to join them together:

let my_string = 10 + " " + "things";
Code language: JavaScript (javascript)

That will produce “10 things”. You might need to add spaces or other characters like commas and periods.

GetAttrs and the Values Object

This is where things tie directly back into Roll20. One very important thing to internalise: sheet workers are completely separate from a character sheet and have no connection to the attributes on that sheet. If you want to use an attribute, you have to tell the sheet worker which attributes you want to work with.

When you create your sheet worker, you have a line like this:

getAttrs(['dexterity', 'agility'], function(values) {
Code language: JavaScript (javascript)

That can also be written like this. These lines are identical:

getAttrs(['dexterity', 'agility'], values => {
Code language: PHP (php)

This is the collection phase. With this line, you are telling the browser to scan the character sheet, look for the dexterity and agility attributes, and store them in an object variable called values.

That will look internally like this:

let values = { dexterity: "17", agility: "13" }
Code language: JavaScript (javascript)

Here, dexterity and agility are keys, and 17 and 13 are values. You can get a value out of an object by using its key like this:

let dex = parseInt(values.dexterity) || 0;
Code language: JavaScript (javascript)

Here, I have created a variable called dex, retrieved its value from the values object, and converted it into an integer at the same time. Now dex has a value of 17, and I can perform arithmetic with it.

You’ll likely do this a lot. Probably every sheet worker will start with a few lines like this.

Objects are very versatile, and we’ll be exploring them in more detail later, but for now, all you need to know is that getAttrs creates an object, stores the attribute names and values inside it, and you can extract them using the object.key syntax (e.g. values.dexterity). And that’s it on Objects for now.

Handy Functions

Since you’ll be doing that a lot, it would be handy to reduce the typing. Here’s one way to do that.

Put these two lines at the start of your script block:

<script type="text/worker"> const int = (score, fallback = 0) => parseInt(score) || fallback; const float = (score, fallback = 0) => parseFloat(score) || fallback; </script>
Code language: JavaScript (javascript)

This creates the int and float functions, which you can use in any sheet workers to save typing. The lines below are equivalent, but the second is simpler to type. You’ll agree once you have created a few dozen sheet workers, each of which has multiple variables…

let strength = parseInt(values.strength) || 0; let strength = int(values.strength);
Code language: JavaScript (javascript)

I’ll provide a few handy time-saving functions here and there. If you need a number with decimal parts, use float(), otherwise use int().

Series Navigation<< Using Sheet Workers instead of AutoCalcsBack to School – Arithmetic in Sheet Workers >>

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.