Teacher's Guide: Custom(ized) Objects!
Overview
Student use of objects thus far has been limited to object classes defined in Pencil Code. Students have created instances of objects using constructors (e.g., new Turtle
) and accessed object properties using dot notation (often by invoking functions, e.g., turtle.rt 90
). This lesson shows how to create simple, user-defined objects and how to add or modify properties of existing objects.
A primary goal of the lesson is to help students develop a deeper understanding of some of the ways objects are used, notably, to organize information and pass around data within a program. Subsequent lessons will draw heavily on the concepts introduced here.
More about the lesson
Syntax and mechanics
This lesson teaches students to define their own objects. Objects can be created using a constructor, e.g., myObj = new Object()
. However, following common practice, the lesson recommends the use of object literal notation. This notation has the benefit of being both syntactically simple and relatively easy to read and write—so much so that it has become more widely adopted as an industry standard for data transmission known as JSON (described below).
Object literal notation has been widely adopted in the coding world because its syntax captures the underlying structure of objects. Objects consist of one or more name-value pairs (also known as key-value pairs). Each of these pairs is described as a single property of the object. An individual property is typically referenced using the name in the name-value pair that comprises it. Thus, drawing on the solar system example from the lesson, the mars
object is said to have a color property, a size property, and so on.
mars = { color: red size: 0.53 radius: 228 earthDaysInYears: 687 }
CoffeeScript is very flexible with the syntax of the underlying Javascript object literal notation. The curly braces are optional. Moreover, if you create the object using multiple lines, you can omit the commas too. Though there is significant flexibility regarding property names, encourage students to choose property names following the rules for valid variable names. This ensures that the properties can be referenced using dot-notation, and it obviates the need to enclose the names in quotes.
The following snippet illustrates the flexibility of object literal notation (each of the following four statements produces an equivalent object):
romans = {'I':1, 'II':2, 'IX':9} romans = {I:1, II:2, IX:9} romans = I:1, II:2, IX:9 romans = I: 1 II: 2 IX: 9
Dot notation can be used not only to reference properties of existing objects, but also to add additional properties to such objects. This holds for instances of built-in object types (such as Pencil Code sprites) and for the user-defined objects which are the focus of this lesson.
This flexibility in JavaScript to extend objects without formally defining new types of objects (or classes) can be quite useful. For example, when working with multiple Pencil Code sprites, adding properties is a useful means by which to keep track of additional, instance-specific information. For example, one might add steps or encounters properties to keep a running tally of how many movements individual turtles have made (t.steps = t.steps + 1
) or how many other turtles each one has touched (t.encounters += 1
). Additionally, as the lesson's ColorEaters activity illustrates, adding a color property to a turtle facilitates working with a collection of (potentially anonymous) turtles while continuing to be able to easily distinguish between them via that property.
Use of objects
Objects are a collections data type, the only non-primitive data type in JavaScript. Objects facilitate organizing and storing related data in a way that is easy to access later, and also for passing information between program elements (and even between programs, using JSON). The values referenced by properties can be of any data type, including objects, ranging from HTML Coordinates, sprites, arrays, and even functions (themselves a special type of object).
To illustrate how useful objects are for storing and conveniently accessing information, the lesson provides the example of the SolarSystem program. This program illustrates the use of objects to capture and organize information about each planet, which facilitates convenient access to that data later on in a for loop.
A class exploration of this code is strongly recommended. Highlight how the properties of each planet are easily referenced with meaningful names (e.g., planet.color
, planet.radius
, etc.).
Pencil Code: objects as function arguments and return values
Many Pencil Code functions accept objects as arguments. Capitalizing on this is a focus of the lesson activities, which instruct students to explore passing object arguments to the coordinates-based functions moveto
, jumpto
, and turnto
, to the boolean touches
function, and to the pen
function.
Sprite constructors also accept object arguments:
r = new Sprite({width:50,height:200,color:red})
In subsequent lessons, students will also explore the myriad formatting options that can be controlled by passing objects to the label
function as well as the css
function. And futher on in the curriculum students will learn to interact with event objects.
Though not as common as functions that accept object arguments, a handful of Pencil Code functions return object values. For example, both the call to random(position)
and pagexy()
(an alternative to getxy()
) return HTML coordinates as objects.
Note that Arrays are a special type of object, defined with special built-in features that facilitate traversing, sorting, and processing data. Functions, too, are special types of objects which are callable, and are central to many of the most powerful features of the language. For these reasons and more, Objects are central to the Javascript programming language.
Notes to activities
The goal of this lesson is to introduce students to the syntax and general use of objects in their programs. As such, the scope of the activities is limited with respect the the full potential of the Object data type. The activities in this lesson focus primarily on using objects as a means to pass information around within a program, i.e., passing data in a format that can be recognized by built-in functions. Students will continue to gain additional practice using, modifying, and creating objects in subsequent lessons.
The intent of the LabeledHtmlAxes activity is to provide students the opportunity to interact with simple objects (having only two properties) in an authentic way, i.e., while introducing HTML Coordinates, a representation common to most graphical software environments. Students will need to pay attention to issues of syntax, in particular ensuring that they get the spelling of the property names right, e.g., pageX
rather than x
or pagex
.
HTML coordinates can take some gettting used to, but they are useful when drawing on the visible screen. With their origin at the top-left corner, they have the advantage that both x and y coordinates are positive for all visible positions, ranging from 0 to screen width horizontally, and 0 to screen height vertically. While HTML coordinates may strike students as a curiosity now, they are in fact often much easier to work with programatically, and = essential for working directly with native (non-Pencil Code) features of the graphical environment, such as the HTML canvas
element (an example of which was provided in the notes to the Add Text! lesson).
The ColorEaters activity is designed to illustrate how useful it can be to add additional properties to turtle objects. Encourage students to define an array that references all the turtles, and then use the syntax for t in turtles
to iterate over that collection.
Additional activities
MirrorMovers: Write a program with two sprites that generates a symmetric pattern randomly. Do this by directing one sprite to move to a random location that is generated with
random(position)
and making the second sprite to jump to the "inverse" position, i.e., the point which has the x and y coordinates of the randomly generated coordinate reversed.FancyPen: The
pen
function has additional formatting options that affect how lines are rendered (i.e,. drawn). These can be set by passing a single formatting object topen
, instead of the familiar two-argument approach (e.g.,pen red, 10
). Define an object calledpenFormat
containing properties with namesstrokeStyle
(which should have a color for a value),lineWidth
(with a number value),lineCap
(with string value "butt", "square", or "round"), andlineJoin
(with string value "bevel", "round", or "miter"). (These last two formatting options are described in the notes to Line Art! lesson).Explore use of these formatting options to add new effects to your shapes, such as the following for a simple triangle.
The Custom-Sized Sprites! lesson showed how to create a custom sprite using a string argument, e.g.,
s = new Sprite("blue 50x50")
. An alternative syntax is to pass an object specifying the color and dimensions of the sprite, as follows:s = new Sprite({width:50,height:50,color:blue})
Code a program ObjectifyingSprites which uses iteration to create five or more sprites with different dimensions and colors, and uses these parameters (via dot-notation) in some creative way.
- PacManGhost: Create a script that moves a PacMan ghost around the screen, with its eyes always pointed in the direction of its motion, i.e., either N, S, E, or W. Use objects to link a specific ghost image with the appropriate movement, which you can then choose randomly to direct the ghost around the screen. For the images, consider using the PNG files produced in the PacManPreliminaries activity from the Notes to the Images! lesson. An effective way to record the movement is to a property that contains an array of two numbers that can be passed to either
movexy
orslide
, e.g.,[0,1]
for north and[-1,0]
for west. For an added challenge, when the sprite moves off the screen, have it continue on the opposite side of the screen, just like it does in the real arcade game. - for: loops through a block of code a specific number of times
- for-in: loops through the properties of an object
- for-of: loops through the values of an iterable object
Beyond the lesson
Iteration over Objects
Students initially learned to iterate in the For Loops! lesson, using the syntax for [1..4]
. In subsequent lessons, students learned a variant of the for loop used to iterate over array, e.g., for t in turtles
. However, this for-in
syntax can only be used to iterate over enumerable objects, which include Arrays and array-like objects (such as the arguments
object embedded in functions and jQuery objects). A more general iteration syntax, which can be used for all objects (including arrays), makes use of the keyword of
rather than in
.
The following simple example illustrates the syntax of the for-of
loop. In the example, k
and v
represent the key and value of each of the object's properties:
The preceding program yields results such as this:
Iteration over objects and for-of
loops will be explored further in the Notes to the Subscripting! lesson.
Updating Objects
There are two means by which to modify and/or add a property in an object, regardless of whether that object is an Array or not. You can use dot notation (discussed in this lesson) or subscripts (to be introduced in Subscripting! ).
To illustrate, consider the example provided above of an object representing Roman numerals. There, we saw we had tremendous flexibility in creating the object, using object-literal notation:
romans = {'I':1, 'II':2, 'III':3} romans = {I:1, II:2, III:3} romans = I:1, II:2, III:3 romans = I: 1 II: 2 III: 3
To add an additional property (or to modify an existing property), we have two options:
romans['IV'] = 4 romans.IV = 4
Note that we need to be careful to use quotes appropriately in subscript notation. In the preceding example, if we entered romans[IV]=4
, Coffeescript would attempt to evaluate the variable named IV
. If IV
didn't evaluate to "IV"
, we would get a different result, likely an error. See this script for a comparison of dot-notation and subscripts for referencing elements in an Object and an Array.
JSON
This lesson emphasizes the usefulness of object literal notation for storing, organizing, and passing infromation around within JavaScript programs. However, the format is also useful for passing information across programming platforms. The object literal notation introduced in this section has become an industry standard for transmission of data objects consisting of attribute pairs, called JavaScript Object Notation (JSON). Though derived from JavaScript, it is a language-independent data format. Files created with this format use the extension .json
.
What can go wrong
Misidentifying or misspelling property names
Perhaps the most common mistake students make in this lesson is misspelling the property names of HTML objects. These types of errors can be difficult to identify because they typically lead to unintended behaviors rather than to a warning or program crash.
Misspecification of object property names can occur in one of two ways. In the first place, it can occur when attempting to access a property of an object generated by the system. For example, invalid attempts to read the x coordinate from an object created with the code loc = random(position)
using, for example, loc.pagex
or loc.x
, will not access the desired value but instead return undefined
.
Errors also arise when students incorrectly specify property names when attempting to create and use location objects of their own. For example, using object literal notation, they may define an object loc
to take the value {x:10,y:20}
or {pagex:10,pagey:20}
rather than {pageX:10,pageY:20}
. When the misspecified user-generated HTML location objects is passed to a Pencil Code function, the misspecified object will not be recognized as a valid HTML coordinate and the desired behavior won't occur.
Syntax for assignment of property values
It is common for coders to confuse the syntax of object literal notation and the assignment or modification of properties using dot-notation. The latter requires the use of the assignment operator, =
. When using object literal notation, however, one defines properties by listing name/value pairs separated by a colon, :
. Code such as the following will fail (but thankfully these errors are caught by the compiler, as indicated by the red x):
Overwriting properties
When adding properties to built-in objects, it is important not to overwrite exising property names. For example, if a student added a property named distance
to a sprite, that sprite would lose the ability to access that sprite's built-in distance
function.
Calling pen
vs. updating its properties
pen
is a function (formally, a specially type of function called a method—see below) that gets called to change the values of properties of a specific instance of the sprite class. In this lesson's activities, students learn to pass formatting objects to the pen
function to set advanced pen features. Students may get the impression that they are modifying the properties of the "pen object" itself. However, pen
is not an object in the sense that we update it's behavior by modifying its values using dot notation, such as with pen.lineCap = "butt"
. Rather, students at this point would need to reissue a call to pen
, passing it a new set of formatting rules.
Pen settings are stored in the turtle object in a turtlePenStyle
property. This can be accessed using the jQuery css
method. For example, the call turtle.css("turtlePenStyle")
returns a string such as "strokeStyle:red; lineWidth:10;"
. The css
method is introduced in the Calling all $(".turtle")s! lesson. Students will explore modifying pen settings via the css
method in an Additional Activity in the Notes to the Return! lesson.
Iterating over object properties using "for
x
in
" loops
Students are unlikely to need to iterate over properties of objects in this lesson. In the event they do they attempt to iterate over a non-Array object using a for
x
in
loop, nothing will appear to happen. As described above (and discussed further below), one must use the for
x
of
syntax for this purpose.
Technicalities
for-loop syntax: JavaScript vs. CoffeeScript
JavaScript offers three different variants of the for-loop:
The syntax of all three JavaScript for-loop variants differs from CoffeeScript. The difference that is likely to be most confusing is that the use of in
and of
are essentially reversed between the two languages. JavaScript uses in
to iterate over object keys, whereas CoffeeScript uses in
to iterate over values in enumerable objects, i.e., Arrays and array-like objects. Conversely, JavaScript uses of
to iterate over values of enumerable objects (including Arrays), whereas CoffeeScript uses of
to iterate over object keys (as described above).
Object properties with function values
Functions are a special type of Object. Among other factors, what makes them special is that they are callable. Functions are central to many of the most powerful features of JavaScript. They will be the focus of a series of lessons later in the curriculum.
When using objects of built-in Pencil Code object types, such Turtle or Sprite, nearly all of the properties values that students access (typically through use of dot notation) are functions. However, this lesson avoids instructing students to add functions to objects. In part, this is because doing so potentially introduces some complexities, which serve as an unnecessary distraction at this point. A more important reason to hold off, however, is that students don't have much need of adding functions to object until they have learned how to define functions of their own.
Admittedly, adding a function as a property of an object is trivial—the process is the same as it is for a property of any other type, as illustrated in the following example, which specifies features of a polygon and how it should be drawn (i.e., using the lt
function, as opposed to, say, rt
):
polyFmt = sides:5 length: 100 color: blue fillColor: red turn: lt
Note that the function is not called at the time of adding it to the object—i.e., the code above is turn: lt
and not turn: lt()
—because otherwise we would not be referencing the function itself, but rather the return value of the function call. Rather, the function is executed when referenced, for example, as on the fourth line of the following snippet:
pen polyFmt.color for [1..polyFmt.sides] fd polyFmt.length polyFmt.turn 360/polyFmt.sides fill polyFmt.fillColor
Implicit in the definition of polyFmt
is that the turtle doing the drawing is the default turtle. If we wanted to rely on a different turtle, we could replace the reference to the function with one involving dot-notation.
The preceding example is necessarily trivial, because at this point all students can do is reference individual existing function definitions. As noted above, more meaningful examples arise only after students can define their own functions. But this issue of referencing the containing object from within the function remains central to coding methods. As we shall see, it is typically addressed with the keyword this
.
Functions versus Methods
A method is a function which is a property of an object. Thus, superficially, the difference between describing something as a function versus a method is about code organization. When a function is saved inside an object, it is referred to as a method. In common parlance, however, the term method implies cases in which the function-as-object-property acts on the underlying object itself.
As an example, consider the example of home
(which this curriculum heretofore has referred to as a function, but is also a method). When home
is invoked, the calling sprite (which can be implied, in the case of turtle
, or explicitly stated using dot-notation) is repositioned to the center of the screen, facing north, and so on. The state of the calling sprite is therefore changed. Contrast functions such as home
, which act on the underlying sprite, with the use of lt
in the polyFmt
example above, which has zero impact on the object. Technically, lt
is a method of the polyFmt
object, but only in the most superficial sense.