Copying, Comparing, and Passing Data
Bitwise Programming
Advanced Function Scope Issues
The movieclip Datatype
Onward!
This chapter collects a variety of advanced ActionScript programming techniques and issues.
There are three fundamental ways to manipulate data. We may copy it (e.g., assign the value of variable x to variable y), we may compare it (e.g., check whether x equals y), and we may pass it (e.g., supply a variable to a function as an argument). Primitive data values are copied, compared, and passed quite differently than composite data. When primitive data is copied to a variable, that variable gets its own unique and private copy of the data, stored separately in memory. The following lines of code would, hence, cause the string "Dave" to be stored twice in memory, once in the memory space reserved for name1 and again in the space reserved for name2:
name1 = "Dave"; name2 = name1;
We say that primitive data is copied by value because the data's literal value is stored in the memory space allotted to the variable. In contrast, when composite data is copied to a variable, only a reference to the data (and not the actual data) is stored in the variable's memory slot. That reference tells the interpreter where the actual data is kept (i.e., its address in memory). When a variable that contains composite data is copied to another variable, it is the reference (often called a pointer) and not the data itself that is copied. Composite data is, hence, said to be copied by reference.
This makes good design sense because it would be grossly inefficient to duplicate large arrays and other composite datatypes. But it has important consequences for our code. When multiple variables are assigned the same piece of composite data as their value, each variable does not store a unique copy of the data (as it would if the data were primitive). Rather, only one copy of the data exists and all the variables point to it. If the value of the data changes, all the variables are updated.
Let's see how this affects a practical application. When two variables refer to the same primitive data, each variable gets its own copy of the data. Here we assign the value 12 to the variable x:
var x = 12;
Now let's assign the value of x to a new variable, y:
var y = x;
As you can guess, y is now equal to 12. But y has its own copy of the value 12, distinct from the copy in x. If we change the value of x, the value of y is unaffected:
x = 15; trace(x); // Displays 15 in the Output window trace(y); // Displays 12 in the Output window
The value of y did not change when x changed because when we assigned x to y, y received its own copy of the number 12 (i.e., the primitive data contained by x).
Now let's try the same thing with composite data. We'll create a new array with three elements and then assign that array to the variable x:
var x = ["first element", 234, 18.5];
Now, just as we did before, we'll assign the value of x to y:
var y = x;
The value of y is now the same as the value of x. But what is the value of x ? Remember that because x refers to an array, which is a composite datum, the value of x is not literally the array ["first element", 234, 18.5] but merely a reference to that datum. Hence, when we assign x to y, what's copied to y is not the array itself, but the reference contained in x that points to the array. So both x and y point to the same array, stored somewhere in memory.
If we change the array through the variable x, like this:
x[0] = "1st element";
the change is also reflected in y :
trace(y[0]); // Displays: "1st element"
Similarly, if we modify the array through y, the change can be seen via x :
y[1] = "second element"; trace (x[1]); // Displays: "second element"
To break the association, use the slice( ) function to create an entirely new array:
var x = ["first element", 234, 18.5]; // Copy each element of x to a new array stored in y var y = x.slice(0); y[0] = "hi there"; trace(x[0]); // Displays: "first element" (not "hi there") trace(y[0]); // Displays: "hi there" (not "first element")
Let's extend our example to see how primitive and composite data values are compared. Here we assign x and y an identical primitive value, then we compare the two variables:
x = 10; y = 10; trace(x == y); // Displays: true
Because x and y contain primitive data, they are compared by value. In a value-based comparison, data is compared literally. The number 10 in x is considered equal to the number 10 in y because the numbers are made up of the same bytes.
Now, let's assign x and y identical versions of the same composite data and compare the two variables again:
x = [10, "hi", 5]; y = [10, "hi", 5]; trace(x == y); // Displays: false
This time, x and y contain composite data, so they are compared by reference. The arrays we assigned to x and y have the same byte values, but the variables x and y are not equal because they do not store a reference to the same composite datum. However, watch what happens when we copy the reference in x to y:
x = y; trace(x == y); // Displays: true
Now that the references are the same, the values are considered equal. Thus, the result of the comparison depends on the references in the variables, not the actual byte values of the arrays.
Primitive and composite data are also treated differently when passed to functions, as discussed under Section 9.8.3, "Primitive Versus Composite Parameter Values" in Chapter 9, "Functions". Most notably, when a primitive variable is passed as an argument to a function, any changes to the datum within the function are not reflected in the original variable. However, when passing a composite variable, changes within the function do affect the original variable. That is, if you pass an integer variable x to a function, changes to it within the function don't affect its original value. But if you pass an array y to a function, any changes to that array within the function will alter the original value of y outside the function (because changes to the array affect the data to which y points).
Copyright © 2002 O'Reilly & Associates. All rights reserved.