Objection! Let's play with primitives in JavaScript
Tags: javascript, beginners, tutorial
Published: 2019-08-02 14:53:22

---
title: Objection! Let's play with primitives in JavaScript
published: true
description: If a string is a primitive, and primitives don't have methods, how come you can call `.toUpperCase()` on one? 
cover_image: https://i.imgur.com/GRzUwQ1.png
tags: javascript, beginners, tutorial
---

I like to spend lazy weekends eating my body weight in Pringles, playing videogames and also really digging into some of the fundamentals of programming languages to get an appreciation for what's going on. I've been fascinated by methods and primitives in JavaScript lately, spurred on as I look to branch out a deeper understanding of standard data types in both object-oriented and functional patterns. 

While you certainly don't need to worry about a lot of this - it's really something the language largely abstracts away from you behind its individual implementation - it's nice to get a sense of what's going on. 

I'm going to be using JavaScript for most of this, but also with little cameos from Ruby and Elixir, though you certainly don't need to know either of those languages.

Let's play with some JavaScript: 

```javascript
const foo = 'foo'
typeof foo
// 'string'
```

Consider the humble `string`, a proper salt of the earth, workhorse of data type. Strings are model citizens. They work hard all day and don't ask questions, and as long as they've got enough cash left over to take the family on a couple of holidays a year they're pretty contented. 

Over on the fields of JavaScript, a `string` is one of its six primitives, which are kind of like the language's Infinity Stones - `string`, `number`, `boolean`, `undefined`, `null` and `symbol`. Primitives in JavaScript are immutable, although can be replaced by other primitives with assignment. Primitives are lightweight, like the delicious [Total 0%](https://uk.fage/yoghurts/fage-total) of data types, and don't have methods or properties - or the extra processing needs that come with them. 

Wait a second, woah woah woah *thank you very much*, how come you can do *this* then? 

```javascript
foo.toUpperCase() // "FOO"
foo.length // 3
```

Well, with the exception of `undefined` and `null`, each primitive also has a complementary [primitive wrapper object](https://developer.mozilla.org/en-US/docs/Glossary/Primitive#Primitive_wrapper_objects_in_JavaScript) that, perhaps unsurprisingly, wraps around it - so that's`String`, `Number`, `Boolean` and `Symbol`. 

When you're as smart as Kyle Simpson (❤️) you can [actually dig deep into what's going on under the hood](https://github.com/getify/You-Dont-Know-JS/blob/master/types%20&%20grammar/ch3.md), but essentially the `String` object (which still has its own constructor) will create an object - so *not* a primitive - around  a given `string` primitive, which is still accessible with the `valueOf` method. This, I believe, is also loosely analogous to the implementation of primitives in Java, but I'm certainly no expert there: the most I know about Java is the [FizzBuzz Enterprise Edition](https://github.com/EnterpriseQualityCoding/FizzBuzzEnterpriseEdition). 

```javascript
const bar = new String("bar")
typeof bar // 'object'
typeof bar.valueOf() // 'string'
bar.valueOf() === "bar" // true
bar === "bar" // false
```

Now, JavaScript will also handle this wrapping (also commonly called *boxing* or *autoboxing*) automatically when you attempt to access a method or property on a primitive, and then immediately following its evaluation it will automatically fling this new, temporary, single-use object off to the garbage collector. 

```javascript
const hello = "Hello!" // variable bound to string primitive
hello.shout = hello.valueOf().toUpperCase().concat("!!!!!") // create a String wrapper object and add a shout method, which is evaluated immediately and is then sent to the garbage collector
// "HELLO!!!!!"
hello.shout // creates a NEW String wrapper object, where shout doesn't exist, so returns undefined 
```

Alas, poor `String`! I knew him. 

You should also never *ever* **EVER** (probably) use these constructors in real-life, as even though it might make sense that creating these objects manually - especially for repetitive loops and the like - would be more efficient, the **reverse** is actually true. Implementations of JavaScript have worked out how to use the single-use wrapped objects way more effectively, which is a peculiar mishmash of timesaving and functionality that makes JavaScript such a hot and cold pleasure to deal with. 

```javascript
const { performance } = require('perf_hooks') // only needed for Node

function test_string(str, desc) {
  const t0 = performance.now()
  for (let i = 0; i < 10000000; i++) {
    str.length
    str.toLowerCase()
  }
  const t1 = performance.now()
  console.log(`${desc} took ${(t1 - t0) / 1000} seconds`)
}

test_string("Hello", "Wrapped string primitive");
test_string(new String("Hello"), "Instantiated String object");

// Wrapped string primitive took 0.011956994999200105 seconds
// Instantiated String object took 1.9173262799978257 seconds
```

Let's put JavaScript to one side and take a look at some other implementations. How's our little `foo` doing over in the ancient zen gardens of Ruby?

```ruby
foo = 'foo'
foo.class # String
foo.class.ancestors # [String, Comparable, Object, Kernel, BasicObject]
```

In Ruby, all data is represented by objects. This helps Ruby become an elegant object orientated language, and Ruby coders to easily unwind in the evening without having to decompress out these particular day terrors. "Ruby follows the influence of the Smalltalk language by giving methods and instance variables to all of its types", [says the language itself](https://www.ruby-lang.org/en/about/). 

By tracing the `String` object through its ancestors, we see that it - and every object in Ruby - inherits from `BasicObject`.

```ruby
magic_number = 3
magic_number.class.ancestors # [Integer, Numeric, Comparable, Object, Kernel, BasicObject]
```

So, all data types in Ruby are objects, and there's no wrapping/autoboxing going on behind the scenes, and even the JavaScript-style concept of primitives is non-existent. 

Because everything starts life as an object, this means you can reopen a class and add your own methods, which I am **legally required** to tell you can be pretty dangerous: you should always *always* **always** make sure you ensure your code is maintainable and sticking your snout into the standard library is a great way to cause a total meltdown in real life. With that said, it's still *pretty cool*. 

```ruby
class String
  def shout
    self.upcase << "!!!!!"
  end
end

"hello".shout
# "HELLO!!!!!"
```

Elsewhere, in more functional languages, the concepts of objects and classes is usually a distant memory - so accessing methods directly on your data types is a no-no. If we follow our venerable `foo` over to Elixir, we can see that instead of accessing properties and methods we're now passing our data types as parameters to functions in the `String` module. 

```elixir
foo = "foo"
is_bitstring(foo) # true
String.upcase(foo) # "FOO"
String.length(foo) # 3
```

This is just a brief stop in Elixir, but it's great to see that our `foo` is doing well, even though we can barely recognise them from those early JavaScript days - they just grow up so fast!