CHAPTER 2

image

Special Objects

JavaScript is an object-oriented language, which is a programming paradigm that acknowledges the compartmentalization of data encapsulated within an “object.” But what exactly is an object? To put it plainly, it is a classification used to represent a generalized/generic form. This lack of specificity makes it possible to classify an object as anything that exists. This affords an object-oriented language a means to address any and all non-primitive types.

This is extremely beneficial to an object-oriented language, which employs the Object—due to its general classification—thereby encompassing everything within a singular classification. The object is the singular classification that unifies any and all more specific objects within the language, thereby devising a hierarchical system. No matter how unique or specific the possessed behaviors of an object may be considered, they can always be regarded as an object.

Objects

Absolutely everything is an object. It’s true that an object can be grouped into a particular category with regard to its particular attributes. This categorization is considered the classification of an object. The greater the emphasis on the particular set of behaviors an object possesses, the further its classification from that of the generalized object. Simultaneously, the emphasis placed on the specific traits, attributes, and/or behaviors of an object can be used to place it within a subclassification. However, the inverse will always hold true. In JavaScript, all classifications, in their most generalized form, are objects.

Before we go any further, it is worth noting the repeated use of the words Object and object(s). These two terms are not being used interchangeably. Throughout this book, I have done my best to ensure that Object and object remain properly distinguished in the sentences in which I refer to them. Object and object refer to two separate concepts, as you will, I hope, come to learn. The term Object regards a built-in type of the JavaScript language, whereas the term object refers to an instance of a said Object type.

Objects Are Collections

What classifies all objects in the JavaScript language is that at their most atomic unit, they are simply collections of string value pairs. Technically speaking, all objects are associative arrays. Simply, what this means is that an object has the capability to retain a value for any given identifier. Furthermore, as a collection of strings, it can hold many identifiers.

Quite commonly, these identifiers are referred to as properties, members, and even keys. Regardless of how they are referred to, these identifiers, much like variables, will map to a value. Such values can be primitive or non-primitive. Because a member can only be paired to a singular value, a member and its value are often referred to as a key/value pair. Precisely like a variable, the keys of an object can be referenced, invoked (if it’s assigned value is that of a function), and even assigned a value. Unlike a variable, which can be referenced simply by the name of the identifier, a key must be accessed through the instance. This is achieved with access notation. You will learn more about how to access, assign, and invoke properties within the section “Access Notation.”

Image Note  This book uses the terms properties, members, and keys interchangeably.

What is so powerful about the object-oriented paradigm is its ability to devise collections of like-minded behaviors whose sole faculties are dedicated toward a specific task. The more specific the behaviors, the more specialized these objects become. Furthermore, because an object-oriented language relies on a hierarchical structure to establish relationships among all objects, any object spawned from an existing object can and will inherit its ancestor’s behaviors. This helps to ensure that every descendant possesses its ancestor’s behaviors. This provides all objects the ability to be classified as any of the classifications that make up their lineage. This, of course, includes their topmost ancestor, the Object.

Built-in Objects

The JavaScript language has plenty of built-in objects, many of which are used throughout this book. Because they all share a common ancestor, the Object, each of these objects, at its core, will continue to remain collections of key/value pairs. Furthermore, as direct descendants, they will indirectly possess the behaviors of their ancestor. What makes these objects specialized are the collective behaviors each possesses to facilitate the fulfillment of a specific goal. For each object, the collections of behaviors and attributes uniquely classify it as highly specialized. The Object and Array are just two of the specialized objects this book will make extensive use of.

Object

As mentioned earlier, an Object is a built-in type that defines an unordered collection of key/value pairs. The defined properties and behaviors possessed by the built-in Object facilitate this behavior. In addition to the aforementioned behavior, the Object also possesses other behaviors, which will be inherited by every descendant. One such behavior possessed and passed on by the Object is the toString behavior.

The toString identifier represents the key that directly accesses the value of a function. Because the key is paired to a function, we can follow up the reference with the parentheses (()) operator, to invoke the function. This results in the return of the string representation of the object.

Image Note  When an identifier is mapped to a function, it is referred to as a method of the object.

Beyond its default behaviors, the Object acts as a template from which our application can clone and supply to it a collection of behaviors required by our application.

Creating Objects

While the Object is extremely beneficial within an object-oriented language, its sole use to a developer is the ability to provide to it a collection of behaviors. Fortunately, for this reason, the JavaScript language allows us to create instances of the Object by way of the keyword new, as demonstrated in Listing 2-1.

Listing 2-1. Creation of an object

var aCollection = new Object();

Listing 2-1 leverages the keyword new to inform the JavaScript engine to create an instance of the Object type. Upon the instantiation, an object is created, returned, and assigned to a variable, so that our application can maintain a reference to the instance. By referencing the aCollection identifier, our application can directly refer to our instance and take advantage of its possessed behaviors.

At any point in time, a reference to aCollection allows our application to access any of the key/value pairs retained by it. At this moment, the only behaviors possessed by our aCollection instance are those that are built in to the Object type. One such behavior is the toString method.

Access Notation

The JavaScript language offers two ways in which one can assign or retrieve a value from an instance. The two varieties of manner are known as dot notation and bracket notation.

Dot Notation

Dot notation represents the particular syntax for which a key/value pair can be accessed or assigned to a specified instance. Dot refers to the use of the operator employed to access a property of an instance. That operator is the period (.) symbol. The period itself acts as the delimiter between our instance and the key we wish to get, set, or invoke, as seen in Listing 2-2.

Listing 2-2. Dot Notation Is Used to Access a Member from an Instance

1 var aCollection = new Object();
2    console.log( aCollection.firstProperty ); // undefined
3    aCollection.firstProperty= "hello world";
4    console.log( aCollection.firstProperty ); // hello world
5    console.log( aCollection.toString() );    // [object Object]

Listing 2-2 instantiates an object and assigns it to aCollection (line 1). Utilizing dot notation, Listing 2-2 attempts to read a property value from our aCollection instance. The name of the property is appropriately labeled firstProperty. As the collection lacks a value for the requested property, the value undefined is returned. This value is then logged to the developer’s console (line 2).

In order to get a value for a particular key, it must be assigned a value, lest it returns undefined. To keep things simple, Listing 2-2 assigns the string value "hello world" to the key firstProperty (line 3). On assignment of a value to the identified property, our aCollection instance will reflect a value for each query of firstProperty until the value is reassigned or deleted. A subsequent lookup of the firstProperty utilizing dot notation outputs the value of "hello world" to the console (line 4).

Last, as every object possesses the toString method, we can invoke its behavior by succeeding the key identifier with a parenthesis (line 5). Doing so outputs a string that represents the current object. As you can see, the output, while not all that insightful, does indeed provide a value to the console. This output is the default behavior of the built-in Object. However, because all objects are collections of key/value pairs, the toString member of aCollection can be reassigned with a function that more accurately represents our instance. Each object-type of the JavaScript language overrides the default functionality of the toString method.

Bracket Notation

The second mechanism used to assign, obtain, or invoke a key/value pair is bracket notation. Bracket notation is similar to dot notation in that it is used to query or assign a value for a given property of an instance. The most noticeable difference between bracket notation and dot notation is that bracket notation requires all keys to be referenced as string values rather than as an identifier. The reference to bracket notation regards the delimiter between the key, represented as a string value, and the instance from which it’s being accessed. The string value is enclosed within an opening ([) and closing (]) bracket and immediately succeeds the instance identifier from which the key is being queried. Listing 2-3 revisits the firstProperty, only this time, it employs bracket notation to do so.

Listing 2-3. Bracket Notation Is Used to Access a Member from an Instance

var aCollection = new Object();
    console.log( aCollection['firstProperty'] ); // undefined
    aCollection['firstProperty']= "hello world";
    console.log( aCollection['firstProperty'] ); // hello world
    console.log( aCollection['toString']() );    // [object Object]

If you were to execute the preceding listing, you would arrive at precisely the same results as those of Listing 2-2. Aside from the obvious differences in syntax, you may wonder why you would use one notation over the other.

Bracket Notation vs. Dot Notation

While dot notation is certainly cleaner than bracket notation, bracket notation has a particular advantage. Bracket notation relies on string values, whereas dot notation utilizes identifiers. The key difference is that identifiers must adhere to language constraints. For example, identifiers can’t start with numbers, use whitespace, or be a reserved word in the language. On the other hand, because bracket notation utilizes string values, it allows for the use of characters that otherwise would be a violation of the syntax. One such example is shown in Listing 2-4.

Listing 2-4. Comparing Notations

var aBracketNotationCollectionA = new Object();
    aBracketNotationCollectionA['1']="1";   // creates a key of "1" and assigns it the string value '1'
var aDotNotationCollectionB = new Object();
    aDotNotationCollectionB.1="1";          // throws a SyntaxError

Array

Because a collection retains a value for a given key, a value is obtained directly by referencing its key. Thus, the key is the sole conduit through which a value is reached. For this reason, the Object is known as an unordered collection. The Array is a specialized descendant of the JavaScript Object, which, on the other hand, seeks to provide an order among values.

What makes the Array special is that its collective behaviors allow for cataloging of data as an ordered list. In order to accomplish this, the Array employs the use of numbers to stand in as the key for any key/value pair. As you may have already surmised, because numbers are involved, rather than relying on dot notation, an Array requires none other than bracket notation. Listing 2-5 demonstrates the use of the array to devise an ordered collection set.

Listing 2-5. An Ordered List of the Days of the Week

var orderedCollection = new Array(); //instantiate an array instance
    orderedCollection[0] = 'Sunday';
    orderedCollection[1] = 'Monday';
    orderedCollection[2] = 'Tuesday';
    orderedCollection[3] = 'Wednesday';
    orderedCollection[4] = 'Thursday';
    orderedCollection[5] = 'Friday';
    orderedCollection[6] = 'Saturday';

As revealed by Listing 2-5, the days of the week are assigned as the value to a key, similar to an object. The difference in this case is that an Array employs bracket notation to allow for its properties to be specified as integers. With each key identified as a sequence of integers, values can be obtained in the precise order in which they are cataloged. The simplest way to obtain each value sequentially is with a for loop, as shown in Listing 2-6.

Listing 2-6. A for Loop Is Used to Read from an Ordered List

var daysOfTheWeek = 7;
for(var i=0; i<daysOfTheWeek; i++) console.log( orderedCollection[i] );

If you were to run Listing 2-6, you would undoubtedly see the days of the week printed to the console tab within the developer’s toolbar. Furthermore, they would be output in the order they are assigned.

As was stated earlier, JavaScript objects are collections of string/value pairs. Although the keys of an array are numerical, behind the scenes each integer is coerced into its string representation.

As a descendant of the Object, all instances of the array possess an inherit toString method. Unlike the default value output earlier, our array instance provides a more appropriate value upon invocation, as seen in Listing 2-7.

Listing 2-7. Demonstrating the String Representation of an array

var orderedCollection = new Array();        //instantiate an array instance
    orderedCollection[0] = 'Sunday';
    orderedCollection[1] = 'Monday';
    orderedCollection[2] = 'Tuesday';
console.log(orderedCollection.toString());  // "Sunday,Monday,Tuesday"

As demonstrated in Listing 2-7, the toString implementation results in the joining of all user-defined values possessed by the collection in a comma-delimited string. Because our collection is ordered, the values within the returned string reflect their index within the collection.

Object Literals

Both the Array and the Object can be instantiated via the keyword new. Once either instance is created, key/value pairs can be assigned accordingly. That being said, both the Array and Object are capable of being configured without this syntactical overhead. To better illustrate this point, take a look at Listing 2-8.

Listing 2-8. Object Literals Can Be Designed with Members

var array= ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];
    console.log( array[0] );   //outputs "Sunday"

var object= { firstProperty: "hello world" };
    console.log( object.firstProperty );   //outputs "hello world"

Listing 2-8 creates two object literals. The first represents the instance of the Array, while the latter represents an instance of the Object. For all intents and purposes, an object literal is just another way to arrive at an instantiated object.

While it may not appear to be the case, the instantiation of an object literal and the instantiation of an object via the keyword new create objects similarly. The most significant difference is that literals can be instantiated with a preconfigured collection of key/values pairs. Literals are referred to as such because they are instantiated as they are designed.

Utilizing this technique, we can assign key/value pairs to the object prior to its instantiation. One immediate benefit is that key/value pairs are more identifiable without the added dot/bracket notation. A second benefit is that complex collections and their structures can be defined prior to the existence of other instances. To better understand the preceding statement, consider the following complex collection in Listing 2-9.

Listing 2-9. undefined Assignment of internalObject

 1 var externalObject = new Object();
 2     externalObject.child = internalObject;
 3 var internalObject = new Array();
 4    internalObject[0] = 'Sunday';
 5    internalObject[1] = 'Monday';
 6    internalObject[2] = 'Tuesday';
 7    internalObject[3] = 'Wednesday';
 8    internalObject[4] = 'Thursday';
 9    internalObject[5] = 'Friday';
10    internalObject[6] = 'Saturday';
11
12 console.log(externalObject.child);   // outputs undefined

Listing 2-9 instantiates an instance of the Object and Array. As you can see, the object instance is assigned as the value to externalObject (line 1). Conversely, the array instance is assigned to the variable labeled internalObject (line 3). Because a property can be assigned any valid type in JavaScript, we will devise a complex structure where our object instance possesses a direct reference to our array instance. Used to represent this relationship is the identifier labeled child (line 2).

As it currently stands, externalObject.child does not possess a reference to internalObject. This is made evident by the undefined value that is printed in the console (line 12). The reason the value is not assigned is simply due to the fact that internalObject was undefined at the time of its assignment to externalObject.child (line 2). Correcting the matter in this particular example is as simple as moving the code within line 2 down to line 11, as seen in Listing 2-10.

Listing 2-10. Moved Assignment of Instance Creation

 1 var externalObject = new Object();
 2
 3 var internalObject = new Array();
 4    internalObject[0] = 'Sunday';
 5    internalObject[1] = 'Monday';
 6    internalObject[2] = 'Tuesday';
 7    internalObject[3] = 'Wednesday';
 8    internalObject[4] = 'Thursday';
 9    internalObject[5] = 'Friday';
10    internalObject[6] = 'Saturday';
11    externalObject.child = internalObject;
12 console.log(externalObject.child);   // outputs our array as expected

Listing 2-10 reflects in bold our changes. Moving the order in which our child property is assigned does, in fact, solve our issue. Unfortunately, this reorganization of code actually decreases the continuity of keeping code organized and can soon become a maintenance nightmare. In this case, our code was subject to function vs. form, not the other way around.

A second alternative is to swap altogether the order in which both instances are created, as seen in Listing 2-11.

Listing 2-11. Reordering of Instantiations

 1 var internalObject = new Array();
 2    internalObject[0] = 'Sunday';
 3    internalObject[1] = 'Monday';
 4    internalObject[2] = 'Tuesday';
 5    internalObject[3] = 'Wednesday';
 6    internalObject[4] = 'Thursday';
 7    internalObject[5] = 'Friday';
 8    internalObject[6] = 'Saturday';
 9 var externalObject = new Object();
10     externalObject.child = internalObject;
11
12  console.log(externalObject.child);   // outputs our array as expected

Listing 2-11 has solved our dilemma in the most ideal way that the new keyword can provide. Because new instantiates bare objects, you may find yourself having to resort to reordering code simply to assign key/value pairs. This is where object literals can truly shine.

Because collections can be preconfigured using literal syntax, creating nested collections is as simple as designing them. When the engine evaluates the literal, each nested collection is instantiated on demand. The end result is the same, as made evident by the output on line 4 of Listing 2-12.

Listing 2-12. Object Literals Are Created As They Are Evaluated

1 var externalObject = {
2         child: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
3     };
4 console.log(externalObject.child);       // outputs our array as expected
5 console.log(externalObject.toString());  // [object Object]

Listing 2-12 employs the literal syntax of the object and array to configure the key/value pairs for two individual collections. Furthermore, because all literals are instantiated into objects, they are bestowed with any and all inherited behaviors. This accounts for the ability to reference the toString method of externalObject.

Image Note  All literals in the JavaScript language are instantiated behind the scenes.

Designing Literals

Because both Array and Object are collections of key/value pairs, the term designing literals simply refers to the incorporation of key/value pairs at author time. Depending on whether the literal is that of an object vs. an array, the syntax used to design a literal will vary.

The Object Literal

The syntax used to delimit an object literal is the use of the opening and closing brace ({, }) symbols. When the JavaScript engine encounters an assignment of a variable that employs the aforementioned delimiters, behind the scenes, an instance of the Object type is instantiated and returned. Listing 2-13 employs the object literal syntax to create an object instance.

Listing 2-13. Syntactical Representation of an Object Literal

1 var emptyObject = { };
      console.log(emptyObject.toString());  // [object Object]

What is important to note is that the assignment operation informs the engine to evaluate the brackets as an object literal rather than that of a statement. This is necessary as a block statement employs the use of the same tokens to delimit a block of statements.

Currently our object literal remains absent of any key/value pairs and thus will be instantiated at runtime without any custom behaviors. However this can be easily changed, as seen in Listing 2-14.

Listing 2-14. Object Literal with a Key/Value Pair

var literalObject = {
       firstProperty:"hello world"
    };
console.log(literalObject.firstProperty );  // "hello world"

As revealed by Listing 2-14, a key/value pair is configured by specifying an identifier along with its value separated by a colon (:) token. Listing 2-14 demonstrates how firstProperty is assigned the value "hello world" with literal syntax. Additionally, literals can be designed with multiple key/value pairs. Each key/value pair must remain separate from one another. This is achieved by separating each key/value pair with a comma (,). Listing 2-15 outlines an object literal that possesses three key/value pairs.

Listing 2-15. Object Literal Designed with Multiple Key/Value Pairs

var literalObject = {
        firstProperty : "hello world",
        name          : "iObjectA",
        toString      : function(){ return this.name; }
    };
console.log( literalObject.toString() );  // "iObjectA"

Listing 2-15 revisits our previous object literal from Listing 2-14. This time instead of configuring a singular key/value pair, it defines three. Note the use of the commas to separate each key/value pair. Lastly, one thing to note is that the toString method is assigned with a function that explicitly returns the name property. The use of this ensures that the identifier being referenced remains scoped to the context of our instance. Use of this is necessary because the built-in Object does not possess a name property, only our literalObject. Therefore, we must ensure the scope remains relevant to the instance invoking the behavior.

The Array Literal

The syntax used to delimit an array literal is the use of the opening and closing bracket ([, ]) symbols. When the JavaScript engine encounters an assignment of a variable that employs the aforementioned delimiters, behind the scenes an instance of the Array type is instantiated and returned. Listing 2-16 employs the array literal syntax to create an empty instance of the Array type.

Listing 2-16. Syntactical Representation of an array Literal

var literalArray = [];

Currently, our literal remains absent of any key/value pairs and, thus, will be instantiated at runtime without any custom behaviors. However, this can be easily changed, as seen in Listing 2-17.

Listing 2-17. array Literal Designed with a Key/Value Pair

var literalArray = ["hello world"];

Listing 2-17 reveals an array literal that’s in possession of a singular string value. You may notice that the key for which this string value is assigned appears to be missing. In fact, it is not missing at all. As you may recall, the Array represents an ordered collection. This means that each value supplied is implicitly provided an index key. In other words, when our literalArray is instantiated as an object at runtime, we can use the 0 integer and bracket notation to access "hello world", as shown in Listing 2-18.

Listing 2-18. Array Literal Value Obtainable via Bracket Notation

var literalArray = ["hello world"];
console.log(literalArray[0]);  // hello world

As with the object literal syntax, multiple values can be supplied to an ordered collection by separating multiple values with a comma, as shown in Listing 2-19. Each value is implicitly provided the next available index as its key.

Listing 2-19. Array Literal Designed with Multiple Key/Value Pairs

var literalArray = ["hello world","goodbye world"];
console.log(literalArray[0]);  // hello world
console.log(literalArray[1]);  // goodbye world

Summary

This chapter provided the fundamentals for working with JavaScript objects. Objects are of great importance not only to the language itself, but to JSON as well.

Key Points from This Chapter

  • Absolutely everything is an object.
  • All classifications in their most generalized form are objects.
  • Object and object have two different meanings.
  • Object (with an initial capital letter) refers to the JavaScript Object type.
  • An object refers to an instance.
  • objects are collections.
  • Special Objects are collections of like-minded behaviors.
  • All instances implicitly possess their ancestors’ behaviors.
  • toString returns the string representation of an object.
  • new is used to create instances of a non-primitive value.
  • Dot notation relies on identifiers.
  • Bracket notation relies on strings.
  • Objects are unordered collections.
  • Arrays are ordered collections.
  • Literals can be instantiated with predefined key/value pairs.
  • All literals are instantiated via objects behind the scenes.
  • this is used to maintain the scope of the property being accessed.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.154.252