Most developers would say that a dynamic language (like JS) does not have types.

An ECMAScript language type corresponds to values that are directly manipulated by an ECMAScript programmer using the ECMAScript language. The ECMAScript language types are Undefined, Null, Boolean, String, Number, and Object.

JavaScript defines seven built-in types:

  • null
  • undefined
  •  boolean
  • number
  • string
  • object
  • symbol — added in ES6!

Note: All of these types except object are called primitive.

The typeof operator inspects the type of the given value, and always returns one of seven string values — surprisingly, there’s not an exact 1-to-1 match with the seven built-in types we just listed.

Capture.PNG

As you may have noticed, I excluded null from the above listing. It’s special — special in the sense that it’s buggy when combined with the typeof operator:

typeof null === "object"; // true

If you want to test for a null value using its type, you need a compound condition:

var a = null;
(!a && typeof a === "object"); // true

It’s easy to think that function would be a top-level built-in type in JS, especially given this behavior of the typeof operator. However, if you read the spec, you’ll see it’s actually a “subtype” of object. Specifically, a function is referred to as a callable object — an object that has an internal Call property that allows it to be invoked.

the fact that functions are actually objects is quite useful. Most importantly, they can have properties. For example:

function a(b,c) {
/* .. */
}

The function object has a `length` property set to the number of formal parameters it is declared with.

a.length;    // 2

Since you declared the function with two formal named parameters (`b` and `c`), the “length of the function” is `2`.

What about arrays? They’re native to JS, so are they a special type?

typeof [1,2,3] === "object"; // true

Nope, just objects. It’s most appropriate to think of them also as a “subtype” of object, in this case with the additional characteristics of being numerically indexed (as opposed to just being string-keyed like plain objects) and maintaining an automatically updated .length property.

In JavaScript, variables don’t have types — values have types. Variables can hold any value, at any time.

Another way to think about JS types is that JS doesn’t have type enforcement, in that the engine doesn’t insist that a variable always holds values of the same initial type that it starts out with. A variable can, in one assignment statement, hold a string and in the next hold a number, and so on.

var a = 42;
typeof a; // "number"

a = true;
typeof a; // "boolean"

undefined vs undeclared

Variables that have no value currently, actually have the undefined value. Calling typeof against such variables will return undefined.

var a;
typeof a; // "undefined"

var b = 42;
var c;
b = c;

typeof b; // "undefined"
typeof c; // "undefined"

It’s tempting for most developers to think of the word undefined and think of it as a synonym for undeclared. However, in JS, these two concepts are quite different.

An undefined variable is one that has been declared in the accessible scope, but *at the moment* has no other value in it. By contrast, an undeclared variable is one that has not been formally declared in the accessible scope.

var a;
a; // undefined
b; // ReferenceError: b is not defined

Values

Arrays: as compared to other type-enforced languages, JavaScript arrays are just containers for any type of value, from string to number to object to even another array (which is how you get multidimensional arrays).

var a = [ 1, "2", [3] ];
a.length;       // 3
a[0] === 1;     // true
a[2][0] === 3;  // true

You don’t need to pre-size your array, you can just declare them and add values as you see fit:

var a = [];
a.length;   // 0
a[0] = 1;
a[1] = "2";
a[2] = [ 3 ];

a.length;   // 3

Be careful about creating a sparse array (leaving or creating empty/missing slots):

var a = [ ];

a[0] = 1;
// no `a[1]` slot set here
a[2] = [ 3 ];

a[1]; // undefined
a.length; // 3

arrays are numerically indexed (as you’d expect), but the tricky thing is that they also are objects that can have string keys/properties added to them (but which don’t count toward the length of the array)

var a = [ ];

a[0] = 1;
a["foobar"] = 2;

a.length;    // 1
a["foobar"]; // 2
a.foobar;    // 2

However, a gotcha to be aware of is that if a string value intended as a key can be coerced to a standard base-10 number, then it is assumed that you wanted to use it as a number index rather than as a string key!

var a = [ ];
a["13"] = 42;
a.length; // 14

Generally, it’s not a great idea to add string keys/properties to an array. Use an object for holding values in keys/properties, and save arrays for strictly numerically indexed values.


Strings

It’s a very common belief that string is essentially just array of characters. While the implementation under the covers may or may not use an array, it’s important to realize that JavaScript strings are really not the same as an array of characters. The similarity is mostly just skin-deep.

var a = "foo";
var b = a;
a.length; // 3
b.length; // 3

a.indexOf( "o" ); // 1
b.indexOf( "o" ); // 1

var c = a.concat( "bar" ); // "foobar"
var d = b.concat( ["b","a","r"] ); // ["f","o","o","b","a","r"]

a === c; // false
b === d; // false

a; // "foo"

JavaScript strings are immutable, while arrays are quite mutable.

c = a.toUpperCase();
a === c; // false
a;       // "foo"
c;       // "FOO"

b.push( "!" );
b;       // ["f","O","o","!"]

Also, many of the array methods that could be helpful when dealing with strings are not actually available for them, but we can borrow non-mutation array methods against our string:

a.join; // undefined
a.map;  // undefined

var c = Array.prototype.join.call( a, "-" );
var d = Array.prototype.map.call( a, function(v){
 return v.toUpperCase() + ".";
} ).join( "" );

c; // "f-o-o"
d; // "F.O.O."

Let’s take another example: reversing a string (incidentally, a common JavaScript interview trivia question!). arrays have a reverse() in-place mutator method, but strings do not

a.reverse; // undefined

b.reverse(); // ["!","o","O","f"]
b; // ["!","o","O","f

Unfortunately, this “borrowing” doesn’t work with array mutators, because strings are immutable and thus can’t be modified in place

Array.prototype.reverse.call( a );
// still returns a String object wrapper (see Chapter 3)
// for "foo" 😦

Another workaround (aka hack) is to convert the `string` into an `array`, perform the desired operation, then convert it back to a `string`.

var c = a
 // split `a` into an array of characters
 .split( "" )
 // reverse the array of characters
 .reverse()
 // join the array of characters back to a string
 .join( "" );

c; // "oof"

Numbers

JavaScript has just one numeric type: number. This type includes both integer values and fractional decimal numbers. I say “integer” in quotes because it’s long been a criticism of JS that there are not true integers, as there are in other languages. That may change at some point in the future, but for now, we just have numbers for everything.

So, in JS, an integer is just a value that has no fractional decimal value. That is, 42.0 is as much an integer as 42.

Number literals are expressed in JavaScript generally as base-10 decimal literals. For example:

var a = 42;
var b = 42.3;

The leading portion of a decimal value, if `0`, is optional

var a = 0.42;
var b = .42;

Very large or very small `number`s will by default be outputted in exponent form, the same as the output of the `toExponential()` method, like:

var a = 5E10;
a; // 50000000000
a.toExponential(); // "5e+10"

var b = a * a;
b; // 2.5e+21

var c = 1 / a;
c; // 2e-11

the toFixed(..) method allows you to specify how many fractional decimal places you’d like the value to be represented with:

var a = 42.59;

a.toFixed( 0 ); // "43"
a.toFixed( 1 ); // "42.6"
a.toFixed( 2 ); // "42.59"
a.toFixed( 3 ); // "42.590"
a.toFixed( 4 ); // "42.5900"

Notice that the output is actually a string representation of the number and that the value is 0-padded on the right-hand side if you ask for more decimals than the value holds.

 

 

Advertisements