Values, Types, Operators and Type Coercion

CSCI-UA.0480-008

All Types All the Time

In this set of slides, we'll take a look at:

  1. JavaScript's types
  2. Numbers and numeric operators
  3. Strings and string operators
  4. Booleans and logical and comparison operators
  5. undefined and null

Some Definitions

  • value - data
  • type - a category or classification of values
  • operator - a language construct that allows the manipulation or combination of a value or values to yield another value
  • operand - a value that an operator works on; the subject of an operator
  • unary operator - an operator that only has one operand
  • binary operator - an operator that has two operands
  • prefix operator - an operator that goes before (to the left) of its operand(s)
  • infix operator - an operator that goes between its operands

Let's Start off with Comments

Yup Similar to comments in C or Java…


// a comment

/*
a multiline
comment
*/

Values

  • What's a value?
    • values are just data
    • they're pieces of information.
  • Some examples of literal values in JavaScript:

317.0
"oh, hello"
true
{'name': 'Joe'}
function() {console.log("in here!")}
undefined

Types of Values

Based on the values in the previous slides, guess what types JavaScript supports?

  1. number
  2. string
  3. boolean
  4. object
  5. function
  6. undefined


Actually… these are the types that the typeof operator returns… the specs specify something different (we'll see in a minute)

typeof

Before we delve into these data types, let's check out a unary, prefix operator:


typeof

As you might expect, typeof returns a string that represents the operand's type:


> typeof 317.0
'number'

We'll be using typeof extensively for the next few slides….

BTW… Types According to the Specification

The ECMAScript specification lists some types, but they're not the ones that typeof returns (of course!)

  • Undefined
  • Null
  • Boolean
  • String
  • Number
  • Object
  • Symbol (ES6)


Wait… what? Then what's typeof doing?

What Does typeof Do?

Weelllll…. it behaves exactly according to what's specified:

  • typeof undefined → "undefined"
  • typeof null → "object" ???
  • typeof false → "boolean"
  • typeof 5 → "number"
  • typeof 'foo' → "string"
  • typeof console.log → "function"
  • typeof [1, 2, 3, 4] → "object" ???


Seems like null is an object (!? … a mistake?). Array is also listed as a generic object. ¯\(ツ)/¯.

TELL ME ABOUT THE TYPES!

Seriously, stop messing around. Types Really:


Functions are actually just objects, but typeof gives back function when its operand is a function. Arrays are objects too, so typeof returns object for an Array.

Primitives vs Objects

Hey… those two terms should sound familiar…

  • booleans, numbers, strings, null and undefined are primitive values:
    • they're immutable
    • they're compared by value
    • note that wrapper objects for primitives do exist (we'll see this later)
  • objects, on the other hand:
    • are compared by reference
    
    console.log({} === {}) // false!
    const foo = {};
    const bar = foo;
    console.log(foo === bar); // true (because "aliasing")
    
    • are mutable (by default, though they can be made immutable-ish)

Numbers

  • unsurpsingly, numbers are just numbers
    • all numbers in Javascript are 64bit (8 bytes) floating point numbers
    • JavaScript does not distinguish between ints, floats, longs, doubles, etc.
  • numbers represent…
    • positive and negative whole numbers: 23, 42, -10
    • floating point numbers (with a dot): 2.3, 4.2
  • number literals consist of digits, an optional decimal point, and an optional exponent

123 // an integer - just digits
12.3 // a floating point number - decimal point
12e3 // (12 times 10 to the 3rd) exponent

More About Numbers

  • So how many values can 64 bits hold? (Um… a lot?) →
  • 2 to the power of 64! About 18 with 18 0's after it. However, this doesn't exactly indicate what numbers can be stored. Why?
  • This just means that number of possible values. This has to include negative numbers, decimals, etc…
    • 52 bits for the value (er really 53 … because of the sign)
    • used to represent both integers and real numbers
    • 11 bits for the exponent (for placing the decimal point)
    • 1 bit for the sign

And Why Does That Matter?

  • integers are considered to be reliable up to about 15~16 digits →

> Math.pow(2,53)
> 9007199254740992
9007199254740992
> 9007199254740993
9007199254740992

Floating Point Operations May Yield Unexpected Results!

  • sooo… you may have to be careful when comparing them!
  • for example, if checking two floating point numbers for equality
    • perhaps take the absolute value of the difference of the values and determine if that's below some threshold
    • if it is, then the floating point numbers are equal
  • this threshold is the machine epsilon
    • The smallest representable positive number such that 1.0 + eps != 1.0
    • 0.1 + 0.2 === 0.3 // false!?
    • Math.abs((0.1 + 0.2) - 0.3) < 0.0000000000000004 // true!

Operators

  • Using operators with values as operands yields values!
  • We've learned one operator so far… what was it?
  • We're familiar with some numeric operators (just because we've seen them in other languages, and - you know, math) … what are they?

Numeric Operators

A quick list of binary, infix arithmetic operators (they take two operands, one on each side of the operator):

  • + - addition
  • - - subtraction
  • * - multiplication
  • / - division
  • % - modulo (remainder)
  • ** for exponentiation works too if your js engine supports ES7
  • check out these operations in the node REPL

Numeric Operators, Precedence

What order would I evaluate this in? What is the resulting value?


4 + 1 * 5
  • remember PEMDAS? (modulo is the same precedence as multiplication)
  • multiplication first
  • then addition
  • result is 9
  • you can find more about operator precedence here

Use Parentheses Liberally

  • parentheses allow grouping
  • grouping operation has highest precedence (always goes first)

// force addition first
(4 + 1) * 5

More Number Operators

A couple more operators - these are prefix, unary operators that yield numbers:

  • + - convert to positive number
  • - - convert to negative number
  • let's try them out

+12
-12
-"12"
+"12"
-true

Note that they work on non-number types as well! These operators can be used to convert strings to numbers.

Bitwise Operators

What do you think the following operators do?


2 & 3 // 10 & 11 = 10 = 2
7 ^ 3 // 111 ^ 011 = 100 = 4
  • bitwise AND - a & b - returns a one in each bit position for which the corresponding bits of both operands are ones
  • bitwise OR - a | b - returns a one in each bit position for which the corresponding bits of either or both operands are ones
  • bitwise XOR - a ^ b returns a one in each bit position for which the corresponding bits of either but not both operands are ones
  • bitwise NOT - ~ a - inverts the bits of its operand


Note… bitwise operators work in 32 bits (even though numbers are stored in 64)

let's try these

More Bitwise Operators

What do you think the following operators do?


2 << 3 // 10 << 11 = 10000 = 16
  • left shift - a << b - shifts a in binary representation b (< 32) bits to the left, shifting in zeros from the right.
  • sign-propagating right shift - a >> b - shifts a in binary representation b (< 32) bits to the right, discarding bits shifted off.
  • zero-fill right shift a >>> b - shifts a in binary representation b (< 32) bits to the right, discarding bits shifted off, and shifting in zeros from the left.

Bitwise operators treat their operands as a sequence of 32 bits!

Let's Try a Few

What are the results of the following expressions?


8 | 2 // 1000 | 0010
8 >> 2 // 1000 >> 0010


10
2

(More details on MDN)

Some Special Numbers…

Try the following operations…


0/0
9e300 * 25874481
  • JavaScript has some special number values:
    • NaN (Not a Number) - this results from any numeric operation that doesn't give back a meaningful result…
    • Infinity, -Infintity - positive and negative infinities
  • Note that these special values are actually numbers! (really!)
    • that is, both NaN and Positive/Negative Infinity are of type Number!
      
      typeof NaN      // --> number (what??? ok)
      typeof Infinity // --> number
      

More About NaN

Again, NaN stands for not a number

  • NaN is toxic
  • using it in any other numeric operations always results in NaN
    • NaN + 1NaN
  • the only way to check if a value is NaN is by using the built-in function isNaN(val)
  • oddly, NaN === NaN is false (!? … as specified by IEEE)

More About Infinity

So, there's Infinity and -Infinity

  • Infinity + 1 or Infinity + Infinity→ is still Infinity
  • Infinity represents all values greater than 1.79769313486231570e+308
  • dividing by 0 yields infinity
  • equality operators and the global function isFinite can be used to determine if a value is Infinity

Special Numeric Values and Bitwise Operators

For bitwise operators… Nan, Infinity, and -Infinity are all converted to 0


NaN | 2 // evaluates to 2
Infinity & 10 // evaluates to 0

Why? Because the specs say so

Also… there is definitely a binary representation for these special numbers (Nan, Infinity, and -Infinity)… the closest I came to determining it was here

Strings

A string is an ordered sequence of Unicode characters (what's Unicode? →). You can tell that a value is a string if it is surrounded by single or double quotes:


'I am a string'
"I'm a string too!"

Quoted text is a string!

Strings Continued

A string can be composed of any characters: numbers, letters, punctuation, spaces, etc.

The following is a string with nothing in it… or an empty string:


""

Escape Characters

If there is a backslash in a string (\), that means:

  • the next character has a special meaning
  • the initial backslash will not be printed out


For example, \n is a newline and \t is a tab


"\n"
"\t" 

How would we put a double quote in a double quoted string?


"\""

And what about an actual backslash?


"\\"

Unicode Escape Sequence

You can specify characters by using their unicode code point!

  • start with \u
  • follow it with a a hexadecimal number representing a unicode code point


How does that work? Welll…. →

  • console.log('\u0041') - 65 - uppercase A
  • as an aside,
    • JavaScript stores strings internally as UTF-16, but the code points for emoji are outside of what UTF-16 can represent
    • consequently, to represent those higher code points, 2 consecutive UTF-16 characters can be used
    • for example, '\uD83D\uDE28' is a fearful face 😨 (AKA the face I make when I see a hex number or read the word, unicode)


String Operators

A few string operators:

  • string concatenation, or +, is an operator that takes two strings and joins them:
    
    "hello " + "there"
    
  • indexing, or []… can be used to retrieve the character at an index, such as 'emoji'[3] (or use charAt)
  • comparison operators, you can use <, <=, etc. … unicode code points are compared 'B' > 'A' // true

Template Literals (ES6)

If you want multiline strings or string interpolation, use template literal syntax:

  • use backticks to delimit your template literal (instead of quotes)
  • use ${variableName} to output the value of a variable in a string

const s1 = `such
lines
wow`;

const food1 = 'bacon';
const food2 = 'pancakes';
const s2 = `Makin' ${food2}, makin' ${food1} ${food2}!`;

console.log(s1)
console.log(s2);

Booleans

A boolean is a data type that has two possible values: true or false.

As one would expect, the literals for these values are (all lowercase):


true
false

Inherent Truthiness

When non-boolean types are converted to booleans, the followings rules are used

  • 0, NaN, empty string (""), and undefined/null are false
  • other values are true-ish


Let's test this out…


// outputs "in here"
if("this string says false, but...!?") {
	console.log("in here!");
}

// no output
var myString = "";

if(myString) {
	console.log("you shouldn't see me!");
}

Logical Operators

Boolean values can be combined and manipulated using logical operators. What are some logical operators, and what do they do?

  • and - && - returns true if and only if both operands are true, otherwise, returns false
  • or - || - returns false if and only if both operands are false, otherwise, returns true
  • not - ! - returns the opposite boolean value of its single operand to the right

Logical Operators Continued, Precedence

What do the following boolean expressions return?


false && true
false || true
false || !true

false
true
false


The operator precedence for logical operators is not, and, and or.

And and Or With Non Boolean Values

Some details about && and ||:

  • if operands are not actually boolean, convert the value on the left side to a boolean
    • ||
      • will return the left operand's value if it's true
      • otherwise, return the value on the right
      • can be used as a way to fall back to a default value potentially_falsey || default_value
    • &&
      • will return the left operand's value if it's false
      • otherwise, return the value on the right
  • also… short-circuit evaluation applies

And and Or Continued

Based on the previous slide, what are the values produced by the following expressions?


5 - 5 || 2
5 - 5 && 2
"hello" || "goodbye"
"hello" &&  "goodbye"

2
0
hello
goodbye

This syntax is actually sometimes used to assign a default value if a value doesn't exist:


// we haven't seen objects yet, but you get the idea
const obj = {prop1: "a value"}; 
const val1 = obj.prop1 || "default value"
const val2 = obj.prop2 || "default value"

Ternary Operator

What will this code return?


true ? "ok" : "not ok!"
  • "ok"
  • format is test (boolean expression) ? value to return if true : value to return if false


The ternary operator works like an if/else statement, but it's one line and it evaluates to a value:


// ternary followed by equivalent if/else
let x = 5 > 2 ? 'yes' : 'no';

let x;
if(5 > 2) {
    x = 'yes';
} else {
    x = 'no';
}

Comparison Operators

Booleans can be produced from comparison operators. Without knowing anything about JavaScript, what do you think are some available comparison operators?

  • <, >, <=, >= - greater than, less than, etc.
  • === - equals, checks both type and value
  • !== - not equals, checks both type and value
  • == - equals, coerces operands to appropriate types
  • != - not equals, coerces operands

Comparison Operators Continued

Comparison Operators are binary , infix operators that can be used to compare two operands:

  • numbers are obvious: 5 > 2
  • strings are compared from left to right (by character code): "aardvark" > "bison" (more or less, alphabetic) →
  • NaN is the only value not equal to itself →
  • You'll probably always want to use ===

undefined and null

See the section on undefined and null in our book

  • undefined means no value
    • think of a function that doesn't return a value
    • or the value of a declared variable that hasn't been given a value yet
    • or a missing argument to a function
  • null means "no object"… it's a value that can be assigned to a variable to represent "no object" →
  • the subtle differences between undefined and null are an accident of language design!
    • you'll typically find undefined when something wasn't initialized
    • you'll find null if an object is explicitly set to null

Type Coercion

What values would you expect from the following lines of code?


5 + 5
"5" + 5
"five" + 5
5 == "5"
5 === "5"
5 * undefined
5 * null

10
'55'
'five5'
true
false
NaN
0


How do we know? We can read the ECMAScript specifications!

Type Coercion Continued

  • JavaScript is a dynamic and weakly typed language.
  • It often goes out of its way to make sure that operators and functions work, regardless of what types are given as operands or arguments.
  • It will try to coerce types into other types to make operators and functions work.

Type Coercion With Numeric Operators

  • for addition:
    • when one operand is a string and the other is not, the other operand is converted into a string, and the two strings are concatenated
    • for all other cases, the operands are converted to numbers
      • true → 1
      • false → 0
      • null → 0
      • undefined is still undefined, and result gives back NaN
  • for other numeric operators, such as subtraction:
    • will usually try to convert to number
    • if something cannot be converted easily (like the string, "hello"), the result is NaN

Type Coercion With Equality Operators

  • JavaScript will do its best to convert types so that they can be checked for equality - these all return true
    • "10" == 10
    • 0 == false
    • "" == false
  • this is Usually an unwanted behavior; to avoid this, use: === and !==
    • these operators check type and value
    • use these three-character comparison operators to prevent unexpected type conversions


If you want to see the details for every possible operand combination for double equals, check out mdn's table 👀

Use === Instead of ==

(mostly)

Relational / Ordering Operators

For relational / ordering operators like >, <, etc.

  1. convert objects to a primitive: booleans, numbers, strings, null, and undefined
  2. if strings, compare lexicographically
  3. otherwise convert both to numbers
  4. NaN is compared as unordered with everything (which is why NaN === NaN is false)

Back to Unary Operators

What the what????


+-12 
-+12
+"hello"

These expressions evaluate to…


-12
-12
NaN

From the docs on mdn

  • unary + … will try to convert its operand to a number (if it can't be converted to a number, then NaN)
  • unary - … will convert its operand to negative number


The order of operations is innermost prefix operator first (right to left).

Ugh All of That is Kind of Crazy

A quick summary of all of that automatic conversion business.

  • when adding values
    • if either of the values is a string, coerce the other to perform string concatenation
    • otherwise convert both sides to numbers (if they aren't already) and perform addition
  • when comparing values with <
    • try to convert both sides to numbers first, so that comparison can be easily performed
    • if either operand is NaN, the result is False
  • when it doubt, check the some online resources, like mdn (or, of course SO it)

Handling Automatic Type Conversion

How do we get out of this mess?

…Without having to remember a series of obscure rules

  1. one way is to use triple equals - === (we've gone over this before!)
  2. another way is to just explicitly cast your operand(s) to minimize surprises

Casting

We can use object contructors as functions to cast to a type:

  • use constructors (named after their corresponding type) as functions by dropping the keyword new to convert to that type
  • note that if you use new with your constructor (avoid!)…
    • primitive type is wrapped in an object (to be discussed later!)
    • when asked for a value, these objects usually yield the value of their primitive type

// do this (call constructor named after type as a function)
i = Number("2")
a = Boolean(false);
// not this (not a good idea to use new!)
b = new Boolean(false);
// because
console.log(typeof a); // --> boolean
console.log(typeof b); // --> object
// ... and 😒
Boolean(new Boolean(false)) // True!?

Casting Continued

Another option is to use some of the operators that we learned to coax JavaScript into doing a predictable automatic conversion for us:

  • convert to a boolean
    • use not twice (negate the not, but preserve the type conversion)
    • !!"hello"
  • convert to a number
    • use unary +
    • for example: +"5", +"hello"
    • use parseInt
  • convert to a string
    • just add an empty string to it
    • 5 + ""


For mind boggling detail, see You Don't Know JS on coercion.

Checking for undefined

Undefined (and also null) means the absence of a meaningful value.

How would you check if a value is undefined? The two ways to do this are: →

  • (preferred) if (myVar === undefined)
  • if (typeof myVar === 'undefined')
    • handles undeclared variables

Checking for NaN

Use the isNaN function to determine if a value is not a number.

(comparing NaN to itself always yields false)


NaN == NaN
NaN === NaN

// false
// false
// weird, eh?

Remember… NaN is not ordered with any value!. Use isNaN


isNaN(NaN)

Some Style

The previous material in this set of slides are about general best practices. Not adhering to them may:

  • result in your code yielding unexpected results
  • difficult to understand / non-standard code


The next few suggestions, however, are purely stylistic - just about how code is formatted:

poochie

Style Continued

  • use 1TBS, One True Brace Style: open curly brace on same line of code as last line preceding the current block of code / statement header (not on a new line)

if (some_boolean_expression) { // <-- curly brace here!
	// do stuff
}
  • use (lower) camel case to separate words in identifiers / variables names: myVerboseVariableName
  • remember to indent blocks of code!

Summary

  • automatic type conversion is tricky; sometimes it's helpful to check the specs, mdn, speaking javascript or even stackoverflow
  • you can get around automatic type conversion (if that's desirable) by casting
    • use object constructors as functions (Number, Boolean, etc.)
    • use operators like !!, +, + ""
  • to check for undefined: if(typeof myVar == 'undefined')
  • to check for NaN: isNan(myVar)

Order of Operations

All of those operators! What goes first again!? (Check out operators precedence here.)

A quick summary:

  • parentheses
  • unary operators like logical NOT, typeof and negative
  • the rest of lPEMDAS (number, string operators) - left to right if same precedence
  • bitwise shift operators
  • comparison operators - left to right
  • equality operators - left to right
  • remaining logical operators - and, or - left to right
  • other bitwise operators - bitwise and, bitwise or - left to right


And… a Quick Review on Types

Name 6 types (as given by typeof) that we know in JavaScript and a literal example of each.

  • number - 317
  • string - "yup, a string"
  • boolean - true
  • function - function f(x) {return x * 2}
  • object - {'classSection': '002'}
  • undefined - undefined (of course!)

Lastly, a Quick Review on Operators

We talked about a bunch of operators. The following are categories of operators, give examples of each →.

  • arithmetic: +  -  *  /  %
  • bitwise: &  |  ^   ~   <  >  >>
  • logical operators: &&  ||  !
  • comparison operators: ==  !=  ===  !==  >  <  >=  <=
  • miscellaneous:
    • unary + and - … convert to positive or negative number
    • typeof … obvs, returns string representation of type of operand
    • unary and postfix ++ and -- … increment and decrement