Chapter 1. JavaScript Objects

Creating Objects

In JavaScript, objects are king: Almost everything is an object or acts like an object. Understand objects and you will understand JavaScript. So let’s examine the creation of objects in JavaScript.

An object is just a container for a collection of named values (a.k.a. properties). Before we look at any JavaScript code, let’s first reason this out. Take myself, for example. Using plain language, we can express in a table, a “cody”:

cody

property:

property value:

living

true

age

33

gender

male

The word “cody” in the table above is just a label for the group of property names and corresponding values that make up exactly what a cody is. As you can see from the table, I am living, 33, and a male.

JavaScript, however, does not speak in tables. It speaks in objects, which are not unlike the parts contained in the “cody” table. Translating the above table into an actual JavaScript object would look like this:

Live Code

<!DOCTYPE html><html lang="en"><body><script>

// create the cody object...
      var cody = new Object();

// then fill the cody object with properties (using dot notation)
      cody.living = true;
cody.age = 33;
cody.gender = 'male';

console.log(cody); // logs Object {living = true, age = 33, gender = 'male'}

</script></body></html>

Keep this at the forefront of your mind: objects are really just containers for properties, each of which has a name and a value. This notion of a container of properties with named values (i.e., an object) is used by JavaScript as the building blocks for expressing values in JavaScript. The cody object is a value which I expressed as a JavaScript object by creating an object, giving the object a name, and then giving the object properties.

Up to this point, the cody object we are discussing has only static information. Since we are dealing with a programing language, we want to program our cody object to actually do something. Otherwise, all we really have is a database, akin to JSON. In order to bring the cody object to life, I need to add a property method. Property methods perform a function. To be precise, in JavaScript, methods are properties that contain a Function() object, whose intent is to operate on the object the function is contained within.

If I were to update the cody table with a getGender method, in plain English it would look like this:

cody

property:

property value:

living

true

age

33

gender

male

getGender

return the value of gender

Using JavaScript, the getGender method from the updated “cody” table above would look like this:

Live Code

<!DOCTYPE html><html lang="en"><body><script>

var cody = new Object();
cody.living = true;
cody.age = 33;
cody.gender = 'male';
cody.getGender = function(){return cody.gender;};

console.log(cody.getGender()); // logs 'male'

</script></body></html>

The getGender method, a property of the cody object, is used to return one of cody’s other property values: the value “male” stored in the gender property. What you must realize is that without methods, our object would not do much except store static properties.

The cody object we have discussed thus far is what is known as an Object() object. We created the cody object using a blank object that was provided to us by invoking the Object() constructor function. Think of constructor functions as a template or cookie cutter for producing pre-defined objects. In the case of the cody object, I used the Object() constructor function to produce an empty object which I named cody. Now since cody is an object constructed from the Object() constructor, we call cody an Object() object. What you really need to grok, beyond the creation of a simple Object() object like cody, is that the majority of values expressed in JavaScript are objects (primitive values like “foo”, 5, and true are the exception but have equivalent wrapper objects).

Consider that the cody object created from the Object() constructor function is not really different from, say, a string object created via the String() constructor function. To drive this fact home, examine and contrast the code below:

Live Code

<!DOCTYPE html><html lang="en"><body><script>

var myObject = new Object(); // produces an Object() object
myObject['0'] = 'f';
myObject['1'] = 'o';
myObject['2'] = 'o';

console.log(myObject); // logs Object { 0="f", 1="o", 2="o"}

var myString = new String('foo'); // produces a String() object

console.log(myString); // logs foo { 0="f", 1="o", 2="o"}

</script></body></html>

As it turns out, myObject and myString are both…objects! They both can have properties, inherit properties, and are produced from a constructor function. The myString variable containing the 'foo' string value seems to be as simple as it goes, but amazingly it’s got an object structure under its surface. If you examine both of the objects produced, you will see that they are identical objects in substance but not in type. More importantly, I hope you begin to see that JavaScript uses objects to express values.

Note

You might find it odd to see the string value 'foo' in the object form because typically a string is represented in JavaScript as a primitive value (e.g., var myString = 'foo';). I specifically used a string object value here to highlight that anything can be an object, including values that we might not typically think of as an object (i.e., string, number, boolean). Also, I think this helps explain why some say that everything in JavaScript can be an object.

JavaScript bakes the String() and Object() constructor functions into the language itself to make the creation of a String() object and Object() object trivial. But you, as a coder of the JavaScript language, can also create equally powerful constructor functions. Below, I demonstrate this by defining a non-native custom Person() constructor function, so that I can create people from it.

Live Code

<!DOCTYPE html><html lang="en"><body><script>

/* define Person constructor function in order to create custom 
Person() objects later */
var Person = function(living, age, gender) {
   this.living = living;
   this.age = age;
   this.gender = gender;
   this.getGender = function() {return this.gender;};
};

// instantiate a Person object and store it in the cody variable
var cody = 
      new Person(true, 33, 'male');

console.log(cody);

/* The String() constructor function below, having been defined by JavaScript, 
has the same pattern. Because the string constructor is native to JavaScript, 
all we have to do to get a string instance is instantiate it. But the pattern is 
the same whether we use native constructors like String() or user-defined 
constructors like Person(). */

// instantiate a String object stored in the myString variable
var myString = new String('foo');

console.log(myString);

</script></body></html>

The user-defined Person() constructor function can produce person objects, just as the native String() constructor function can produce string objects. The Person() constructor is no less capable, and is no more or less malleable, than the native String() constructor or any of the native constructors found in JavaScript.

Remember how the cody object we first looked at was produced from an Object(). It’s important to note that the Object() constructor function and the new Person() constructor shown in the last code example can give us identical outcomes. Both can produce an identical object with the same properties and property methods. Examine the two sections of code below, showing that codyA and codyB have the same object values, even though they are produced in different ways.

Live Code

<!DOCTYPE html><html lang="en"><body><script>

// create a codyA object using the Object() constructor

var codyA = new Object();
codyA.living = true;
codyA.age = 33;
codyA.gender = 'male';
codyA.getGender = function() {return codyA.gender;};

console.log(codyA); // logs Object {living=true, age=33, gender="male", ...}

/* The same cody object is created below, but instead of using the native 
Object() constructor to create a one-off cody, we first define our own Person()  
constructor that can create a cody object (and any other Person object we like) 
and then instantiate it with "new". */

var Person = function(living, age, gender) {
   this.living = living;
   this.age = age;
   this.gender = gender;
   this.getGender = function() {return this.gender;};
};

// logs Object {living=true, age=33, gender="male", ...}
var codyB = new Person(true, 33, 'male');

console.log(codyB);

</script></body></html>

The main difference between the codyA and codyB objects is not found in the object itself, but in the constructor functions used to produce the objects. The codyA object was produced using an instance of the Object() constructor. The Person() constructor constructed codyB but can also be used as a powerful, centrally defined object “factory” to be used for creating more Person() objects. Crafting your own constructors for producing custom objects also sets up prototypal inheritance for Person() instances.

Both solutions resulted in the same complex object being created. It’s these two patterns that are the most commonly used for constructing objects.

JavaScript is really just a language that is pre-packaged with a few native object constructors used to produce complex objects which express a very specific type of value (e.g., numbers, strings, functions, object, arrays, etc.), as well as the raw materials via Function() objects for crafting user-defined object constructors [e.g., Person()]. The end result—no matter the pattern for creating the object—is typically the creation of a complex object.

Understanding the creation, nature, and usage of objects and their primitive equivalents is the focus of the rest of this book.

JavaScript Constructors Construct and Return Object Instances

The role of a constructor function is to create multiple objects that share certain qualities and behaviors. Basically a constructor function is a cookie cutter for producing objects that have default properties and property methods.

If you said, “A constructor is nothing more than a function,” then I would reply, “You are correct—unless that function is invoked using the new keyword.” [e.g., new String('foo')]. When this happens, a function takes on a special role, and JavaScript treats the function as special by setting the value of this for the function to the new object that is being constructed. In addition to this special behavior, the function will return the newly created object (i.e., this) by default instead of a falsey value. The new object that is returned from the function is considered to be an instance of the constructor function that constructs it.

Consider the Person() constructor again, but this time read the comments in the code below carefully, as they highlight the effect of the new keyword.

Live Code

<!DOCTYPE html><html lang="en"><body><script>

/* Person is a constructor function. It was written with the intent of being used
with the new keyword. */

var Person = function Person(living, age, gender) {
   /* "this" below is the new object that is being created 
      (i.e., this = new Object();) */
   this.living = living;
   this.age = age;
   this.gender = gender;
   this.getGender = function() {return this.gender;};
   /* when the function is called with the new keyword "this" is returned 
   instead of undefined */
};

// instantiate a Person object named cody
var cody = new Person(true, 33, 'male');

// cody is an object and an instance of Person()
console.log(typeof cody); // logs object
console.log(cody); // logs the internal properties and values of cody
console.log(cody.constructor); // logs the Person() function

</script></body></html>

The above code leverages a user-defined constructor function [i.e., Person()] to create the cody object. This is no different from the Array() constructor creating an Array() object [e.g., new Array()]:

Live Code

<!DOCTYPE html><html lang="en"><body><script>

// instantiate an Array object named myArray
var myArray = new Array(); // myArray is an instance of Array

// myArray is an object and an instance of Array() constructor
console.log(typeof myArray); // logs object! What? Yes, arrays are type of object
console.log(myArray); // logs [ ]

console.log(myArray.constructor); // logs Array()

</script></body></html>

In JavaScript, most values (excluding primitive values) involve objects being created, or instantiated, from a constructor function. An object returned from a constructor is called an instance. Make sure you are comfortable with these semantics, as well as the pattern of leveraging constructors to construct objects.

The JavaScript Native/Built-In Object Constructors

The JavaScript language contains nine native (or built-in) object constructors. These objects are used by JavaScript to construct the language, and by “construct” I mean that these objects are used to express object values in JavaScript code, as well as orchestrate several features of the language. Thus, the native object constructors are multifaceted in that they produce objects, but are also leveraged in facilitating many of the language’s programming conventions. For example, functions are objects created from the Function() constructor, but are also used to create other objects when called as constructor functions using the new keyword.

Below, I list the nine native object constructors that come pre-packaged with JavaScript:

  • Number()

  • String()

  • Boolean()

  • Object()

  • Array()

  • Function()

  • Date()

  • RegExp()

  • Error()

JavaScript is mostly constructed from just these nine objects (as well as string, number, and boolean primitive values). Understanding these objects in detail is key to taking advantage of JavaScript’s unique programming power and language flexibility.

Notes

  • The Math object is the oddball here. It’s a static object, rather than a constructor function, meaning you can’t do this: var x = new Math(). But you can use it as if it has already been instantiated (e.g., Math.PI). Truly, Math is a just an object namespace set up by JavaScript to house math functions.

  • The native objects are sometimes referred to as “global objects” since they are the objects that JavaScript has made natively available for use. Do not confuse the term global object with the “head” global object that is the topmost level of the scope chain, for example, the window object in all web browsers.

  • The Number(), String(), and Boolean() constructors not only construct objects; they also provide a primitive value for a string, number and boolean, depending upon how the constructor is leveraged. If you called these constructors directly, then a complex object is returned. If you simply express a number, string, or boolean value in your code (primitive values like 5, “foo” and true), then the constructor will return a primitive value instead of a complex object value.

User-Defined/Non-Native Object Constructor Functions

As you saw with the Person() constructor, we can make our own constructor functions, from which we can produce not just one but multiple custom objects.

Below, I present the familiar Person() constructor function:

Live Code

<!DOCTYPE html><html lang="en"><body><script>

var Person = function(living, age, gender) {
    this.living = living;
    this.age = age;
    this.gender = gender;
    this.getGender = function() {return this.gender;};
};

var cody = new Person(true, 33, 'male');
console.log(cody); // logs Object {living=true, age=33, gender="male", ...}

var lisa = new Person(true, 34, 'female');
console.log(lisa); // logs Object {living=true, age=34, gender="female", ...}

</script></body></html>

As you can see, by passing unique parameters and invoking the Person() constructor function, you could easily create a vast number of unique people objects. This can be pretty handy when you need more than two or three objects that possess the same properties, but with different values. Come to think of it, this is exactly what JavaScript does with the native objects. The Person() constructor follows the same principles as the Array() constructor. So new Array('foo','bar') is really not that different than new Person(true, 33, 'male'). Creating your own constructor functions is just using the same pattern that JavaScript itself uses for its own native constructor functions.

Notes

  • It is not required, but when creating custom constructor functions intended to be used with the new operator, it’s best practice to make the first character of the constructor name uppercase: Person() rather than person().

  • One tricky thing about constructor functions is the use of the this value inside of the function. Remember, a constructor function is just a cookie cutter. When used with the new keyword, it will create an object with properties and values defined inside of the constructor function. When new is used, the value this literally means the new object/instance that will be created based on the statements inside the constructor function. On the other hand, if you create a constructor function and call it without the use of the new keyword the this value will refer to the “parent” object that contains the function. More detail about this topic can be found in Chapter 6.

  • It’s possible to forgo the use of the new keyword and the concept of a constructor function by explicitly having the function return an object. The function would have to be written explicitly to build an Object() object and return it: var myFunction = function() {return {prop: val}};. Doing this, however, sidesteps prototypal inheritance.

Instantiating Constructors Using the new Operator

A constructor function is basically a cookie cutter template used to create pre-configured objects. Take String() for example. This function, when used with the new operator [new String('foo')] creates a string instance based on the String() “template.” Let’s look at an example.

Live Code

<!DOCTYPE html><html lang="en"><body><script>

var myString = new String('foo');

console.log(myString); // logs foo {0 = "f", 1 = "o", 2 = "o"}

</script></body></html>

Above, we created a new string object that is an instance of the String() constructor function. Just like that, we have a string value expressed in JavaScript.

Note

I’m not suggesting that you use constructor functions instead of their literal/primitive equivalents—like var string="foo";. I am, however, suggesting that you understand what is going on behind literal/primitive values.

As previously mentioned, the JavaScript language has the following native predefined constructors: Number(), String(), Boolean(), Object(), Array(), Function(), Date(), RegExp(), and Error(). We can instantiate an object instance from any of these constructor functions by applying the new operator. Below, I construct these nine native JavaScript objects.

Live Code

<!DOCTYPE html><html lang="en"><body><script>

// instantiate an instance for each native constructor using the new keyword

var myNumber = new Number(23);
var myString = new String('male');
var myBoolean = new Boolean(false);
var myObject = new Object();
var myArray = new Array('foo','bar');
var myFunction = new Function("x", "y", "return x*y");
var myDate = new Date();
var myRegExp = new RegExp('\bt[a-z]+\b');
var myError = new Error('Crap!');

// log/verify which constructor created the object
console.log(myNumber.constructor); // logs Number()
console.log(myString.constructor); // logs String()
console.log(myBoolean.constructor); // logs Boolean()
console.log(myObject.constructor); // logs Object()
console.log(myArray.constructor); //logs Array(), in modern browsers
console.log(myFunction.constructor); // logs Function()
console.log(myDate.constructor); // logs Date()
console.log(myRegExp.constructor); // logs RegExp()
console.log(myError.constructor); // logs Error()

</script></body></html>

By using the new operator, we are telling the JavaScript interpreter that we would like an object that is an instance of the corresponding constructor function. For example, in the code above, the Date() constructor function is used to create date objects. The Date() constructor function is a cookie cutter for date objects. That is, it produces date objects from a default pattern defined by the Date() constructor function.

At this point, you should be well acquainted with creating object instances from native [e.g., new String('foo')] and user-defined constructor functions [e.g., new Person(true, 33, 'male')].

Note

Keep in mind that Math is a static object—a container for other methods—and is not a constructor that uses the new operator.

Creating Shorthand/Literal Values from Constructors

JavaScript provides shortcuts—called “literals”—for manufacturing most of the native object values without having to use new Foo() or new Bar(). For the most part, the literal syntax accomplishes the same thing as using the new operator. The exceptions are: Number(), String(), and Boolean()—see notes below.

If you come from other programming backgrounds, you are likely more familiar with the literal way of creating objects. Below, I instantiate the native JavaScript constructors using the new operator and then create corresponding literal equivalents.

Live Code

<!DOCTYPE html><html lang="en"><body><script>

var myNumber = new Number(23); // an object
var myNumberLiteral = 23; // primitive number value, not an object

var myString = new String('male'); // an object
var myStringLiteral = 'male'; // primitive string value, not an object

var myBoolean = new Boolean(false); // an object
var myBooleanLiteral = false; // primitive boolean value, not an object

var myObject = new Object();
var myObjectLiteral = {};

var myArray = new Array('foo', 'bar');
var myArrayLiteral = ['foo', 'bar'];

var myFunction = new Function("x", "y", "return x*y");
var myFunctionLiteral = function(x, y) {return x*y};

var myRegExp = new RegExp('\bt[a-z]+\b');
var myRegExpLiteral = /\bt[a-z]+\b/;

// verify that literals are created from same constructor

console.log(myNumber.constructor,myNumberLiteral.constructor);
console.log(myString.constructor,myStringLiteral.constructor);
console.log(myBoolean.constructor,myBooleanLiteral.constructor);
console.log(myObject.constructor,myObjectLiteral.constructor);
console.log(myArray.constructor,myArrayLiteral.constructor);
console.log(myFunction.constructor,myFunctionLiteral.constructor);
console.log(myRegExp.constructor,myRegExpLiteral.constructor);


</script></body></html>

What you need to take away here is the fact that, in general, using literals simply conceals the underlying process identical to using the new operator. Maybe more importantly, it’s a lot more convenient!

Okay, things are a little more complicated with respect to the primitive string, number, and boolean values. In these cases, literal values take on the characteristics of primitive values rather than complex object values. See my note below.

Note

When using literal values for string, number, and boolean, an actual complex object is never created until the value is treated as an object. In other words, you are dealing with a primitive datatype until you attempt to use methods or retrieve properties associated with the constructor (e.g., var charactersInFoo = 'foo'.length). When this happens, JavaScript creates a wrapper object for the literal value behind the scenes, allowing the value to be treated as an object. Then, after the method is called, JavaScript discards the wrapper object and the value returns to a literal type. This is why string, number, and boolean are considered primitive (or simple) datatypes. I hope this clarifies the misconception that “everything in JavaScript is an object” with the concept that “everything in JavaScript can act like an object.”

Primitive (a.k.a. Simple) Values

The JavaScript values 5, 'foo', true, and false, as well as null and undefined, are considered primitive because they are irreducible. That is, a number is a number, a string is a string, a boolean is either true or false, and null and undefined are just that, null and undefined. These values are inherently simple, and do not represent values that can be made up of other values.

Examine the code below and ask yourself if the string, number, boolean, null, and undefined values could be more complex. Contrast this to what you know of an Object() instance or Array() instance or really any complex object.

Live Code

<!DOCTYPE html><html lang="en"><body><script>

var myString = 'string'
var myNumber = 10;
var myBoolean = false; // could be true or false, but that is it
var myNull = null;
var myUndefined = undefined;

console.log(myString, myNumber, myBoolean, myNull, myUndefined);

/* Consider that a complex object like array or object can be made up of multiple 
primitive values, and thus becomes a complex set of multiple values. */

var myObject = {
   myString: 'string',
   myNumber: 10,
   myBoolean: false,
   myNull: null,
   myUndefined: undefined
};

console.log(myObject);

var myArray = ['string', 10, false, null, undefined];

console.log(myArray);

</script></body></html>

Quite simply, primitive values represent the lowest form (i.e., simplest) of datum/information available in JavaScript.

Notes

  • As opposed to creating values with literal syntax, when a String(), Number(), or Boolean() value is created using the new keyword, the object created is actually a complex object.

  • It’s critical that you understand the fact that the String(), Number(), and Boolean() constructors are dual-purpose constructors used to create literal/primitive values as well as complex values. These constructors do not always return objects, but instead, when used without the new operator, can return a primitive representation of the actual complex object value.

The Primitive Values null, undefined, “string”, 10, true, and false Are Not Objects

The null and undefined values are such trivial values that they do not require a constructor function, nor the use of the new operator to establish them as a JavaScript value. To use null or undefined, all you do is use them as if they were an operator. The remaining primitive values string, number, and boolean, while technically returned from a constructor function, are not objects.

Below, I contrast the difference between primitive values and the rest of the native JavaScript objects.

Live Code

<!DOCTYPE html><html lang="en"><body><script>

/* no object is created when producing primitive values, 
notice no use of the "new" keyword */
var primitiveString1 = "foo";
var primitiveString2 = String('foo');
var primitiveNumber1 = 10;
var primitiveNumber2 = Number('10');
var primitiveBoolean1 = true;
var primitiveBoolean2 = Boolean('true');

// confirm the typeof is not object
console.log(typeof primitiveString1, typeof primitiveString2); 
  // logs 'string,string'
console.log(typeof primitiveNumber1, typeof primitiveNumber2); 
  // logs 'number,number,
console.log(typeof primitiveBoolean1, typeof primitiveBoolean2); 
  // logs 'boolean,boolean'

// versus the usage of a constructor and new keyword for creating objects

var myNumber = new Number(23);
var myString = new String('male');
var myBoolean = new Boolean(false);
var myObject = new Object();
var myArray = new Array('foo', 'bar');
var myFunction = new Function("x", "y", "return x * y");
var myDate = new Date();
var myRegExp = new RegExp('\\bt[a-z]+\\b');
var myError = new Error('Crap!');

// logs 'object object object object object function object function object'
console.log(
typeof myNumber,
typeof myString,
typeof myBoolean,
typeof myObject,
typeof myArray,
typeof myFunction, // BE AWARE typeof returns function for all function objects
typeof myDate,
typeof myRegExp, // BE AWARE typeof returns function for RegExp()
typeof myError
);

</script></body></html>

What I would like you to grasp from the previous code example is that primitive values are not objects. Primitive values are special in that they are used to represent simple values.

How Primitive Values Are Stored/Copied in JavaScript

It is extremely important to grok that primitive values are stored and manipulated at “face value.” It might sound simple, but this means that if I store the string value "foo" in a variable called myString, then the value "foo" is literally stored in memory as such. Why is this important? Once you begin manipulating (e.g., copying) values, you have to be equipped with this knowledge, because primitive values are copied literally.

In the example below, we store a copy of the myString value ('foo') in the variable myStringCopy, and its value is literally copied. Even if we change the original value, the copied value, referenced by the variable myStringCopy, remains unchanged.

Live Code

<!DOCTYPE html><html lang="en"><body><script>

var myString = 'foo' // create a primitive string object
var myStringCopy = myString; // copy its value into a new variable
var myString = null; // manipulate the value stored in the myString variable

/* The original value from myString was copied to myStringCopy. This is confirmed
by updating the value of myString then checking the value of myStringCopy */
console.log(myString, myStringCopy); // logs 'null foo'


</script></body></html>

The takeaway here is that primitive values are stored and manipulated as irreducible values. Referring to them transfers their value. In the example above, we copied, or cloned, the myString value to the variable myStringCopy. When we updated the myString value, the myStringCopy value still had a copy of the old myString value. Remember this and contrast the mechanics here with complex objects (discussed below).

Primitive Values Are Equal by Value

Primitives can be compared to see if their values are literally the same. As logic would suggest, if you compare a variable containing the numeric value 10 with another variable containing the numeric value 10, JavaScript will consider these equal because 10 is the same as 10 (i.e., 10 === 10). The same, of course, would apply if you compare the primitive string 'foo' to another primitive string with a value of 'foo'. The comparison would say that they are equal to each other based on their value (i.e., 'foo' === 'foo').

In the code below, I demonstrate the “equal by value” concept using primitive numbers, as well as contrast this with a complex number object.

Live Code

<!DOCTYPE html><html lang="en"><body><script>

var price1 = 10;
var price2 = 10;
var price3 = new Number('10'); // a complex numeric object because new was used
var price4 = price3;

console.log(price1 === price2); // logs true

/* logs false because price3 contains a complex number object and price 1 is 
a primitive value */
console.log(price1 === price3);

// logs true because complex values are equal by reference, not value
console.log(price4 === price3);

// what if we update the price4 variable to contain a primitive value?
price4 = 10;

console.log(price4 === price3); /* logs false: price4 is now primitive 
                                rather than complex */

</script></body></html>

The takeaway here is that primitives, when compared, will check to see if the expressed values are equal. When a string, number, or boolean value is created using the new keyword [e.g., new Number('10')], the value is no longer primitive. As such, comparison does not work the same as if the value had been created via literal syntax. This is not surprising, given that primitive values are stored by value (does 10 === 10?), while complex values are stored by reference (do price3 and price4 contain a reference to the same value?).

The String, Number, and Boolean Primitive Values Act Like Objects When Used Like Objects

When a primitive value is used as if it were an object created by a constructor, JavaScript converts it to an object in order to respond to the expression at hand, but then discards the object qualities and changes it back to a primitive value. In the code below, I take primitive values and showcase what happens when the values are treated like objects.

Live Code

<!DOCTYPE html><html lang="en"><body><script>

// Produce primitive values
var myNull = null;
var myUndefined = undefined;
var primitiveString1 = "foo";
var primitiveString2 = String('foo'); // did not use new, so we get primitive
var primitiveNumber1 = 10;
var primitiveNumber2 = Number('10'); // did not use new, so we get primitive
var primitiveBoolean1 = true;
var primitiveBoolean2 = Boolean('true'); // did not use new, so we get primitive

/* Access the toString() property method (inherited by objects from 
object.prototype) to demonstrate that the primitive values are converted to 
objects when treated like objects. */

// logs "string string"
console.log(primitiveString1.toString(), primitiveString2.toString());

// logs "number number"
console.log(primitiveNumber1.toString(), primitiveNumber2.toString());

// logs "boolean boolean"
console.log(primitiveBoolean1.toString(), primitiveBoolean2.toString());

/* This will throw an error and not show up in firebug lite, as null and 
undefined do not convert to objects and do not have constructors. */
console.log(myNull.toString());
console.log(myUndefined.toString());

</script></body></html>

In the above code example, all of the primitive values (except null and undefined) are converted to objects, so as to leverage the toString() method, and then are returned to primitive values once the method is invoked and returned.

Complex (a.k.a. Composite) Values

The native object constructors Object(), Array(), Function(), Date(), Error(), and RegExp() are complex because they can contain one or or more primitive or complex values. Essentially, complex values can be made up of many different types of JavaScript objects. It could be said that complex objects have an unknown size in memory because complex objects can contain any value and not a specific known value. In the code below, we create an object and an array that houses all of the primitive objects.

Live Code

<!DOCTYPE html><html lang="en"><body><script>

var object = {
   myString: 'string',
   myNumber: 10,
   myBoolean: false,
   myNull: null,
   myUndefined: undefined
};

var array = ['string', 10, false, null, undefined];

/* Contrast this to the simplicity of the primitive values below. In a primitive 
form, none of the values below can be more complex than what you see while 
complex values can encapsulate any of the JavaScript values (seen above). */

var myString = 'string';
var myNumber = 10;
var myBoolean = false;
var myNull = null;
var myUndefined = undefined;

</script></body></html>

The takeaway here is that complex values are a composite of values and differ in complexity and composition to primitive values.

Note

The term “complex object” has also been expressed in other writings as “composite objects” or “reference types.” If it’s not obvious, all these names describe the nature of a JavaScript value excluding primitive values. Primitive values are not “referenced by value” and cannot represent a composite (i.e., a thing made up of several parts or elements) of other values. Complex objects, on the other hand, are “referenced by value” and can contain or encapsulate other values.

How Complex Values Are Stored/Copied in JavaScript

It is extremely important to grok that complex values are stored and manipulated by reference. When creating a variable containing a complex object, the value is stored in memory at an address. When you reference a complex object, you’re using its name (i.e., variable or object property) to retrieve the value at that address in memory. The implications are significant when you consider what happens when you attempt to copy a complex value. Below, we create an object stored in the variable myObject. Then the value in myObject is copied to the variable copyOfMyObject. Really, it is not a copy of the object—more like a copy of the address of the object.

Live Code

<!DOCTYPE html><html lang="en"><body><script>

var myObject = {};

var copyOfMyObject = myObject; /* not copied by value, 
                              just the reference is copied */
myObject.foo = 'bar'; // manipulate the value stored in myObject

/* Now if we log myObject and copyOfMyObject, they will have a foo property 
because they reference the same object. */
console.log(myObject, copyOfMyObject); /* logs 'Object { foo="bar"} 
                                       Object { foo="bar"}' */

</script></body></html>

What you need to realize is that, unlike primitive values that would copy a value, objects (a.k.a. complex values) are stored by reference. As such, the reference (a.k.a. address) is copied, but not the actual value. This means that objects are not copied at all. Like I said, what is copied is the address or reference to the object in the memory stack. In our code example, myObject and copyOfMyObject point to the same object stored in memory.

The big takeaway here is that when you change a complex value—because it is stored by reference—you change the value stored in all variables that reference that complex value. In our code example, both myObject and copyOfMyObject are changed when you update the object stored in either variable.

Notes

  • When the values String(), Number(), and Boolean() are created using the new keyword, or converted to complex objects behind the scenes, the values continue to be stored/copied by value. So, even though primitive values can be treated like complex values, they do not take on the quality of being copied by reference.

  • To truly make a copy of an object, you have to extract the values from the old object, and inject them into a new object.

Complex Objects Are Equal by Reference

When comparing complex objects, they are equal only when they reference the same object (i.e., have the same address). Two variables containing identical objects are not equal to each other since they do not actually point at the same object.

Below, objectFoo and objectBar have the same properties and are, in fact, identical objects, but when asked if they are equal via ===, JavaScript tells us they are not.

Live Code

<!DOCTYPE html><html lang="en"><body><script>

var objectFoo = {same: 'same'};
var objectBar = {same: 'same'};

/* logs false, JS does not care that they are identical 
and of the same object type */
console.log(objectFoo === objectBar);

// how complex objects are measured for equality
var objectA = {foo: 'bar'};
var objectB = objectA;

console.log(objectA === objectB); /* logs true because they reference 
                                  the same object */

</script></body></html>

The takeaway here is that variables that point to a complex object in memory are equal only because they are using the same “address.” Conversely, two independently created objects are not equal even if they are of the same type and possess the exact same properties.

Complex Objects Have Dynamic Properties

A new variable that points to an existing complex object does not copy the object. This is why complex objects are sometimes called reference objects. A complex object can have as many references as you want, and they will always refer to the same object, even as that object changes.

Live Code

<!DOCTYPE html><html lang="en"><body><script>

var objA = {property: 'value'};
var pointer1 = objA;
var pointer2 = pointer1;

// update the objA.property, and all references (pointer1 and pointer2) are updated
objA.property = null;

/* logs 'null null null' because objA, pointer1, and pointer2 all reference 
the same object */
console.log(objA.property, pointer1.property, pointer2.property);

</script></body></html>

This allows for dynamic object properties because you can define an object, create references, update the object, and all of the variables referring to the object will “get” that update.

The typeof Operator Used on Primitive and Complex Values

The typeof operator can be used to return the type of value you are dealing with. But the values returned from it are not exactly consistent or what some might say, logical. The following code exhibits the returned values from using the typeof operator.

Live Code

<!DOCTYPE html><html lang="en"><body><script>

// primitive values
var myNull = null;
var myUndefined = undefined;
var primitiveString1 = "string";
var primitiveString2 = String('string');
var primitiveNumber1 = 10;
var primitiveNumber2 = Number('10');
var primitiveBoolean1 = true;
var primitiveBoolean2 = Boolean('true');

console.log(typeof myNull); // logs object? WHAT? Be aware...
console.log(typeof myUndefined); // logs undefined
console.log(typeof primitiveString1, typeof primitiveString2); 
  // logs string string
console.log(typeof primitiveNumber1, typeof primitiveNumber2); 
  // logs number number
console.log(typeof primitiveBoolean1, typeof primitiveBoolean2); 
  // logs boolean boolean

// Complex Values
var myNumber = new Number(23);
var myString = new String('male');
var myBoolean = new Boolean(false);
var myObject = new Object();
var myArray = new Array('foo', 'bar');
var myFunction = new Function("x", "y", "return x * y");
var myDate = new Date();
var myRegExp = new RegExp('\\bt[a-z]+\\b');
var myError = new Error('Crap!');

console.log(typeof myNumber); // logs object
console.log(typeof myString); // logs object
console.log(typeof myBoolean); // logs object
console.log(typeof myObject); // logs object
console.log(typeof myArray); // logs object
console.log(typeof myFunction); // logs function? WHAT? Be aware...
console.log(typeof myDate); // logs object
console.log(typeof myRegExp); // logs function? WHAT? Be aware...
console.log(typeof myError); // logs object

</script></body></html>

When using this operator on values, you should be aware of the potential values returned given the type of value (primitive or complex) that you are dealing with.

Dynamic Properties Allow for Mutable Objects

Complex objects are made up of dynamic properties. This allows for user-defined objects—and most of the native objects—to be mutated. This means that the majority of objects in JavaScript can be updated or changed at any time. Because of this, we can change the native pre-configured nature of JavaScript itself by augmenting its native objects. However, I am not telling you to do this; in fact, I do not think you should. But let’s not cloud what is possible with opinions.

This means it’s possible to store properties on native constructors and add new methods to the native objects with additions to their prototype objects.

In the code below, I mutate the String() constructor function and String.prototype.

Live Code

<!DOCTYPE html><html lang="en"><body><script>

/* augment the built-in String constructor Function() with the augmentedProperties 
property */
String.augmentedProperties = [];

if (!String.prototype.trimIT) { // if the prototype does not have trimIT() add it
   String.prototype.trimIT = function() {
       return this.replace(/^\s+|\s+$/g, '');
   }

   // now add trimIT string to the augmentedProperties array
   String.augmentedProperties.push('trimIT');
}
var myString = '  trim me  ';
console.log(myString.trimIT()); /* invoke our custom trimIT string method, 
                                logs 'trim me' */

console.log(String.augmentedProperties.join()); // logs 'trimIT'

</script></body></html>

I want to drive home the fact that objects in JavaScript are dynamic. This allows objects in JavaScript to be mutated. Essentially, the entire language can be mutated into a custom version (e.g., trimIT string method). Again, I am not recommending this—I am just pointing out that it is part of the nature of objects in JavaScript.

Note

Careful! If you mutate the native inner workings of JavaScript, you potentially have a custom version of JavaScript to deal with. Proceed with caution, as most people will assume that JavaScript is the same whenever it’s available.

All Constructor Instances Have Constructor Properties that Point to Their Constructor Function

When any object is instantiated, the constructor property is created behind the scenes as a property of that object/instance. This points to the constructor function that created the object. Below, we create an Object() object, stored in the foo variable, and then verify that the constructor property is available for the object we created.

Live Code

<!DOCTYPE html><html lang="en"><body><script>

var foo = {};

console.log(foo.constructor === Object) /* logs true, because object() 
                                        constructed foo */
console.log(foo.constructor) // points to the Object() constructor function

</script></body></html>

This can be handy: if I’m working with some instance, and I can’t see who or what created it (especially if it was someone else’s code), I can determine if it’s an array, an object, or whatever.

Below, you can see that I have instantiated most of the pre-configured objects that come included with the JavaScript language. Note that using the constructor property on literal/primitive values correctly resolves (i.e., points) to the right constructor.

Live Code

<!DOCTYPE html><html lang="en"><body><script>

var myNumber = new Number('23');
var myNumberL = 23; // literal shorthand
var myString = new String('male');
var myStringL = 'male'; // literal shorthand
var myBoolean = new Boolean('true');
var myBooleanL = true; // literal shorthand
var myObject = new Object();
var myObjectL = {}; // literal shorthand
var myArray = new Array();
var myArrayL = []; // literal shorthand
var myFunction = new Function();
var myFunctionL = function() {}; // literal shorthand
var myDate = new Date();
var myRegExp = new RegExp('/./');
var myRegExpL = /./; // literal shorthand
var myError = new Error();

console.log( // all of these return true
   myNumber.constructor === Number,
   myNumberL.constructor === Number,
   myString.constructor === String,
   myStringL.constructor === String,
   myBoolean.constructor === Boolean,
   myBooleanL.constructor === Boolean,
   myObject.constructor === Object,
   myObjectL.constructor === Object,
   myArray.constructor === Array,
   myArrayL.constructor === Array,
   myFunction.constructor === Function,
   myFunctionL.constructor === Function,
   myDate.constructor === Date,
   myRegExp.constructor === RegExp,
   myRegExpL.constructor === RegExp,
   myError.constructor === Error
);

</script></body></html>

The constructor property also works on user-defined constructor functions. Below, we define a CustomConstructor() constructor function, then using the keyword new, we invoke the function to produce an object. Once we have our object, we can then leverage the constructor property.

Live Code

<!DOCTYPE html><html lang="en"><body><script>

var CustomConstructor = function CustomConstructor(){ return 'Wow!'; };
var instanceOfCustomObject = new CustomConstructor();

// logs true
console.log(instanceOfCustomObject.constructor === CustomConstructor);

// returns a reference to CustomConstructor() function
// returns 'function() { return 'Wow!'; };'
console.log(instanceOfCustomObject.constructor);

</script></body></html>

Notes

  • You might be confused as to why primitive values have constructor properties that point to constructor functions when objects are not returned. By using a primitive value, the constructor is still called, so there is still a relationship with primitive values and constructor functions. However, the end result is a primitive value.

  • If you would like the constructor property to log the actual name of the constructor for user-defined constructor function expressions, you have to give the constructor function expressions an actual name (e.g., var Person = function Person(){};).

Verify that an Object Is an Instance of a Particular Constructor Function

By using the instanceof operator, we can determine (true or false) if an object is an instance of a particular constructor function.

Below, we are verifying if the object InstanceOfCustomObject is an instance of the CustomConstructor constructor function. This works with user-defined objects as well as native objects created with the new operator.

Live Code

<!DOCTYPE html><html lang="en"><body><script>

// user-defined object constructor
var CustomConstructor = function() {this.foo = 'bar';};

// instantiate an instance of CustomConstructor
var instanceOfCustomObject = new CustomConstructor();

console.log(instanceOfCustomObject instanceof CustomConstructor); // logs true

// works the same as a native object
console.log(new Array('foo') instanceof Array) // logs true

</script></body></html>

Notes

  • One thing to watch out for when dealing with the instanceof operator is that it will return true any time you ask if an object is an instance of Object since all objects inherit from the Object() Constructor.

  • The instanceof operator will return false when dealing with primitive values that leverage object wrappers (e.g., 'foo' instanceof String // returns false). Had the string 'foo' been created with the new operator, the instanceof operator would have returned true. So, keep in mind that instanceof really only works with complex objects and instances created from constructor functions that return objects.

An Instance Created From a Constructor Can Have Its Own Independent Properties (Instance Properties)

In JavaScript, objects can be augmented at any time (i.e., dynamic properties). As previously mentioned, and to be exact, JavaScript has mutable objects. This means that objects created from a constructor function can be augmented with properties.

Below, I create an instance from the Array() constructor and then augment it with its own property.

Live Code

<!DOCTYPE html><html lang="en"><body><script>

var myArray = new Array();
myArray.prop = 'test';

console.log(myArray.prop) // logs 'test'

</script></body></html>

This could be done with Object(), RegExp(), or any of the other non-primitive constructors—even Boolean().

Live Code

<!DOCTYPE html><html lang="en"><body><script>

/* this can be done with any of the native constructors that actually 
produce an object */
var myString = new String();
var myNumber = new Number();
var myBoolean = new Boolean(true);
var myObject = new Object();
var myArray = new Array();
var myFunction = new Function('return 2+2');
var myRegExp = new RegExp('\bt[a-z]+\b');

myString.prop = 'test';
myNumber.prop = 'test';
myBoolean.prop = 'test';
myObject.prop = 'test';
myArray.prop = 'test';
myFunction.prop = 'test';
myRegExp.prop = 'test';

// logs 'test', 'test', 'test', 'test', 'test', 'test', 'test'
console.log(myString.prop,myNumber.prop,myBoolean.prop,myObject.prop,
  myArray.prop,myFunction.prop, myRegExp.prop);

// be aware: instance properties do not work with primitive/literal values
var myString = 'string';
var myNumber = 1;
var myBoolean = true;

myString.prop = true;
myNumber.prop = true;
myBoolean.prop = true;

// logs undefined, undefined, undefined
console.log(myString.prop, myNumber.prop, myBoolean.prop);

</script></body></html>

Adding properties to objects created from a constructor function is not uncommon. Remember: object instances created from constructor functions are just plain old objects.

Note

Keep in mind that, besides their own properties, instances can have properties inherited from the prototype chain. Or, as we just saw in the code, properties added to the constructor after instantiation. This highlights the dynamic nature of objects in JavaScript.

The Semantics of “JavaScript Objects” and “Object() Objects”

Do not confuse the general term “JavaScript objects”, which refers to the notion of objects in JavaScript, with Object() objects. An Object() object [e.g., var myObject = new Object()] is a very specific type of value expressed in JavaScript. Just as an Array() object is a type of object called array, an Object() object is a type of object called object. The gist is that the Object() constructor function produces an empty generic object container, which is referred to as an Object() object. Similarly, the Array() constructor function produces an array object, and we refer to these objects as Array() objects.

In this book, the term “JavaScript object” is used to refer to all objects in JavaScript, because most of the values in JavaScript can act like objects. This is due to the fact that the majority of JavaScript values are created from a native constructor function which produces a very specific type of object.

What you need to remember is that an Object() object is a very specific kind of value. It’s a generic empty object. Do not confuse this with the term “JavaScript objects” used to refer to most of the values that can be expressed in JavaScript as an object.

Get JavaScript Enlightenment now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.