Home > javascript, programming > Javascript 101 Week 2: Functions, Encapsulation, Augmentation

Javascript 101 Week 2: Functions, Encapsulation, Augmentation


Here’s the second week of homework/ reflection for the JS 101 course offered through Peer 2 Peer University.  You can read my week one homework as well.

Why do languages provide the switch statement, when we can achieve the same thing with multiple if… elseif statements? Show one example of how you might use the switch statement.

Languages provide the switch statement for two main reasons. The first is that they are arguably more readable than multiple if/else if statements. Secondly, in some languages the compiler can optimize switch statements to be more efficient than the equivalent if/else if/else if construct. See the wikipedia article on Switch statements and Branch tables if you’re interested in the details.

Unfortunately, switch statements can be more error prone due to the ability to ‘fall through’ switch statements. Consider the following:

var BOY = 1;
var GIRL = 2;
var sentence = "Congratulations, it's a ";
var gender = GIRL;
switch (gender) {
    case BOY:
        sentence += "boy!";
    // ERROR: no break statement; will fall through to girl case, ending
    // with the sentence "Congratulations, it's a boy!girl!" if gender == BOY
    case GIRL:
        sentence += "girl!";
}

(Note: the above example is somewhat contrived, but forgetting to put a break at the end of a case is a very common error. Please be cognizant of it when using switch.)

Furthermore, programmers frequently forget to provide a default case to handle the case when none of the alternative options match. This frequently happens in Java with enumerations, since the compiler won’t mark this as an error:

enum Foo {
    FOO_1,
    FOO_2
}

Foo x = …;
switch (x) {
    case FOO_1:
        …
        break;
    case FOO_2:
        …
        break;
}

// Everything is fine.  Later, the Foo enum is modified, and a new option is added

enum Foo {
    FOO_1,
    FOO_2,
    FOO_3
}

With the addition of the new enumerated value, we can inadvertently fall through all the options without having executed any code. It is for this reason that I suggest you always provide a default case, even if all it does is throw an exception indicating that this should never happen. Trust me, you’ll find your bugs much earlier/easier this way.

What is encapsulation, and what do functions encapsulate?

Encapsulation is a programming technique to manage complexity and reduce duplication. If I am writing a geometric library I might have code to calculate the area of a circle in a few different places. If this happens once or twice, that might not be the end of the world. The problem is that it becomes very difficult to keep the code in sync in multiple places. A better solution is to break out the logic for calculating the area into a separate function, and then call that function from various places.

This has three main benefits.

  1. This encapsulation of the logic reduces code duplication. Code duplication is bad, as it means that any time you find a bug or want to change something, you need to remember to change it in multiple places. This is a maintenance headache and is extremely error prone.
  2. It makes the code easier to read by better expressing the intent of what you are trying to do and by hiding the details. For instance, instead of having a few lines of code to calculate some number, you can move these lines into a small helper function whose name expresses what the calculation does.
  3. By encapsulating the implementation details within a function, you can change the underlying algorithm without necessitating any client code to change. For instance, you might change a recursive function to an iterative approach for efficiency purposes, but as long as the method name and parameter list stay constant, dependent code is unaffected.

Encapsulation is extremely useful for all the above reasons. It allows the programmer to work at higher levels of abstraction, by hiding implementation details and allowing complex functionality to be built from multiple small, simple function calls.

What is a pure function? Is the function show() provided in Eloquent Javascript a pure function?

A pure function is one without side effects, i.e. a function in the mathematical sense of the word. (It doesn’t make use of variables other than those passed in to the function, so that you are always guaranteed to get the same output for the same input) show is not a pure function, as it has the side effect of writing to the screen.

What do we mean when we say a variable in a function is shadowing a top level variable?

If two variables have the same name, with one being in the global scope and one being in the function scope, the function scoped variable shadows that of the global, top level variable. This means that when we refer to the variable within the function, we access the function scoped variable rather than the top level variable. For instance,


// No var declaration; this is global
name = "Nick";

function greet() {
    // This name variable shadows the global name declaration.
    var name = "Kitty";
    alert("Hi " + name);
}
// Says "Hi Kitty"
greet();

A recursive function, must have some sort of an end condition. Why would we get a “out of stack space” error message if a recursive function does not have an end condition?

A running computer program has memory space allocated both for a stack and for a heap. The heap consists of global or static variables and those things that must remain throughout the life of the program. The stack is where local variables reside. When we call a function, all of the local variables necessary for that function reside are pushed to the top of the stack. When a function exits, the space on the stack is able to be reclaimed.

When we have unbounded recursion, more and more variables are added to the stack. Since none of the functions are exiting, nothing is freed from the stack, and we soon run out of stack space. See the following screenshot and the accompanying article on Stack vs Heap allocation for more information

Organization of the stack

By the way, the fact that function calls are added to this stack is the reason that you can always replace a recursive function with an iterative solution using an explicit stack data structure. This is often not worth the added complexity, but it’s something to be aware of. (You can often replace a recursive algorithm with an iterative solution without using a stack, but the code can be much more complicated. Iterative solutions are often more efficient than recursive solutions, so as always it’s a tradeoff. See the recursion article on Wikipedia for more information.)

Reflect about the difference between object inheritance and class inheritance

Class inheritance, in a language like Java, means that an instance of a subclass inherits all of the members and methods of its superclass; in a sense it has its own ‘copies’. In object inheritance, we get the members and methods via a hidden pointer to another object. Thus changes in that linked object implicitly change the values in the other object.

What is object augmentation, and how do we do it?

Object augmentation is the act of adding fields or functions to an existing object. For instance,

var nick = {name:"Nick",age:23};
// Augment the nick object with a new field
nick.profession = "programmer";
// Remove that field
nick.profession = undefined

Why is this useful? Well it’s useful in the case I just presented, since you do not need to know the full set of fields in your object at initialization, but instead can add and remove them after the fact.

It’s a more powerful concept when combined with the idea of object prototypes. Inheritance is achieved in Javascript through a hidden pointer to another object. All objects have their pointer set to the Object.prototype, so we can augment all objects with a new method, simply by augmenting the Object.prototype object:

nick = {name:"Nick",age:23};

// This function returns a string representation of whatever
// is invoking it
function selfStringRep() {
  var str = "";
  for (var v in this) {
    // This is not an inherited property
    if (this.hasOwnProperty(v)) {
      str += "'" + v + "': " + this[v] +"\n";
    }
  }
  return str;
}
Object.prototype.toString = selfStringRep;
print(nick.toString());
// prints
‘name': Nick
‘age': 23

This is an incredibly powerful feature, and one that I could see being extremely useful.

There is a way to add a method to String, such as any new String we create will have that augmented method (this is a bit different from object augmentation). How would you do this?

To augment all strings, we need to augment String.prototype, since all string instances inherit from this object. For instance, let’s add the ability to reverse any string.

function reverseString(str) {
  var result = "";
  for (var i = str.length - 1; i >= 0; i—) {
    result +=  str.charAt(i);
  }
  return result;
}

String.prototype.reversed = function() { return reverseString(this); }
print("Nick".reversed());
// prints "kciN"

What is garbage collection?

Garbage collection refers to the fact that objects that go out of scope and no longer are referenced are automatically found and their memory is restored. Garbage collection is a feature that makes programmers’ lives easier, as we do not have to manually keep track of freeing the memory of each and every object as it goes in and out of scope. Languages like C do not have garbage collection, introducing a whole potential of errors for programmers. The most common error is a memory leak which might not immediately crash a program, but leads to an increasing amount of memory usage over time.

What is the difference between an array and an object?

While arrays are very similar to objects, there are at least 3 differences. (See jsfiddle for an illustrative example)

  1. Literal construction syntax
    Arrays are formed by square brackets ([]), whereas general objects are formed with curly braces ({})
  2. “Secret link”
    Arrays are automatically linked with Array.prototype; Objects are automatically linked with Object.prototype. This affects the fields available to an array vs an object; for instance, an array will have a length field that automatically reflects the size of the array, whereas a general object will not. Arrays also have methods defined on them, such as concat(), join(), pop(), etc. (see w3schools for more)
  3. Objects’ entries can be accessed with dot syntax or using the bracket notation (e.g. o.name or o[“name”]); arrays can only be accessed with bracket notation (e.g. array[1])

Homework

3.1

Write a function called absolute, which returns the absolute value of the number it is given as its argument. The absolute value of a negative number is the positive version of that same number, and the absolute value of a positive number (or zero) is that number itself.

function abs(x) {
    if (x < 0) {
        return -x;
    }
    else {
        return x;
    }
}

3.2

Write a function greaterThan, which takes one argument, a number, and returns a function that represents a test. When this returned function is called with a single number as argument, it returns a boolean: true if the given number is greater than the number that was used to create the test function, and false otherwise.

function greaterThan(x) {
    return function(y) {
        return y>x;
    }
}

3

Shown below is some code which does something useful. The function ‘iterateAndOperate’ is the one which accomplishes something useful. The remaining code helps this function. Try to understand what the function accomplishes and solve the problems in part a, b, and c. The code can be done inside the console in Javascript, or in the web browser. Please see this comment, for hints on how you may do it inside a web page(remember, HTML has special codes for spaces and newlines).

var pictureArray = ["++++@++++", "+++@@@+++", "++@@@@@++", "+++@@@+++", "++++@++++"];
iterateAndOperate(pictureArray, print)
++++@++++
+++@@@+++
++@@@@@++
+++@@@+++
++++@++++

var triangleArray = ["*", "***", "*****", "***", "*"];
iterateAndOperate(triangleArray, print);
*
***
*****
***
*

try {
    iterateAndOperate();
}
catch (err) {
    alert("Error, you must provide an array and function argument to iterateAndOperate");
}

/*#p2pu-Jan2011-javascript101*/

About these ads
  1. February 19, 2011 at 10:03 pm

    your good

  2. Carleton
    March 24, 2011 at 10:10 am

    I think you meant if gender == BOY not if gender == GIRL in your comment on dangers of fall through…

    • i82much
      March 24, 2011 at 12:08 pm

      Thanks – edited it to fix that mistake. More dangerous than I thought :)

  1. February 15, 2011 at 11:27 pm

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: